]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: MGMT: validate Add Extended Advertising Data length
authorMichael Bommarito <michael.bommarito@gmail.com>
Fri, 15 May 2026 14:38:19 +0000 (10:38 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 20 May 2026 20:35:47 +0000 (16:35 -0400)
MGMT_OP_ADD_EXT_ADV_DATA is registered as a variable-length command,
with MGMT_ADD_EXT_ADV_DATA_SIZE as the fixed header size.  The handler
then uses cp->adv_data_len and cp->scan_rsp_len to validate and copy
cp->data, but it never checks that those bytes are part of the mgmt
command payload.

A short command can therefore make add_ext_adv_data() pass an
out-of-bounds pointer into tlv_data_is_valid().  If the bytes beyond
the command buffer are addressable, they can also be copied into the
advertising instance as scan response data, where the caller can read
them back via MGMT_OP_GET_ADV_INSTANCE.  The trigger requires
CAP_NET_ADMIN in the initial user namespace; KASAN reports an 8-byte
slab-out-of-bounds read.

Reject commands whose length does not match the fixed header plus both
advertising data lengths before parsing cp->data.

Fixes: 12410572833a ("Bluetooth: Break add adv into two mgmt commands")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/mgmt.c

index b05bb380e5f87715e2a4ac38aa7e7eb77c48549f..de5bd6b637b2053904e95c5666e039658869f0ba 100644 (file)
@@ -9110,9 +9110,15 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
        struct adv_info *adv_instance;
        int err = 0;
        struct mgmt_pending_cmd *cmd;
+       u16 expected_len;
 
        BT_DBG("%s", hdev->name);
 
+       expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len);
+       if (expected_len != data_len)
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
+                                      MGMT_STATUS_INVALID_PARAMS);
+
        hci_dev_lock(hdev);
 
        adv_instance = hci_find_adv_instance(hdev, cp->instance);