Bluetooth: L2CAP: Fix not checking l2cap_chan security level
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 7 May 2025 19:00:30 +0000 (15:00 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 22 May 2025 17:04:39 +0000 (13:04 -0400)
l2cap_check_enc_key_size shall check the security level of the
l2cap_chan rather than the hci_conn since for incoming connection
request that may be different as hci_conn may already been
encrypted using a different security level.

Fixes: 522e9ed157e3 ("Bluetooth: l2cap: Check encryption key size on incoming connection")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/l2cap_core.c

index 73472756618a0cf9eea4c441702f57edf8e44a67..042d3ac3b4a38ea7d3d6db2cd2315570be487810 100644 (file)
@@ -1411,7 +1411,8 @@ static void l2cap_request_info(struct l2cap_conn *conn)
                       sizeof(req), &req);
 }
 
-static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
+static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
+                                    struct l2cap_chan *chan)
 {
        /* The minimum encryption key size needs to be enforced by the
         * host stack before establishing any L2CAP connections. The
@@ -1425,7 +1426,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
        int min_key_size = hcon->hdev->min_enc_key_size;
 
        /* On FIPS security level, key size must be 16 bytes */
-       if (hcon->sec_level == BT_SECURITY_FIPS)
+       if (chan->sec_level == BT_SECURITY_FIPS)
                min_key_size = 16;
 
        return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
@@ -1453,7 +1454,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
            !__l2cap_no_conn_pending(chan))
                return;
 
-       if (l2cap_check_enc_key_size(conn->hcon))
+       if (l2cap_check_enc_key_size(conn->hcon, chan))
                l2cap_start_connection(chan);
        else
                __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
@@ -1528,7 +1529,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                continue;
                        }
 
-                       if (l2cap_check_enc_key_size(conn->hcon))
+                       if (l2cap_check_enc_key_size(conn->hcon, chan))
                                l2cap_start_connection(chan);
                        else
                                l2cap_chan_close(chan, ECONNREFUSED);
@@ -3992,7 +3993,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
            (!hci_conn_check_link_mode(conn->hcon) ||
-           !l2cap_check_enc_key_size(conn->hcon))) {
+           !l2cap_check_enc_key_size(conn->hcon, pchan))) {
                conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
@@ -7352,7 +7353,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                }
 
                if (chan->state == BT_CONNECT) {
-                       if (!status && l2cap_check_enc_key_size(hcon))
+                       if (!status && l2cap_check_enc_key_size(hcon, chan))
                                l2cap_start_connection(chan);
                        else
                                __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
@@ -7362,7 +7363,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        struct l2cap_conn_rsp rsp;
                        __u16 res, stat;
 
-                       if (!status && l2cap_check_enc_key_size(hcon)) {
+                       if (!status && l2cap_check_enc_key_size(hcon, chan)) {
                                if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
                                        res = L2CAP_CR_PEND;
                                        stat = L2CAP_CS_AUTHOR_PEND;