[go: nahoru, domu]

CHROMIUM: Bluetooth: Require Read Encryption Key Size command

The HCI command Read Encryption Key Size is optional by the Bluetooth
standard. However, in Chrome OS we require the support of this command
to guarantee security.

This CL does the following:
* Disables Bluetooth if Read Local Commands shows that Read Encryption
  Key Size is not supported.
* Otherwise, always try to send command Read Encryption Key Size to the
  chip and abort the connection if the command fails (may be because
  it's unsupported by the chip.)
* Add kernel warning if we detect that Read Encryption Key Size command
  may be unsupported so we can evaluate chip security.

BUG=chromium:929763
TEST=Tested on caroline board with simulated unsupported commands.

Change-Id: I6992ce3530c9df47ee08f42705e28c1dd8652b66
Signed-off-by: Sonny Sasaka <sonnysasaka@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1501716
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Xiaoyong Zhou <xzhou@chromium.org>
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c4293a2..6d6d72a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1439,6 +1439,13 @@
 
 	clear_bit(HCI_INIT, &hdev->flags);
 
+	/* Don't allow usage of Bluetooth if the chip doesn't support */
+	/* Read Encryption Key Size command (byte 20 bit 4). */
+	if (!ret && !(hdev->commands[20] & 0x10)) {
+		WARN(1, "Disabling Bluetooth due to unsupported HCI Read Encryption Key Size command");
+		ret = -EIO;
+	}
+
 	if (!ret) {
 		hci_dev_hold(hdev);
 		hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c14840a..6f99b7b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2583,20 +2583,23 @@
 	if (!conn)
 		goto unlock;
 
-	/* If we fail to read the encryption key size, assume maximum
-	 * (which is the same we do also when this HCI command isn't
-	 * supported.
+	/* If we fail to read the encryption key size, abort the connection
+	 * since the encryption key entropy is not guaranteed to be large
+	 * enough.
 	 */
 	if (rp->status) {
+		WARN(1, "Read Encryption Key Size command failed, chip may not support this");
 		bt_dev_err(hdev, "failed to read key size for handle %u",
 			   handle);
-		conn->enc_key_size = HCI_LINK_KEY_SIZE;
+		hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
+		hci_conn_drop(conn);
+		goto unlock;
 	} else {
 		conn->enc_key_size = rp->key_size;
 	}
 
 	if (conn->enc_key_size < MIN_ENC_KEY_LEN) {
-		BT_DBG("Dropping connection with weak encryption key length");
+		WARN(1, "Dropping connection with weak encryption key length");
 		hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
 		hci_conn_drop(conn);
 		goto unlock;
@@ -2690,30 +2693,22 @@
 		struct hci_cp_read_enc_key_size cp;
 		struct hci_request req;
 
-		/* Only send HCI_Read_Encryption_Key_Size if the
-		 * controller really supports it. If it doesn't, assume
-		 * the default size (16).
-		 */
-		if (!(hdev->commands[20] & 0x10)) {
-			conn->enc_key_size = HCI_LINK_KEY_SIZE;
-			goto notify;
-		}
-
 		hci_req_init(&req, hdev);
 
 		cp.handle = cpu_to_le16(conn->handle);
 		hci_req_add(&req, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp);
 
 		if (hci_req_run_skb(&req, read_enc_key_size_complete)) {
+			WARN(1, "Failed sending HCI Read Encryption Key Size, chip may not support this");
 			bt_dev_err(hdev, "sending read key size failed");
-			conn->enc_key_size = HCI_LINK_KEY_SIZE;
-			goto notify;
+			hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
+			hci_conn_drop(conn);
+			goto unlock;
 		}
 
 		goto unlock;
 	}
 
-notify:
 	if (conn->state == BT_CONFIG) {
 		if (!ev->status)
 			conn->state = BT_CONNECTED;