mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Bluetooth: mgmt: fix pending command UAF in EIR updates
MGMT_OP_SET_LOCAL_NAME is handled asynchronously on powered controllers
and can run set_name_sync(). When the controller is BR/EDR capable,
set_name_sync() updates the local name and then rebuilds EIR data through
eir_create(). The EIR builder walks hdev->uuids, but the UUID list can
be changed and entries can be freed by MGMT_OP_ADD_UUID and
MGMT_OP_REMOVE_UUID.
pending_eir_or_class() is meant to serialize management commands that
can change EIR or the class of device, but it did not include
MGMT_OP_SET_LOCAL_NAME. In addition, it walked hdev->mgmt_pending
without hdev->mgmt_pending_lock even though pending commands are added
and removed under that mutex. A racing command completion can therefore
remove and free a pending command while pending_eir_or_class() is still
inspecting it, leading to a use-after-free in the pending-command list or
allowing a local name update to rebuild EIR while UUID entries are being
removed.
Take hdev->mgmt_pending_lock while scanning hdev->mgmt_pending and treat
MGMT_OP_SET_LOCAL_NAME as an EIR/class-affecting pending command on the
powered asynchronous path. Check for a conflicting pending command before
copying the new short name so a rejected SET_LOCAL_NAME request does not
modify hdev->short_name.
Fixes: 6fe26f694c ("Bluetooth: MGMT: Protect mgmt_pending list with its own lock")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
d0a7b48ad0
commit
8f2f62855a
+18
-2
@@ -2696,18 +2696,28 @@ static int mgmt_hci_cmd_sync(struct sock *sk, struct hci_dev *hdev,
|
||||
static bool pending_eir_or_class(struct hci_dev *hdev)
|
||||
{
|
||||
struct mgmt_pending_cmd *cmd;
|
||||
bool pending = false;
|
||||
|
||||
mutex_lock(&hdev->mgmt_pending_lock);
|
||||
|
||||
list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
|
||||
switch (cmd->opcode) {
|
||||
case MGMT_OP_ADD_UUID:
|
||||
case MGMT_OP_REMOVE_UUID:
|
||||
case MGMT_OP_SET_DEV_CLASS:
|
||||
case MGMT_OP_SET_LOCAL_NAME:
|
||||
case MGMT_OP_SET_POWERED:
|
||||
return true;
|
||||
pending = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pending)
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
mutex_unlock(&hdev->mgmt_pending_lock);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
static const u8 bluetooth_base_uuid[] = {
|
||||
@@ -4071,6 +4081,12 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (hdev_is_powered(hdev) && pending_eir_or_class(hdev)) {
|
||||
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
|
||||
MGMT_STATUS_BUSY);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
|
||||
|
||||
if (!hdev_is_powered(hdev)) {
|
||||
|
||||
Reference in New Issue
Block a user