Re: [PATCH v4 1/3] fuse: whitelist the request headers for usercopy
Bernd Schubert <[email protected]> Wed, 15 Jul 2026 23:59:30 +0200
| Newsgroups | dev.linux.lists.fuse-devel,org.kernel.vger.linux-hardening,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
On 7/15/26 20:13, Joanne Koong wrote: > On Tue, Jul 14, 2026 at 4:54 PM Xiang Mei <[email protected]> wrote: >> >> The fuse-io-uring transport copies req->in.h out to the ring in >> fuse_uring_copy_to_ring() and req->out.h back in fuse_uring_commit(). >> Both headers live inside the fuse_request slab object, whose cache >> (fuse_req_cachep) is created without a usercopy whitelist, so copying >> them directly to/from userspace trips CONFIG_HARDENED_USERCOPY and >> panics: >> >> usercopy: Kernel memory exposure attempt detected from SLUB object >> 'fuse_request' (offset 56, size 40)! >> kernel BUG at mm/usercopy.c:102! >> Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI >> RIP: 0010:usercopy_abort (mm/usercopy.c:90) >> Call Trace: >> __check_heap_object (mm/slub.c:8268) >> __check_object_size (mm/usercopy.c:197 mm/usercopy.c:258 mm/usercopy.c:223) >> copy_header_to_ring (fs/fuse/dev_uring.c:618) >> fuse_uring_prepare_send (fs/fuse/dev_uring.c:776 fs/fuse/dev_uring.c:785) >> fuse_uring_send_in_task (fs/fuse/dev_uring.c:1306) >> tctx_task_work_run (io_uring/tw.c:96) >> task_work_run (kernel/task_work.c:233) >> io_run_task_work (io_uring/tw.h:84) >> io_cqring_wait (io_uring/wait.c:278) >> __do_sys_io_uring_enter (io_uring/io_uring.c:2685) >> entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) >> >> in.h and out.h are adjacent in struct fuse_req, so a single usercopy >> region starting at in.h covers both and nothing else. Create the cache >> with that region whitelisted. >> >> Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") >> Cc: [email protected] >> Reported-by: Weiming Shi <[email protected]> >> Suggested-by: Baokun Li <[email protected]> >> Assisted-by: Claude:claude-opus-4-8 >> Signed-off-by: Xiang Mei <[email protected]> >> --- >> v3: no context change; add Bernd's Reviewed-by >> v4: drop previous tags; use kmem_cache_args to reserve usercopy area >> >> fs/fuse/dev.c | 9 +++++++-- >> fs/fuse/fuse_dev_i.h | 5 +++++ >> 2 files changed, 12 insertions(+), 2 deletions(-) >> >> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c >> index 5763a7cd3b37..b8e43e374b35 100644 >> --- a/fs/fuse/dev.c >> +++ b/fs/fuse/dev.c >> @@ -2404,10 +2404,15 @@ static struct miscdevice fuse_miscdevice = { >> >> int __init fuse_dev_init(void) >> { >> + struct kmem_cache_args args = { >> + .useroffset = offsetof(struct fuse_req, in.h), >> + .usersize = sizeof_field(struct fuse_req, in.h) + >> + sizeof_field(struct fuse_req, out.h), >> + }; >> int err = -ENOMEM; >> + >> fuse_req_cachep = kmem_cache_create("fuse_request", >> - sizeof(struct fuse_req), >> - 0, 0, NULL); >> + sizeof(struct fuse_req), &args, 0); >> if (!fuse_req_cachep) >> goto out; >> >> diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h >> index 668c8391d61c..b511aaab6bfc 100644 >> --- a/fs/fuse/fuse_dev_i.h >> +++ b/fs/fuse/fuse_dev_i.h >> @@ -81,6 +81,11 @@ struct fuse_req { >> /** @flags: Request flags, updated with test/set/clear_bit() */ >> unsigned long flags; >> >> + /* >> + * @in and @out are the usercopy region of this cache (see >> + * fuse_dev_init()); keep them adjacent. >> + */ >> + >> /** @in: The request input header */ >> struct { >> /** @in.h: The request input header */ >> -- >> 2.43.0 >> > > I think this is more a matter of preference as they're both > functionally correct but imo the previous approach seemed cleaner, > given that only the io-uring path needs this. The extra hop goes > through a tmp stack variable whose memory is already in the L1 cache > and the memcpys are small (~40 bytes), so I think the cost is > essentially negligible. Not sure if Bernd or Miklos or Amir have a > preference here. Sorry for late replies, currently on vacation and reviews only when everyone else is asleep. I don't have a strong opinion, I wondered the same if the stack copy was avoidable, but then came to the same conclusion as Joanne - negligible overhead. Thanks, Bernd