From nobody Thu Dec 18 23:30:07 2025 Received: from mail-wm1-f46.google.com (mail-wm1-f46.google.com [209.85.128.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8401B2BE043 for ; Tue, 16 Dec 2025 19:13:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765912391; cv=none; b=NlA/AeHnyG+1k3HvX02Qb+VoD3hdbMDPLuTE8+bci+pdEm92OIWJXPxUv5F1g54U0Hu2LwbOKOLX+MmMnLnv5xsrJrXUak3eRj36grCntCuirhMbl1nmBvK1ChMHPPan0XDZpDhXghvpV9NbfOHkXzZb2skhMymRh8YlJ+rEyrM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765912391; c=relaxed/simple; bh=9aejOiev4cEQVwtjfzoreNUfB0kVR9KWVuIDK7nOAkA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=j8pDt07IQiLyr8hmbHBrk+lapEz+tSEUowjWDuzOdF01IiysIbm93vFk7FmmmHm0iaAHMWpVqgpwHGYg9BxgWGKjwuIp5NrCnLlaCy/QT0Q/nC9kbDH63EkEXnijxG0pJ9wrcWOllMxtW6lvj9hb5BYzmS9zs25HLIxWqmkQnfQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mr6O+BCM; arc=none smtp.client-ip=209.85.128.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mr6O+BCM" Received: by mail-wm1-f46.google.com with SMTP id 5b1f17b1804b1-4779a4fc95aso19416055e9.1 for ; Tue, 16 Dec 2025 11:13:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765912387; x=1766517187; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=c7Zu6eAcymY6NeJU3CgMqAJH0fkDjsEct7SgqC2bGP0=; b=mr6O+BCM9l7FPVHU//DvWCyjmmdONGIfSu5tETDZbGfLAKrK03X7zslPB0ql8VnI5J dnmgAwj9ZHSiP/s0AmJ9BAsdsag7GMfvwmiEwqfie1ajPqMh826DnH8ftwM0g6t2SGOJ idP7OQs2JZASkv8/PysnRzFnW2RHQSuTBHTgqqnpfRGX4Z/adtmQ/6EVKp6b70/glV8T P4M/Z6R56kKTLk8LvNM/ASyX5Q/ksCBChnhi9cqjJYyz5wbTI2M0amM5M6dk/hBcjSHE G5zRroSmrmcWqc/oAyKyuxW3a3Vp73VXddIAoS7/G3LQZ1AKcTkbpGL5orDTGkhpgTnk uF0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765912387; x=1766517187; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=c7Zu6eAcymY6NeJU3CgMqAJH0fkDjsEct7SgqC2bGP0=; b=s+/ntBLKMo1xKRuI+XjklkwLA6NKrwPFA3SFMlAIZYqhyWYYHUYWNwEmxNM8bMZpXn tvI8H/ogqq2L4GIETugjl8mGB6fPiImBxUq1tKn3BKM2ajVon33yHHSjqz/8kKaQd4oU dqFucl/slU5xxapvZjn7r4I5ELdmB2yO4muemDhhlTxKBPJeF2V5oiOppBBzFPs0jLMH ExbJFdG11I5OqjyDMPJqhjmcqwHc87a4lZhjaMgECVup1yqlNqi3fwAvS9PCXPT2ESKF Bc83JYjYqKDsrFPGyi8OCx6m1ZHwuRl3V2rtvILLaWObUS4+twMAWOgYaje/8UTAE+hK cU6A== X-Forwarded-Encrypted: i=1; AJvYcCV/q2zU+YFdJRdnrpKLlaPGB0RlUbckuQByVG8UqOGZxa7IIqKtr7r/mu44W1yTKKHOmKucXadIYJToq0g=@vger.kernel.org X-Gm-Message-State: AOJu0Yw0m5T+5dHH1XYAkzeiKuHVvXBsFcVbzLQEmZOCioAXf3yb9jjC p1nPVIlCR9qR8lXi2CEM8sQVY2RWcx+ulBVxiPKAQQ3ikMw9J93n1VE= X-Gm-Gg: AY/fxX665lnK3Fm6jThxw5JskOmkVVjGM9wZcrQR5/Mi5i1qygYVz9HWqHBX3FGx2cg 0g1BjALPGsnQxS/f8OdoUzOKiss23kGsu6IOdT7rw6IGCGq6W9sGO6koaQtpNmB/vaOKmcm5G1a Z3yiSkIM2lAuvkGsAmx41BkVxQS91N9egcW8tBp3DvSLBKqayV0U/lsp03CE7XbOKhdvmZ0Tdfy MziHdbnrsKx549S0iLzGw8ftiPBQHZ0K3EID38xVvswcjCqKVwhOfbNzF6EGoNK4IAnq3SZz8uD wy1jKfkARI/wRvGAJKsthjangI5w5fu44qgH4r2zavMLFJlkXsv8SSgX+FUdZeippEafEe/Z1Wz OCPrIpsfYvxlIBMFH8ZgdKwGa5PO1AGkyPGyayTMbViVQZ2K4qTZ263hpYEkMPkLqjSAhdQ5SBJ yX6Qcuvc8LrrrK/iXRCWry X-Google-Smtp-Source: AGHT+IEAqeMIDhK+f/ZJDeUorxR8/oEQnp2bw9uHrtBZm1kdrq7o6FrAZ251LEGgaY+X/yNUZHh75Q== X-Received: by 2002:adf:f7cf:0:b0:42f:b555:5274 with SMTP id ffacd0b85a97d-42fb55553f5mr13925210f8f.20.1765912387191; Tue, 16 Dec 2025 11:13:07 -0800 (PST) Received: from slim.tail1db9c.ts.net ([31.223.101.104]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4310ade81absm652655f8f.21.2025.12.16.11.13.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Dec 2025 11:13:05 -0800 (PST) From: Cihangir Akturk To: linux-bluetooth@vger.kernel.org Cc: Marcel Holtmann , Johan Hedberg , Luiz Augusto von Dentz , linux-kernel@vger.kernel.org, Cihangir Akturk , syzbot+87badbb9094e008e0685@syzkaller.appspotmail.com Subject: [PATCH] Bluetooth: hci: fix refcounts in LE remote features command Date: Tue, 16 Dec 2025 22:12:55 +0300 Message-ID: <20251216191255.882653-1-cakturk@gmail.com> X-Mailer: git-send-email 2.52.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" KASAN reported a slab-use-after-free in le_read_features_complete() running from hci_cmd_sync_work. le_read_features_complete() can run after hci_rx_work/hci_conn_del() has removed the link, so the destroy callback may touch a freed hci_conn and trigger a KASAN use-after-free. Duplicate submissions also need to drop the references to avoid leaking the hold and blocking teardown. Fix this by taking hci_conn_get() before queueing, passing the conn directly as work data, and balancing hci_conn_hold()/drop() and hci_conn_get()/put() in the completion and all error/-EEXIST paths so the connection stays referenced while the work runs and is released afterwards. Reported-by: syzbot+87badbb9094e008e0685@syzkaller.appspotmail.com Signed-off-by: Cihangir Akturk --- net/bluetooth/hci_sync.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) I am not entirely sure that removing the err =3D=3D -ECANCELED early return is strictly correct. My assumption is that, with the changes in this patch, there does not appear to be another cancellation path that reliably balances hci_conn_drop() and hci_conn_put() for this command. Based on that assumption, keeping the early return could leave the references taken before queuing unbalanced on cancellation, so I opted to remove it to keep the lifetime handling consistent. diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index a9f5b1a68356..5a3d288e7015 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -776,14 +776,23 @@ _hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_= cmd_sync_work_func_t func, * - Lookup if an entry already exist and only if it doesn't creates a new= entry * and queue it. */ -int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t= func, +static int __hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_wo= rk_func_t func, void *data, hci_cmd_sync_work_destroy_t destroy) { if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) - return 0; + return -EEXIST; =20 return hci_cmd_sync_queue(hdev, func, data, destroy); } + +int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t= func, + void *data, hci_cmd_sync_work_destroy_t destroy) +{ + int ret; + + ret =3D __hci_cmd_sync_queue_once(hdev, func, data, destroy); + return ret =3D=3D -EEXIST ? 0 : ret; +} EXPORT_SYMBOL(hci_cmd_sync_queue_once); =20 /* Run HCI command: @@ -7338,10 +7347,8 @@ static void le_read_features_complete(struct hci_dev= *hdev, void *data, int err) =20 bt_dev_dbg(hdev, "err %d", err); =20 - if (err =3D=3D -ECANCELED) - return; - hci_conn_drop(conn); + hci_conn_put(conn); } =20 static int hci_le_read_all_remote_features_sync(struct hci_dev *hdev, @@ -7408,12 +7415,20 @@ int hci_le_read_remote_features(struct hci_conn *co= nn) * role is possible. Otherwise just transition into the * connected state without requesting the remote features. */ - if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) - err =3D hci_cmd_sync_queue_once(hdev, - hci_le_read_remote_features_sync, - hci_conn_hold(conn), - le_read_features_complete); - else + if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) { + hci_conn_get(conn); + hci_conn_hold(conn); + err =3D __hci_cmd_sync_queue_once(hdev, + hci_le_read_remote_features_sync, + conn, + le_read_features_complete); + if (err) { + hci_conn_drop(conn); + hci_conn_put(conn); + if (err =3D=3D -EEXIST) + err =3D 0; + } + } else err =3D -EOPNOTSUPP; =20 return err; --=20 2.52.0