]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Bluetooth: MGMT: fix crash in set_mesh_sync and set_mesh_complete
authorPauli Virtanen <pav@iki.fi>
Fri, 3 Oct 2025 19:07:32 +0000 (22:07 +0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 24 Oct 2025 14:21:37 +0000 (10:21 -0400)
There is a BUG: KASAN: stack-out-of-bounds in set_mesh_sync due to
memcpy from badly declared on-stack flexible array.

Another crash is in set_mesh_complete() due to double list_del via
mgmt_pending_valid + mgmt_pending_remove.

Use DEFINE_FLEX to declare the flexible array right, and don't memcpy
outside bounds.

As mgmt_pending_valid removes the cmd from list, use mgmt_pending_free,
and also report status on error.

Fixes: 302a1f674c00d ("Bluetooth: MGMT: Fix possible UAFs")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/mgmt.h
net/bluetooth/mgmt.c

index 74edea06985bfaa0af9bf99c6ba17e85d3111a56..bca0333f1e991621153c48ed87a9995bb630affb 100644 (file)
@@ -853,7 +853,7 @@ struct mgmt_cp_set_mesh {
        __le16 window;
        __le16 period;
        __u8   num_ad_types;
-       __u8   ad_types[];
+       __u8   ad_types[] __counted_by(num_ad_types);
 } __packed;
 #define MGMT_SET_MESH_RECEIVER_SIZE    6
 
index a3d16eece0d236e6c2c9882a6f63769476e1c3c5..24e335e3a7271f18237b13165ea0f44df80e7efa 100644 (file)
@@ -2175,19 +2175,24 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
        sk = cmd->sk;
 
        if (status) {
+               mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
+                               status);
                mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
                                     cmd_status_rsp, &status);
-               return;
+               goto done;
        }
 
-       mgmt_pending_remove(cmd);
        mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0);
+
+done:
+       mgmt_pending_free(cmd);
 }
 
 static int set_mesh_sync(struct hci_dev *hdev, void *data)
 {
        struct mgmt_pending_cmd *cmd = data;
-       struct mgmt_cp_set_mesh cp;
+       DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types,
+                   sizeof(hdev->mesh_ad_types));
        size_t len;
 
        mutex_lock(&hdev->mgmt_pending_lock);
@@ -2197,27 +2202,26 @@ static int set_mesh_sync(struct hci_dev *hdev, void *data)
                return -ECANCELED;
        }
 
-       memcpy(&cp, cmd->param, sizeof(cp));
+       len = cmd->param_len;
+       memcpy(cp, cmd->param, min(__struct_size(cp), len));
 
        mutex_unlock(&hdev->mgmt_pending_lock);
 
-       len = cmd->param_len;
-
        memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types));
 
-       if (cp.enable)
+       if (cp->enable)
                hci_dev_set_flag(hdev, HCI_MESH);
        else
                hci_dev_clear_flag(hdev, HCI_MESH);
 
-       hdev->le_scan_interval = __le16_to_cpu(cp.period);
-       hdev->le_scan_window = __le16_to_cpu(cp.window);
+       hdev->le_scan_interval = __le16_to_cpu(cp->period);
+       hdev->le_scan_window = __le16_to_cpu(cp->window);
 
-       len -= sizeof(cp);
+       len -= sizeof(struct mgmt_cp_set_mesh);
 
        /* If filters don't fit, forward all adv pkts */
        if (len <= sizeof(hdev->mesh_ad_types))
-               memcpy(hdev->mesh_ad_types, cp.ad_types, len);
+               memcpy(hdev->mesh_ad_types, cp->ad_types, len);
 
        hci_update_passive_scan_sync(hdev);
        return 0;