linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org,
	syzbot <syzbot+a5df189917e79d5e59c9@syzkaller.appspotmail.com>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>,
	Luiz Augusto von Dentz <luiz.von.dentz@intel.com>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH 4.4 09/25] Bluetooth: defer cleanup of resources in hci_unregister_dev()
Date: Fri, 13 Aug 2021 17:06:33 +0200	[thread overview]
Message-ID: <20210813150521.027222164@linuxfoundation.org> (raw)
In-Reply-To: <20210813150520.718161915@linuxfoundation.org>

From: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>

[ Upstream commit e04480920d1eec9c061841399aa6f35b6f987d8b ]

syzbot is hitting might_sleep() warning at hci_sock_dev_event() due to
calling lock_sock() with rw spinlock held [1].

It seems that history of this locking problem is a trial and error.

Commit b40df5743ee8 ("[PATCH] bluetooth: fix socket locking in
hci_sock_dev_event()") in 2.6.21-rc4 changed bh_lock_sock() to
lock_sock() as an attempt to fix lockdep warning.

Then, commit 4ce61d1c7a8e ("[BLUETOOTH]: Fix locking in
hci_sock_dev_event().") in 2.6.22-rc2 changed lock_sock() to
local_bh_disable() + bh_lock_sock_nested() as an attempt to fix the
sleep in atomic context warning.

Then, commit 4b5dd696f81b ("Bluetooth: Remove local_bh_disable() from
hci_sock.c") in 3.3-rc1 removed local_bh_disable().

Then, commit e305509e678b ("Bluetooth: use correct lock to prevent UAF
of hdev object") in 5.13-rc5 again changed bh_lock_sock_nested() to
lock_sock() as an attempt to fix CVE-2021-3573.

This difficulty comes from current implementation that
hci_sock_dev_event(HCI_DEV_UNREG) is responsible for dropping all
references from sockets because hci_unregister_dev() immediately
reclaims resources as soon as returning from
hci_sock_dev_event(HCI_DEV_UNREG).

But the history suggests that hci_sock_dev_event(HCI_DEV_UNREG) was not
doing what it should do.

Therefore, instead of trying to detach sockets from device, let's accept
not detaching sockets from device at hci_sock_dev_event(HCI_DEV_UNREG),
by moving actual cleanup of resources from hci_unregister_dev() to
hci_cleanup_dev() which is called by bt_host_release() when all
references to this unregistered device (which is a kobject) are gone.

Since hci_sock_dev_event(HCI_DEV_UNREG) no longer resets
hci_pi(sk)->hdev, we need to check whether this device was unregistered
and return an error based on HCI_UNREGISTER flag.  There might be subtle
behavioral difference in "monitor the hdev" functionality; please report
if you found something went wrong due to this patch.

Link: https://syzkaller.appspot.com/bug?extid=a5df189917e79d5e59c9 [1]
Reported-by: syzbot <syzbot+a5df189917e79d5e59c9@syzkaller.appspotmail.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Fixes: e305509e678b ("Bluetooth: use correct lock to prevent UAF of hdev object")
Acked-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/net/bluetooth/hci_core.h |    1 
 net/bluetooth/hci_core.c         |   16 ++++++------
 net/bluetooth/hci_sock.c         |   49 ++++++++++++++++++++++++++-------------
 net/bluetooth/hci_sysfs.c        |    3 ++
 4 files changed, 45 insertions(+), 24 deletions(-)

--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1013,6 +1013,7 @@ struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
 void hci_unregister_dev(struct hci_dev *hdev);
+void hci_cleanup_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_reset_dev(struct hci_dev *hdev);
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3457,14 +3457,10 @@ EXPORT_SYMBOL(hci_register_dev);
 /* Unregister HCI device */
 void hci_unregister_dev(struct hci_dev *hdev)
 {
-	int id;
-
 	BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
 	hci_dev_set_flag(hdev, HCI_UNREGISTER);
 
-	id = hdev->id;
-
 	write_lock(&hci_dev_list_lock);
 	list_del(&hdev->list);
 	write_unlock(&hci_dev_list_lock);
@@ -3493,7 +3489,14 @@ void hci_unregister_dev(struct hci_dev *
 	}
 
 	device_del(&hdev->dev);
+	/* Actual cleanup is deferred until hci_cleanup_dev(). */
+	hci_dev_put(hdev);
+}
+EXPORT_SYMBOL(hci_unregister_dev);
 
+/* Cleanup HCI device */
+void hci_cleanup_dev(struct hci_dev *hdev)
+{
 	debugfs_remove_recursive(hdev->debugfs);
 
 	destroy_workqueue(hdev->workqueue);
@@ -3513,11 +3516,8 @@ void hci_unregister_dev(struct hci_dev *
 	hci_discovery_filter_clear(hdev);
 	hci_dev_unlock(hdev);
 
-	hci_dev_put(hdev);
-
-	ida_simple_remove(&hci_index_ida, id);
+	ida_simple_remove(&hci_index_ida, hdev->id);
 }
-EXPORT_SYMBOL(hci_unregister_dev);
 
 /* Suspend HCI device */
 int hci_suspend_dev(struct hci_dev *hdev)
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -53,6 +53,17 @@ struct hci_pinfo {
 	unsigned long     flags;
 };
 
+static struct hci_dev *hci_hdev_from_sock(struct sock *sk)
+{
+	struct hci_dev *hdev = hci_pi(sk)->hdev;
+
+	if (!hdev)
+		return ERR_PTR(-EBADFD);
+	if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
+		return ERR_PTR(-EPIPE);
+	return hdev;
+}
+
 void hci_sock_set_flag(struct sock *sk, int nr)
 {
 	set_bit(nr, &hci_pi(sk)->flags);
@@ -480,19 +491,13 @@ void hci_sock_dev_event(struct hci_dev *
 	if (event == HCI_DEV_UNREG) {
 		struct sock *sk;
 
-		/* Detach sockets from device */
+		/* Wake up sockets using this dead device */
 		read_lock(&hci_sk_list.lock);
 		sk_for_each(sk, &hci_sk_list.head) {
-			lock_sock(sk);
 			if (hci_pi(sk)->hdev == hdev) {
-				hci_pi(sk)->hdev = NULL;
 				sk->sk_err = EPIPE;
-				sk->sk_state = BT_OPEN;
 				sk->sk_state_change(sk);
-
-				hci_dev_put(hdev);
 			}
-			release_sock(sk);
 		}
 		read_unlock(&hci_sk_list.lock);
 	}
@@ -631,10 +636,10 @@ static int hci_sock_blacklist_del(struct
 static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
 				unsigned long arg)
 {
-	struct hci_dev *hdev = hci_pi(sk)->hdev;
+	struct hci_dev *hdev = hci_hdev_from_sock(sk);
 
-	if (!hdev)
-		return -EBADFD;
+	if (IS_ERR(hdev))
+		return PTR_ERR(hdev);
 
 	if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL))
 		return -EBUSY;
@@ -766,6 +771,18 @@ static int hci_sock_bind(struct socket *
 
 	lock_sock(sk);
 
+	/* Allow detaching from dead device and attaching to alive device, if
+	 * the caller wants to re-bind (instead of close) this socket in
+	 * response to hci_sock_dev_event(HCI_DEV_UNREG) notification.
+	 */
+	hdev = hci_pi(sk)->hdev;
+	if (hdev && hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
+		hci_pi(sk)->hdev = NULL;
+		sk->sk_state = BT_OPEN;
+		hci_dev_put(hdev);
+	}
+	hdev = NULL;
+
 	if (sk->sk_state == BT_BOUND) {
 		err = -EALREADY;
 		goto done;
@@ -937,9 +954,9 @@ static int hci_sock_getname(struct socke
 
 	lock_sock(sk);
 
-	hdev = hci_pi(sk)->hdev;
-	if (!hdev) {
-		err = -EBADFD;
+	hdev = hci_hdev_from_sock(sk);
+	if (IS_ERR(hdev)) {
+		err = PTR_ERR(hdev);
 		goto done;
 	}
 
@@ -1191,9 +1208,9 @@ static int hci_sock_sendmsg(struct socke
 		goto done;
 	}
 
-	hdev = hci_pi(sk)->hdev;
-	if (!hdev) {
-		err = -EBADFD;
+	hdev = hci_hdev_from_sock(sk);
+	if (IS_ERR(hdev)) {
+		err = PTR_ERR(hdev);
 		goto done;
 	}
 
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -180,6 +180,9 @@ ATTRIBUTE_GROUPS(bt_host);
 static void bt_host_release(struct device *dev)
 {
 	struct hci_dev *hdev = to_hci_dev(dev);
+
+	if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
+		hci_cleanup_dev(hdev);
 	kfree(hdev);
 	module_put(THIS_MODULE);
 }



  parent reply	other threads:[~2021-08-13 15:08 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-13 15:06 [PATCH 4.4 00/25] 4.4.281-rc1 review Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 01/25] ALSA: seq: Fix racy deletion of subscriber Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 02/25] scsi: sr: Return correct event when media event code is 3 Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 03/25] media: videobuf2-core: dequeue if start_streaming fails Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 04/25] net: natsemi: Fix missing pci_disable_device() in probe and remove Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 05/25] mips: Fix non-POSIX regexp Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 06/25] bnx2x: fix an error code in bnx2x_nic_load() Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 07/25] net: pegasus: fix uninit-value in get_interrupt_interval Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 08/25] net: vxge: fix use-after-free in vxge_device_unregister Greg Kroah-Hartman
2021-08-13 15:06 ` Greg Kroah-Hartman [this message]
2021-08-13 15:06 ` [PATCH 4.4 10/25] USB: serial: option: add Telit FD980 composition 0x1056 Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 11/25] USB: serial: ch341: fix character loss at high transfer rates Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 12/25] USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2 Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 13/25] scripts/tracing: fix the bug that cant parse raw_trace_func Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 14/25] media: rtl28xxu: fix zero-length control request Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 15/25] serial: 8250: Mask out floating 16/32-bit bus bits Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 16/25] MIPS: Malta: Do not byte-swap accesses to the CBUS UART Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 17/25] pcmcia: i82092: fix a null pointer dereference bug Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 18/25] reiserfs: add check for root_inode in reiserfs_fill_super Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 19/25] reiserfs: check directory items on read from disk Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 20/25] alpha: Send stop IPI to send to online CPUs Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 21/25] net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and ql_adapter_reset Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 22/25] pipe: increase minimum default pipe size to 2 pages Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 23/25] USB:ehci:fix Kunpeng920 ehci hardware problem Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 24/25] net: xilinx_emaclite: Do not print real IOMEM pointer Greg Kroah-Hartman
2021-08-13 15:06 ` [PATCH 4.4 25/25] ovl: prevent private clone if bind mount is not allowed Greg Kroah-Hartman
2021-08-13 23:26 ` [PATCH 4.4 00/25] 4.4.281-rc1 review Shuah Khan
2021-08-14 14:20 ` Naresh Kamboju
2021-08-14 18:14 ` Guenter Roeck
2021-08-15 19:51 ` Pavel Machek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210813150521.027222164@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luiz.von.dentz@intel.com \
    --cc=penguin-kernel@I-love.SAKURA.ne.jp \
    --cc=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=syzbot+a5df189917e79d5e59c9@syzkaller.appspotmail.com \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).