From: Yu Zhang <yuz08559@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Alan Stern <stern@rowland.harvard.edu>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
Yu Zhang <yuz08559@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH v2] usb: gadget: f_mass_storage: take filesem in nofua store to fix backing-file UAF
Date: Tue, 20 Oct 2026 12:30:50 +1000 [thread overview]
Message-ID: <20261020023050.87701-1-yuz08559@gmail.com> (raw)
In-Reply-To: <20261018130519.65850-1-yuz08559@gmail.com>
fsg_store_nofua() syncs the LUN's backing file when switching from async
to sync mode:
if (!nofua && curlun->nofua)
fsg_lun_fsync_sub(curlun);
fsg_lun_fsync_sub() dereferences curlun->filp (vfs_fsync(filp)). Unlike
every other store that touches the backing file -- fsg_store_ro() and
fsg_store_cdrom() (down_read), fsg_store_file() (down_write) --
fsg_store_nofua() holds no filesem while doing so.
A concurrent close of the backing file runs under down_write(filesem) and
does fput(curlun->filp) in fsg_lun_close() (fsg_store_file() with an empty
path, the SCSI START_STOP eject in do_start_stop(), or forced_eject), so
it can free the file while fsg_store_nofua() is dereferencing it:
BUG: KASAN: slab-use-after-free in vfs_fsync+0x20/0xe0
vfs_fsync+0x20/0xe0
fsg_lun_fsync_sub+0xa0/0xd0
fsg_store_nofua+0x138/0x160
configfs_write_iter+0x1a7/0x250
vfs_write+0x5df/0x940
Allocated by task 3459:
fsg_store_file+0x150/0x1f0
configfs_write_iter+0x1a7/0x250
Freed by task 3459:
__fput+0x456/0x6c0
__fput_deferred+0x10d/0x330
fsg_store_file+0x9e/0x1f0
configfs_write_iter+0x1a7/0x250
Hold filesem for read around the fsync in fsg_store_nofua() so the backing
file cannot be closed underneath it. The lock is only needed when the
fsync actually runs, so it is taken only in that branch.
Reproduced on a mass_storage gadget over dummy_hcd by writing lun.N/nofua
(1 then 0) from one task while another task rewrites and clears lun.N/file.
Cc: stable@vger.kernel.org
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
---
v2:
- Use guard(rwsem_read) instead of a bare down_read()/up_read() pair
(Greg KH).
- Take filesem only inside the branch that actually calls
fsg_lun_fsync_sub(), not around the whole function / the
curlun->nofua assignment, since the lock is only needed for the sync
(Alan Stern).
v1: https://lore.kernel.org/all/20261018130519.65850-1-yuz08559@gmail.com/
drivers/usb/gadget/function/f_mass_storage.c | 8 ++++++--
drivers/usb/gadget/function/storage_common.c | 7 +++++--
drivers/usb/gadget/function/storage_common.h | 3 ++-
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index b7b06cb..6712566 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2663,8 +2663,9 @@ static ssize_t nofua_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
+ struct rw_semaphore *filesem = dev_get_drvdata(dev);
- return fsg_store_nofua(curlun, buf, count);
+ return fsg_store_nofua(curlun, filesem, buf, count);
}
static ssize_t file_store(struct device *dev, struct device_attribute *attr,
@@ -3239,7 +3240,10 @@ static ssize_t fsg_lun_opts_nofua_show(struct config_item *item, char *page)
static ssize_t fsg_lun_opts_nofua_store(struct config_item *item,
const char *page, size_t len)
{
- return fsg_store_nofua(to_fsg_lun_opts(item)->lun, page, len);
+ struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
+ struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
+
+ return fsg_store_nofua(opts->lun, &fsg_opts->common->filesem, page, len);
}
CONFIGFS_ATTR(fsg_lun_opts_, nofua);
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index 75831f2..51a70f2 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -415,7 +415,8 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
}
EXPORT_SYMBOL_GPL(fsg_store_ro);
-ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
+ssize_t fsg_store_nofua(struct fsg_lun *curlun, struct rw_semaphore *filesem,
+ const char *buf, size_t count)
{
bool nofua;
int ret;
@@ -425,8 +426,10 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
return ret;
/* Sync data when switching from async mode to sync */
- if (!nofua && curlun->nofua)
+ if (!nofua && curlun->nofua) {
+ guard(rwsem_read)(filesem);
fsg_lun_fsync_sub(curlun);
+ }
curlun->nofua = nofua;
diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
index 11ac785..347a86b 100644
--- a/drivers/usb/gadget/function/storage_common.h
+++ b/drivers/usb/gadget/function/storage_common.h
@@ -210,7 +210,8 @@ ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf);
ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf);
ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
const char *buf, size_t count);
-ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count);
+ssize_t fsg_store_nofua(struct fsg_lun *curlun, struct rw_semaphore *filesem,
+ const char *buf, size_t count);
ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
const char *buf, size_t count);
ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
--
2.43.0
next prev parent reply other threads:[~2026-10-20 2:31 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-18 13:05 [PATCH] usb: gadget: f_mass_storage: take filesem in nofua store to fix backing-file UAF Yu Zhang
2026-10-18 13:08 ` sashiko-bot
2026-10-18 13:34 ` Greg Kroah-Hartman
2026-10-18 15:50 ` Alan Stern
2026-10-20 2:30 ` Yu Zhang [this message]
2026-10-20 8:03 ` [PATCH v2] " sashiko-bot
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=20261020023050.87701-1-yuz08559@gmail.com \
--to=yuz08559@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@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.