All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Eli Billauer <eli.billauer@gmail.com>,
	Hyunwoo Kim <imv4bel@gmail.com>,
	Alan Stern <stern@rowland.harvard.edu>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH AUTOSEL 6.1 17/26] char: xillybus: Prevent use-after-free due to race condition
Date: Fri, 23 Dec 2022 20:29:21 -0500	[thread overview]
Message-ID: <20221224012930.392358-17-sashal@kernel.org> (raw)
In-Reply-To: <20221224012930.392358-1-sashal@kernel.org>

From: Eli Billauer <eli.billauer@gmail.com>

[ Upstream commit 282a4b71816b6076029017a7bab3a9dcee12a920 ]

The driver for XillyUSB devices maintains a kref reference count on each
xillyusb_dev structure, which represents a physical device. This reference
count reaches zero when the device has been disconnected and there are no
open file descriptors that are related to the device. When this occurs,
kref_put() calls cleanup_dev(), which clears up the device's data,
including the structure itself.

However, when xillyusb_open() is called, this reference count becomes
tricky: This function needs to obtain the xillyusb_dev structure that
relates to the inode's major and minor (as there can be several such).
xillybus_find_inode() (which is defined in xillybus_class.c) is called
for this purpose. xillybus_find_inode() holds a mutex that is global in
xillybus_class.c to protect the list of devices, and releases this
mutex before returning. As a result, nothing protects the xillyusb_dev's
reference counter from being decremented to zero before xillyusb_open()
increments it on its own behalf. Hence the structure can be freed
due to a rare race condition.

To solve this, a mutex is added. It is locked by xillyusb_open() before
the call to xillybus_find_inode() and is released only after the kref
counter has been incremented on behalf of the newly opened inode. This
protects the kref reference counters of all xillyusb_dev structs from
being decremented by xillyusb_disconnect() during this time segment, as
the call to kref_put() in this function is done with the same lock held.

There is no need to hold the lock on other calls to kref_put(), because
if xillybus_find_inode() finds a struct, xillyusb_disconnect() has not
made the call to remove it, and hence not made its call to kref_put(),
which takes place afterwards. Hence preventing xillyusb_disconnect's
call to kref_put() is enough to ensure that the reference doesn't reach
zero before it's incremented by xillyusb_open().

It would have been more natural to increment the reference count in
xillybus_find_inode() of course, however this function is also called by
Xillybus' driver for PCIe / OF, which registers a completely different
structure. Therefore, xillybus_find_inode() treats these structures as
void pointers, and accordingly can't make any changes.

Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Eli Billauer <eli.billauer@gmail.com>
Link: https://lore.kernel.org/r/20221030094209.65916-1-eli.billauer@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/char/xillybus/xillyusb.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/char/xillybus/xillyusb.c b/drivers/char/xillybus/xillyusb.c
index 39bcbfd908b4..5a5afa14ca8c 100644
--- a/drivers/char/xillybus/xillyusb.c
+++ b/drivers/char/xillybus/xillyusb.c
@@ -184,6 +184,14 @@ struct xillyusb_dev {
 	struct mutex process_in_mutex; /* synchronize wakeup_all() */
 };
 
+/*
+ * kref_mutex is used in xillyusb_open() to prevent the xillyusb_dev
+ * struct from being freed during the gap between being found by
+ * xillybus_find_inode() and having its reference count incremented.
+ */
+
+static DEFINE_MUTEX(kref_mutex);
+
 /* FPGA to host opcodes */
 enum {
 	OPCODE_DATA = 0,
@@ -1237,9 +1245,16 @@ static int xillyusb_open(struct inode *inode, struct file *filp)
 	int rc;
 	int index;
 
+	mutex_lock(&kref_mutex);
+
 	rc = xillybus_find_inode(inode, (void **)&xdev, &index);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&kref_mutex);
 		return rc;
+	}
+
+	kref_get(&xdev->kref);
+	mutex_unlock(&kref_mutex);
 
 	chan = &xdev->channels[index];
 	filp->private_data = chan;
@@ -1275,8 +1290,6 @@ static int xillyusb_open(struct inode *inode, struct file *filp)
 	    ((filp->f_mode & FMODE_WRITE) && chan->open_for_write))
 		goto unmutex_fail;
 
-	kref_get(&xdev->kref);
-
 	if (filp->f_mode & FMODE_READ)
 		chan->open_for_read = 1;
 
@@ -1413,6 +1426,7 @@ static int xillyusb_open(struct inode *inode, struct file *filp)
 	return rc;
 
 unmutex_fail:
+	kref_put(&xdev->kref, cleanup_dev);
 	mutex_unlock(&chan->lock);
 	return rc;
 }
@@ -2227,7 +2241,9 @@ static void xillyusb_disconnect(struct usb_interface *interface)
 
 	xdev->dev = NULL;
 
+	mutex_lock(&kref_mutex);
 	kref_put(&xdev->kref, cleanup_dev);
+	mutex_unlock(&kref_mutex);
 }
 
 static struct usb_driver xillyusb_driver = {
-- 
2.35.1


  parent reply	other threads:[~2022-12-24  1:32 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-24  1:29 [PATCH AUTOSEL 6.1 01/26] gpiolib: of: add a quirk for legacy names in Mediatek mt2701-cs42448 Sasha Levin
2022-12-24  1:29 ` Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 02/26] gpiolib: of: consolidate simple renames into a single quirk Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 03/26] gpiolib: of: tighten selection of gpio renaming quirks Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 04/26] gpiolib: of: add quirk for locating reset lines with legacy bindings Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 05/26] gpiolib: of: add a quirk for reset line for Marvell NFC controller Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 06/26] gpiolib: of: add a quirk for reset line for Cirrus CS42L56 codec Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 07/26] gpiolib: of: add a quirk for legacy names in MOXA ART RTC Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 08/26] kset: fix memory leak when kset_register() returns error Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 09/26] USB: core: Change configuration warnings to notices Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 10/26] usb: core: stop USB enumeration if too many retries Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 11/26] usb: gadget: aspeed: fix buffer overflow Sasha Levin
2022-12-24  1:29   ` Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 12/26] usb: gadget: u_ether: Do not make UDC parent of the net device Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 13/26] usb: gadget: f_ecm: Always set current gadget in ecm_bind() Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 14/26] devres: Use kmalloc_size_roundup() to match ksize() usage Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 15/26] chardev: Fix potential memory leak when cdev_add() failed Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 16/26] usb/usbip: Fix v_recv_cmd_submit() to use PIPE_BULK define Sasha Levin
2022-12-24  1:29 ` Sasha Levin [this message]
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 18/26] habanalabs: zero ts registration buff when allocated Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 19/26] char: xillybus: Fix trivial bug with mutex Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 20/26] iio: filter: admv8818: close potential out-of-bounds read in __admv8818_read_[h|l]pf_freq() Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 21/26] xhci: disable U3 suspended ports in S4 hibernate poweroff_late stage Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 22/26] ACPICA: Fix operand resolution Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 23/26] ksmbd: Fix resource leak in smb2_lock() Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 24/26] writeback: Add asserts for adding freed inode to lists Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 25/26] exfat: fix overflow in sector and cluster conversion Sasha Levin
2022-12-24  1:29 ` [PATCH AUTOSEL 6.1 26/26] fbdev: smscufx: fix error handling code in ufx_usb_probe Sasha Levin
2022-12-24  1:29   ` Sasha Levin

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=20221224012930.392358-17-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=eli.billauer@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=imv4bel@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.