Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp21319975ybl; Mon, 6 Jan 2020 02:15:47 -0800 (PST) X-Google-Smtp-Source: APXvYqyhn7hV716ag4X3rXijIGiFOw7bQ3/gUEHtQuZrmV3JYTppvO6a64Qzhul4oieuzRx2WZPN X-Received: by 2002:a9d:674f:: with SMTP id w15mr116954623otm.243.1578305747042; Mon, 06 Jan 2020 02:15:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578305747; cv=none; d=google.com; s=arc-20160816; b=cOQDg8QGjDmkFzS+ZrpItGccUN57RJ5C8pbong50MHxQPOF4GDbQ68/Ij7ePLB/yNb SAtFWVVjKHrsN2qi5elPYE64axkAgESHy0EIyZAamu/xTG+Z9zFJjlkkO46+JfJ1f6El kv5HE11h7GUhPsDBPObU806q7tWhhOUa/jHDJ2qiqShsn6vpWNBoPIYF5DKNw2KzEHEz iqNwBmXP3Fkr8wB+ZCY5fGlcpD7vJNMZbTqhqvlcC0/Dv3Ji8u0s5NxVtMAF4SGL1zGV E7dD7r1eCQqiXzuglxMma5NIO96a1YhzkBpZZ0wZoAVzsURpKy5g57v25QJ7KEio+j8J R+Hg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:mime-version :message-id:date:dkim-signature; bh=at/6LW2CyTT3AHJ4DEYijPCx/QdUy/o9K531OsH9S78=; b=ThN45lN6iBHXv/C11MphNtVX38uSzMN9XRylzBVbbaYzpaPSiKzzRL7CkqvPIiugLC ++4JLSwkWwc5E4kxtPbvKuefptRanFSnMv5uEG90fLBihPlP5e0ysWLvuRY0FQqv+zut llaTO4T2h2F0jjUDhTDtr2ovtKyQt1SpG8z7Hw+8KrSnoG/NZnGcTcQPE+2h2cHerBO8 EYK/gLk4YcerpR5+9dEjB19eyUHQxNlvHPBKrThr4GWx8jRh4L6wqzP0uO6OCVpGbwO9 ZsmQq7SfFEdg6EI2l6y+QTlR99+izVdFmxwV7GAGhPh4IcLOYekNOXyeVscy2yheWgGm yDkw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=bDdqcPXV; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 25si32839457oiz.230.2020.01.06.02.15.34; Mon, 06 Jan 2020 02:15:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=bDdqcPXV; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726293AbgAFKOx (ORCPT + 99 others); Mon, 6 Jan 2020 05:14:53 -0500 Received: from mail-vk1-f202.google.com ([209.85.221.202]:44796 "EHLO mail-vk1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726080AbgAFKOx (ORCPT ); Mon, 6 Jan 2020 05:14:53 -0500 Received: by mail-vk1-f202.google.com with SMTP id k16so7014761vko.11 for ; Mon, 06 Jan 2020 02:14:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=at/6LW2CyTT3AHJ4DEYijPCx/QdUy/o9K531OsH9S78=; b=bDdqcPXVe98eZZsa1W/fgJGsjHgmbnuAHsdVZRxB/3KvothFJUQUfQ0onHWQZ8cfpX nT4tXkR1hx5QKJ0kqcm+i6hbjFiePhLwRTnnLJECG/i4KiwAfG9k7E6aYHg+osoPighR XXXc5btco0/w1GOLEiK4WqSzvlCx/j9nz6X+8fZqp1uvhV7PRUaXbDN25u71AmYpWLyG fxGkkeRTD0kfFO+jyrVOand0ROEnj5QBZn7670exqa2lPa0stOycRFTxWkSvuO/LOtdZ pYS7sDIxeCDkp8cvSom/ZlQ7HLcbWDA13yy8M1tvGIWYO5o2xdI4JQFmv8Z7mjlYurwT 4nrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=at/6LW2CyTT3AHJ4DEYijPCx/QdUy/o9K531OsH9S78=; b=bc82Lj/n0nZu+L2i2q8a7DkHHZutRsY8aeOFGdrHVYLXcUAsHbSvTSjAtxwkkLpVoQ mH9XE62M5q5yS89Cdv0cXixILklr65Yp5hxZnl2qafNUO8vWmZAM2X1bwrrkbwgIiF+F 2ULOvhdV3EtubDK3z7peSiJoGhPNQJ9u8/yqOzJjY+XiWA+1iyCim2Igka12s/PZgIZy fE5xTq0/TbKavghX4GRUB4L7iCxLyZtSlB1V9wnJOzq5TT+jBsG8AK0Q1Mjs/7FXTjbH CxXkZDV04mBX3/ADMMbEaeiapONNCTzFWtlGi67OFv/BbRjN/ovSyI5CL4Ua/A768V8M u7wQ== X-Gm-Message-State: APjAAAXzIJtC9arBHp8JXWV0siRzO9ivQYLH4Sxx9IGUjvMOGZFrPaOd vPfLg/x1XVExFpVGoAHnHhizoSBGDNIXnCodBQ== X-Received: by 2002:ab0:714c:: with SMTP id k12mr58239995uao.124.1578305691993; Mon, 06 Jan 2020 02:14:51 -0800 (PST) Date: Mon, 6 Jan 2020 18:14:37 +0800 Message-Id: <20200106181425.Bluez.v1.1.I5ee1ea8e19d41c5bdffb4211aeb9cd9efa5e0a4a@changeid> Mime-Version: 1.0 X-Mailer: git-send-email 2.24.1.735.g03f4e72817-goog Subject: [Bluez PATCH v1] bluetooth: secure bluetooth stack from bluedump attack From: "howardchung@google.com" To: linux-bluetooth@vger.kernel.org, marcel@holtmann.org Cc: chromeos-bluetooth-upstreaming@chromium.org, howardchung , "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: howardchung Attack scenario: 1. A Chromebook (let's call this device A) is paired to a legitimate Bluetooth classic device (e.g. a speaker) (let's call this device B). 2. A malicious device (let's call this device C) pretends to be the Bluetooth speaker by using the same BT address. 3. If device A is not currently connected to device B, device A will be ready to accept connection from device B in the background (technically, doing Page Scan). 4. Therefore, device C can initiate connection to device A (because device A is doing Page Scan) and device A will accept the connection because device A trusts device C's address which is the same as device B's address. 5. Device C won't be able to communicate at any high level Bluetooth profile with device A because device A enforces that device C is encrypted with their common Link Key, which device C doesn't have. But device C can initiate pairing with device A with just-works model without requiring user interaction (there is only pairing notification). After pairing, device A now trusts device C with a new different link key, common between device A and C. 6. From now on, device A trusts device C, so device C can at anytime connect to device A to do any kind of high-level hijacking, e.g. speaker hijack or mouse/keyboard hijack. To fix this, reject the pairing if all the conditions below are met. - the pairing is initialized by peer - the authorization method is just-work - host already had the link key to the peer Also create a debugfs option to permit the pairing even the conditions above are met. Signed-off-by: howardchung --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 47 +++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 12 ++++++++++ 3 files changed, 60 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 07b6ecedc6ce..4918b79baa41 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -283,6 +283,7 @@ enum { HCI_FORCE_STATIC_ADDR, HCI_LL_RPA_RESOLUTION, HCI_CMD_PENDING, + HCI_PERMIT_JUST_WORK_REPAIR, __HCI_NUM_FLAGS, }; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9e19d5a3aac8..9014aa567e7b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -172,10 +172,57 @@ static const struct file_operations vendor_diag_fops = { .llseek = default_llseek, }; +static ssize_t permit_just_work_repair_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = hci_dev_test_flag(hdev, HCI_PERMIT_JUST_WORK_REPAIR) ? 'Y' + : 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t permit_just_work_repair_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf) - 1)); + bool enable; + + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + if (strtobool(buf, &enable)) + return -EINVAL; + + if (enable) + hci_dev_set_flag(hdev, HCI_PERMIT_JUST_WORK_REPAIR); + else + hci_dev_clear_flag(hdev, HCI_PERMIT_JUST_WORK_REPAIR); + + return count; +} + +static const struct file_operations permit_just_work_repair_fops = { + .open = simple_open, + .read = permit_just_work_repair_read, + .write = permit_just_work_repair_write, + .llseek = default_llseek, +}; + static void hci_debugfs_create_basic(struct hci_dev *hdev) { debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev, &dut_mode_fops); + debugfs_create_file("permit_just_work_repair", 0644, hdev->debugfs, + hdev, &permit_just_work_repair_fops); if (hdev->set_diag) debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6ddc4a74a5e4..898e347e19e0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4539,6 +4539,18 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, goto unlock; } + /* If there already exists link key in local host, terminate the + * connection by default since the remote device could be malicious. + * Permit the connection if permit_just_work_repair is enabled. + */ + if (!hci_dev_test_flag(hdev, HCI_PERMIT_JUST_WORK_REPAIR) && + hci_find_link_key(hdev, &ev->bdaddr)) { + BT_DBG("Rejecting request: local host already have link key"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) && (!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) { -- 2.24.1.735.g03f4e72817-goog