On Wed, Sep 9, 2026 at 7:25 PM Xiang Mei <[email protected]> wrote:
>
> fuse_copy_fill() hits BUG_ON(!err) once the iterator backing the copy
> runs out of pages.  Over io-uring the amount copied is not bounded by the
> payload buffer the server registered, so an unprivileged user can drain
> the iterator and panic the host - mount a FUSE filesystem with small
> payload buffers, then setxattr() a larger value:
>
>   kernel BUG at fs/fuse/dev.c:1064!
>   Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
>   CPU: 1 UID: 0 PID: 148 Comm: exploit Not tainted 7.3.0-rc1 #2
>   RIP: 0010:fuse_copy_fill (fs/fuse/dev.c:1033)
>   Call Trace:
>    <TASK>
>    fuse_copy_args (fs/fuse/dev.c:1354 fs/fuse/dev.c:1380)
>    fuse_uring_args_to_ring (fs/fuse/dev_uring.c:891)
>    fuse_uring_prepare_send (fs/fuse/dev_uring.c:940 fs/fuse/dev_uring.c:1057)
>    fuse_uring_send_in_task (fs/fuse/dev_uring.c:1745)
>    tctx_task_work_run (io_uring/tw.c:96)
>    tctx_task_work (io_uring/tw.c:133)
>    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:2676)
>    do_syscall_64 (arch/x86/entry/syscall_64.c:61)
>    entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
>    </TASK>
>
> The reply path can drain it the same way, via the server-supplied
> payload_sz in fuse_uring_copy_from_ring().
>
> An exhausted iterator is recoverable, so return -EIO.  All three

super nit: imo, the reason for returning -EIO is unrelated to an
iterator being recoverable.

> fuse_copy_fill() callers already propagate the error.
>
> Fixes: c090c8abae4b ("fuse: Add io-uring sqe commit and fetch support")
> Cc: [email protected]
> Reported-by: Weiming Shi <[email protected]>
> Suggested-by: Joanne Koong <[email protected]>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Xiang Mei <[email protected]>

Thanks for your patience with iterating on this fix!

Reviewed-by: Joanne Koong <[email protected]>

Thanks,
Joanne

> ---
>  fs/fuse/dev.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 4fec31fc0b84..4148e4488d77 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1061,7 +1061,8 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
>                 err = iov_iter_get_pages2(cs->iter, &page, PAGE_SIZE, 1, 
> &off);
>                 if (err < 0)
>                         return err;
> -               BUG_ON(!err);
> +               if (!err)
> +                       return -EIO;
>                 cs->len = err;
>                 cs->offset = off;
>                 cs->pg = page;
> --
> 2.43.0
>

Reply via email to