@@ -2886,12 +2886,25 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
+ u8 reason;
+ int err;
+
+ rcu_read_lock();
conn = hci_conn_hash_lookup_handle(hdev, handle);
+ if (conn) {
+ reason = READ_ONCE(conn->abort_reason);
+ conn = reason ? hci_conn_get(conn) : NULL;
+ }
+
+ rcu_read_unlock();
+
if (!conn)
return 0;
- return hci_abort_conn_sync(hdev, conn, conn->abort_reason);
+ err = hci_abort_conn_sync(hdev, conn, reason);
+ hci_conn_put(conn);
+ return err;
}
int hci_abort_conn(struct hci_conn *conn, u8 reason)
@@ -2903,6 +2916,8 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
*/
if (conn->abort_reason)
return 0;
+ if (WARN_ON(!reason))
+ reason = HCI_ERROR_UNSPECIFIED;
bt_dev_dbg(hdev, "handle 0x%2.2x reason 0x%2.2x", conn->handle, reason);
@@ -5375,6 +5375,8 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
u16 handle = conn->handle;
struct hci_conn *c;
+ WARN_ON(!reason);
+
switch (conn->state) {
case BT_CONNECTED:
case BT_CONFIG:
There is a race condition where a connection handle is reused, after hci_abort_conn but before abort_conn_sync is processed in hci_sync. In this case, hci_abort_conn_sync ends up calling hci_connect_cfm with success status and then delete the connection, which causes use-after-free. Fix by checking abort_reason before calling hci_abort_conn_sync. Also fix some theoretical UAF / races, where something frees the conn while hci_abort_conn_sync is working on it. Fixes: a13f316e90fd ("Bluetooth: hci_conn: Consolidate code for aborting connections") Reported-by: syzbot+a0c80b06ae2cb8895bc4@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-bluetooth/0000000000005ab984060371583e@google.com/ Signed-off-by: Pauli Virtanen <pav@iki.fi> --- Notes: Not sure how you'd hit this condition in real controller, but syzbot does end up calling hci_abort_conn_sync with reason == 0 which then causes havoc. This can be verified: with a patch that changes abort_conn_sync to 2874 conn = hci_conn_hash_lookup_handle(hdev, handle); 2875 if (!conn || WARN_ON(!conn->abort_reason)) 2876 return 0; https://syzkaller.appspot.com/text?tag=Patch&x=16eff740680000 it hits that WARN_ON: https://syzkaller.appspot.com/x/log.txt?x=10affb97a80000 #syz test git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master net/bluetooth/hci_conn.c | 17 ++++++++++++++++- net/bluetooth/hci_sync.c | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-)