|
David Disseldorp |
458382 |
From d18dcfe9860e842f394e37ba01ca9440ab2178f4 Mon Sep 17 00:00:00 2001
|
|
David Disseldorp |
458382 |
From: Alan Stern <stern@rowland.harvard.edu>
|
|
David Disseldorp |
458382 |
Date: Fri, 23 Dec 2022 09:59:09 -0500
|
|
David Disseldorp |
458382 |
Subject: [PATCH] USB: gadgetfs: Fix race between mounting and unmounting
|
|
David Disseldorp |
458382 |
References: CVE-2022-4382 bsc#1206258
|
|
David Disseldorp |
699515 |
Patch-mainline: v6.2-rc5
|
|
David Disseldorp |
458382 |
Git-commit: d18dcfe9860e842f394e37ba01ca9440ab2178f4
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
The syzbot fuzzer and Gerald Lee have identified a use-after-free bug
|
|
David Disseldorp |
458382 |
in the gadgetfs driver, involving processes concurrently mounting and
|
|
David Disseldorp |
458382 |
unmounting the gadgetfs filesystem. In particular, gadgetfs_fill_super()
|
|
David Disseldorp |
458382 |
can race with gadgetfs_kill_sb(), causing the latter to deallocate
|
|
David Disseldorp |
458382 |
the_device while the former is using it. The output from KASAN says,
|
|
David Disseldorp |
458382 |
in part:
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:176 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in __refcount_sub_and_test include/linux/refcount.h:272 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in __refcount_dec_and_test include/linux/refcount.h:315 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in refcount_dec_and_test include/linux/refcount.h:333 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in put_dev drivers/usb/gadget/legacy/inode.c:159 [inline]
|
|
David Disseldorp |
458382 |
BUG: KASAN: use-after-free in gadgetfs_kill_sb+0x33/0x100 drivers/usb/gadget/legacy/inode.c:2086
|
|
David Disseldorp |
458382 |
Write of size 4 at addr ffff8880276d7840 by task syz-executor126/18689
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
CPU: 0 PID: 18689 Comm: syz-executor126 Not tainted 6.1.0-syzkaller #0
|
|
David Disseldorp |
458382 |
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022
|
|
David Disseldorp |
458382 |
Call Trace:
|
|
David Disseldorp |
458382 |
<TASK>
|
|
David Disseldorp |
458382 |
...
|
|
David Disseldorp |
458382 |
atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:176 [inline]
|
|
David Disseldorp |
458382 |
__refcount_sub_and_test include/linux/refcount.h:272 [inline]
|
|
David Disseldorp |
458382 |
__refcount_dec_and_test include/linux/refcount.h:315 [inline]
|
|
David Disseldorp |
458382 |
refcount_dec_and_test include/linux/refcount.h:333 [inline]
|
|
David Disseldorp |
458382 |
put_dev drivers/usb/gadget/legacy/inode.c:159 [inline]
|
|
David Disseldorp |
458382 |
gadgetfs_kill_sb+0x33/0x100 drivers/usb/gadget/legacy/inode.c:2086
|
|
David Disseldorp |
458382 |
deactivate_locked_super+0xa7/0xf0 fs/super.c:332
|
|
David Disseldorp |
458382 |
vfs_get_super fs/super.c:1190 [inline]
|
|
David Disseldorp |
458382 |
get_tree_single+0xd0/0x160 fs/super.c:1207
|
|
David Disseldorp |
458382 |
vfs_get_tree+0x88/0x270 fs/super.c:1531
|
|
David Disseldorp |
458382 |
vfs_fsconfig_locked fs/fsopen.c:232 [inline]
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
The simplest solution is to ensure that gadgetfs_fill_super() and
|
|
David Disseldorp |
458382 |
gadgetfs_kill_sb() are serialized by making them both acquire a new
|
|
David Disseldorp |
458382 |
mutex.
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
|
David Disseldorp |
458382 |
Reported-and-tested-by: syzbot+33d7ad66d65044b93f16@syzkaller.appspotmail.com
|
|
David Disseldorp |
458382 |
Reported-and-tested-by: Gerald Lee <sundaywind2004@gmail.com>
|
|
David Disseldorp |
458382 |
Link: https://lore.kernel.org/linux-usb/CAO3qeMVzXDP-JU6v1u5Ags6Q-bb35kg3=C6d04DjzA9ffa5x1g@mail.gmail.com/
|
|
David Disseldorp |
458382 |
Fixes: e5d82a7360d1 ("vfs: Convert gadgetfs to use the new mount API")
|
|
David Disseldorp |
458382 |
CC: <stable@vger.kernel.org>
|
|
David Disseldorp |
458382 |
Link: https://lore.kernel.org/r/Y6XCPXBpn3tmjdCC@rowland.harvard.edu
|
|
David Disseldorp |
458382 |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
David Disseldorp |
458382 |
Acked-by: David Disseldorp <ddiss@suse.de>
|
|
David Disseldorp |
458382 |
---
|
|
David Disseldorp |
458382 |
drivers/usb/gadget/legacy/inode.c | 28 +++++++++++++++++++++-------
|
|
David Disseldorp |
458382 |
1 file changed, 21 insertions(+), 7 deletions(-)
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
|
|
David Disseldorp |
458382 |
index 01c3ead7d1b4..d605bc2e7e8f 100644
|
|
David Disseldorp |
458382 |
--- a/drivers/usb/gadget/legacy/inode.c
|
|
David Disseldorp |
458382 |
+++ b/drivers/usb/gadget/legacy/inode.c
|
|
David Disseldorp |
458382 |
@@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data)
|
|
David Disseldorp |
458382 |
*/
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
static const char *CHIP;
|
|
David Disseldorp |
458382 |
+static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
/*----------------------------------------------------------------------*/
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
@@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
|
|
David Disseldorp |
458382 |
{
|
|
David Disseldorp |
458382 |
struct inode *inode;
|
|
David Disseldorp |
458382 |
struct dev_data *dev;
|
|
David Disseldorp |
458382 |
+ int rc;
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
- if (the_device)
|
|
David Disseldorp |
458382 |
- return -ESRCH;
|
|
David Disseldorp |
458382 |
+ mutex_lock(&sb_mutex);
|
|
David Disseldorp |
458382 |
+
|
|
David Disseldorp |
458382 |
+ if (the_device) {
|
|
David Disseldorp |
458382 |
+ rc = -ESRCH;
|
|
David Disseldorp |
458382 |
+ goto Done;
|
|
David Disseldorp |
458382 |
+ }
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
CHIP = usb_get_gadget_udc_name();
|
|
David Disseldorp |
458382 |
- if (!CHIP)
|
|
David Disseldorp |
458382 |
- return -ENODEV;
|
|
David Disseldorp |
458382 |
+ if (!CHIP) {
|
|
David Disseldorp |
458382 |
+ rc = -ENODEV;
|
|
David Disseldorp |
458382 |
+ goto Done;
|
|
David Disseldorp |
458382 |
+ }
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
/* superblock */
|
|
David Disseldorp |
458382 |
sb->s_blocksize = PAGE_SIZE;
|
|
David Disseldorp |
458382 |
@@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
|
|
David Disseldorp |
458382 |
* from binding to a controller.
|
|
David Disseldorp |
458382 |
*/
|
|
David Disseldorp |
458382 |
the_device = dev;
|
|
David Disseldorp |
458382 |
- return 0;
|
|
David Disseldorp |
458382 |
+ rc = 0;
|
|
David Disseldorp |
458382 |
+ goto Done;
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
-Enomem:
|
|
David Disseldorp |
458382 |
+ Enomem:
|
|
David Disseldorp |
458382 |
kfree(CHIP);
|
|
David Disseldorp |
458382 |
CHIP = NULL;
|
|
David Disseldorp |
458382 |
+ rc = -ENOMEM;
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
- return -ENOMEM;
|
|
David Disseldorp |
458382 |
+ Done:
|
|
David Disseldorp |
458382 |
+ mutex_unlock(&sb_mutex);
|
|
David Disseldorp |
458382 |
+ return rc;
|
|
David Disseldorp |
458382 |
}
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
/* "mount -t gadgetfs path /dev/gadget" ends up here */
|
|
David Disseldorp |
458382 |
@@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc)
|
|
David Disseldorp |
458382 |
static void
|
|
David Disseldorp |
458382 |
gadgetfs_kill_sb (struct super_block *sb)
|
|
David Disseldorp |
458382 |
{
|
|
David Disseldorp |
458382 |
+ mutex_lock(&sb_mutex);
|
|
David Disseldorp |
458382 |
kill_litter_super (sb);
|
|
David Disseldorp |
458382 |
if (the_device) {
|
|
David Disseldorp |
458382 |
put_dev (the_device);
|
|
David Disseldorp |
458382 |
@@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb)
|
|
David Disseldorp |
458382 |
}
|
|
David Disseldorp |
458382 |
kfree(CHIP);
|
|
David Disseldorp |
458382 |
CHIP = NULL;
|
|
David Disseldorp |
458382 |
+ mutex_unlock(&sb_mutex);
|
|
David Disseldorp |
458382 |
}
|
|
David Disseldorp |
458382 |
|
|
David Disseldorp |
458382 |
/*----------------------------------------------------------------------*/
|
|
David Disseldorp |
458382 |
--
|
|
David Disseldorp |
458382 |
2.39.0
|
|
David Disseldorp |
458382 |
|