On Thu, Jul 9, 2026 at 2:11 PM Xiang Mei <[email protected]> wrote: > > The fuse-io-uring transport imports each ring entry's payload buffer at > ring->max_payload_sz and bounds both copy directions against that value, > ignoring the buffer length the server actually registered. Both the > server-supplied reply payload_sz (fuse_uring_copy_from_ring) and an > oversized request payload such as a large FUSE_SETXATTR value > (fuse_uring_args_to_ring) can then overrun the imported iterator and hit > fuse_copy_fill()'s BUG_ON(!err): > > kernel BUG at fs/fuse/dev.c:1053! > Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI > RIP: 0010:fuse_copy_fill (fs/fuse/dev.c:1022) > Call Trace: > fuse_copy_args (fs/fuse/dev.c:1329 fs/fuse/dev.c:1351) > fuse_uring_copy_from_ring (fs/fuse/dev_uring.c:686) > fuse_uring_cmd (fs/fuse/dev_uring.c:1226) > io_uring_cmd (io_uring/uring_cmd.c:271) > __io_issue_sqe (io_uring/io_uring.c:1395) > io_issue_sqe (io_uring/io_uring.c:1418) > io_submit_sqes (io_uring/io_uring.c:1649 io_uring/io_uring.c:1934 > io_uring/io_uring.c:2057) > __do_sys_io_uring_enter (io_uring/io_uring.c:2646) > do_syscall_64 (arch/x86/entry/syscall_64.c:63 > arch/x86/entry/syscall_64.c:94) > entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) > > The request path overruns the same way, via fuse_copy_args() -> > fuse_uring_args_to_ring(). > > Store the registered payload length (payload->iov_len) in the ring entry > and use it for the import and both bounds checks, so the buffer the > server provided is honoured and an oversized reply/request is rejected > (-EINVAL for a reply, and -E2BIG/-EIO for a request, matching > fuse_dev_do_read()) instead of panicking. > > Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support") > Cc: [email protected] > Reported-by: Weiming Shi <[email protected]> > Assisted-by: Claude:claude-opus-4-8 > Signed-off-by: Xiang Mei <[email protected]> > --- > v3: propose the patch fixing another issue found by Bernd by Joanne suggested > way > > fs/fuse/dev_uring.c | 9 ++++++++- > fs/fuse/dev_uring_i.h | 1 + > 2 files changed, 9 insertions(+), 1 deletion(-) > > diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c > index 0814681eb04b..248e5a3e340e 100644 > --- a/fs/fuse/dev_uring.c > +++ b/fs/fuse/dev_uring.c > @@ -650,7 +650,7 @@ static int setup_fuse_copy_state(struct fuse_copy_state > *cs, > { > int err; > > - err = import_ubuf(dir, ent->payload, ring->max_payload_sz, iter); > + err = import_ubuf(dir, ent->payload, ent->payload_sz, iter); > if (err) { > pr_info_ratelimited("fuse: Import of user buffer failed\n"); > return err; > @@ -679,6 +679,9 @@ static int fuse_uring_copy_from_ring(struct fuse_ring > *ring, > if (err) > return err; > > + if (ring_in_out.payload_sz > ent->payload_sz) > + return -EINVAL; > + > err = setup_fuse_copy_state(&cs, ring, req, ent, ITER_SOURCE, &iter); > if (err) > return err; > @@ -725,6 +728,9 @@ static int fuse_uring_args_to_ring(struct fuse_ring > *ring, struct fuse_req *req, > num_args--; > } > > + if (fuse_len_args(num_args, (struct fuse_arg *)in_args) > > ent->payload_sz) > + return args->opcode == FUSE_SETXATTR ? -E2BIG : -EIO;
Reviewed-by: Joanne Koong <[email protected]> Not saying you have to do this, but if you wanted to, I think it'd be nice to have a separate cleanup patch that deduplicates this setxattr special casing logic between the /dev/fuse path and here. Thanks, Joanne

