Browse Source

Bluetooth: Fix race condition with conn->sec_level

The conn->sec_level value is supposed to represent the current level of
security that the connection has. However, by assigning to it before
requesting authentication it will have the wrong value during the
authentication procedure. To fix this a pending_sec_level variable is
added which is used to track the desired security level while making
sure that sec_level always represents the current level of security.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Johan Hedberg 14 years ago
parent
commit
765c2a964b
3 changed files with 12 additions and 6 deletions
  1. 1 0
      include/net/bluetooth/hci_core.h
  2. 6 2
      net/bluetooth/hci_conn.c
  3. 5 4
      net/bluetooth/hci_event.c

+ 1 - 0
include/net/bluetooth/hci_core.h

@@ -184,6 +184,7 @@ struct hci_conn {
 	__u32		 link_mode;
 	__u32		 link_mode;
 	__u8             auth_type;
 	__u8             auth_type;
 	__u8             sec_level;
 	__u8             sec_level;
+	__u8		 pending_sec_level;
 	__u8             power_save;
 	__u8             power_save;
 	__u16            disc_timeout;
 	__u16            disc_timeout;
 	unsigned long	 pend;
 	unsigned long	 pend;

+ 6 - 2
net/bluetooth/hci_conn.c

@@ -379,7 +379,8 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	hci_conn_hold(acl);
 	hci_conn_hold(acl);
 
 
 	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
 	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
-		acl->sec_level = sec_level;
+		acl->sec_level = BT_SECURITY_LOW;
+		acl->pending_sec_level = sec_level;
 		acl->auth_type = auth_type;
 		acl->auth_type = auth_type;
 		hci_acl_connect(acl);
 		hci_acl_connect(acl);
 	}
 	}
@@ -437,8 +438,11 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
 {
 	BT_DBG("conn %p", conn);
 	BT_DBG("conn %p", conn);
 
 
+	if (conn->pending_sec_level > sec_level)
+		sec_level = conn->pending_sec_level;
+
 	if (sec_level > conn->sec_level)
 	if (sec_level > conn->sec_level)
-		conn->sec_level = sec_level;
+		conn->pending_sec_level = sec_level;
 	else if (conn->link_mode & HCI_LM_AUTH)
 	else if (conn->link_mode & HCI_LM_AUTH)
 		return 1;
 		return 1;
 
 

+ 5 - 4
net/bluetooth/hci_event.c

@@ -692,13 +692,13 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 	if (conn->state != BT_CONFIG || !conn->out)
 	if (conn->state != BT_CONFIG || !conn->out)
 		return 0;
 		return 0;
 
 
-	if (conn->sec_level == BT_SECURITY_SDP)
+	if (conn->pending_sec_level == BT_SECURITY_SDP)
 		return 0;
 		return 0;
 
 
 	/* Only request authentication for SSP connections or non-SSP
 	/* Only request authentication for SSP connections or non-SSP
 	 * devices with sec_level HIGH */
 	 * devices with sec_level HIGH */
 	if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
 	if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
-					conn->sec_level != BT_SECURITY_HIGH)
+				conn->pending_sec_level != BT_SECURITY_HIGH)
 		return 0;
 		return 0;
 
 
 	return 1;
 	return 1;
@@ -1095,9 +1095,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
 	if (conn) {
 	if (conn) {
-		if (!ev->status)
+		if (!ev->status) {
 			conn->link_mode |= HCI_LM_AUTH;
 			conn->link_mode |= HCI_LM_AUTH;
-		else
+			conn->sec_level = conn->pending_sec_level;
+		} else
 			conn->sec_level = BT_SECURITY_LOW;
 			conn->sec_level = BT_SECURITY_LOW;
 
 
 		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);