Re: WARNING in fuse_request_end

From: Hou Tao
Date: Tue May 07 2024 - 09:37:43 EST


Hi,

On 5/7/2024 10:52 AM, lee bruce wrote:
> Hello, I found a new bug titled "WARNING in fuse_request_end" and
> comfirmed in the lastest upstream.
>
> If you fix this issue, please add the following tag to the commit:
> Reported-by: xingwei lee <xrivendell7@xxxxxxxxx>
> Reported-by: yue sun <samsun1006219@xxxxxxxxx>
> kernel: upstream dccb07f2914cdab2ac3a5b6c98406f765acab803(lastest)
> kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=7144b4fe7fbf5900
> with KASAN enabled
> compiler: gcc (GCC) 13.2.1 20231011
>
> TITLE: WARNING in fuse_request_end
> ------------[ cut here ]------------
> WARNING: CPU: 0 PID: 8264 at fs/fuse/dev.c:300
> fuse_request_end+0x685/0x7e0 fs/fuse/dev.c:300
> Modules linked in:
> CPU: 0 PID: 8264 Comm: ab2 Not tainted 6.9.0-rc7-00012-gdccb07f2914c #27
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
> 1.16.2-1.fc38 04/01/2014
> RIP: 0010:fuse_request_end+0x685/0x7e0 fs/fuse/dev.c:300
> Code: ff 3c 03 0f 8f d6 fd ff ff 4c 89 ff e8 24 31 f9 fe e9 c9 fd ff
> ff e8 1a 8b 9c fe 90 0f 0b 90 e9 a9 fa ff ff e8 0c 8b 9c fe 90 <0f> 0b
> 90 e9 e6 fa ff ff 48 89 34 24 e8 fa 30 f9 fe 48 8b 34 24 e9
> RSP: 0018:ffffc9000eb17a60 EFLAGS: 00010293
> RAX: 0000000000000000 RBX: ffff8880342cc008 RCX: ffffffff82f20b6a
> RDX: ffff88802fa79ec0 RSI: ffffffff82f21084 RDI: 0000000000000007
> RBP: ffff8880342cc038 R08: 0000000000000007 R09: 0000000000000000
> R10: 0000000000000100 R11: 0000000000000000 R12: ffff888029989000
> R13: ffff88802cc39740 R14: 0000000000000100 R15: ffff8880342cc038
> FS: 00007febdf6d96c0(0000) GS:ffff8880b9400000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000020002200 CR3: 000000001fe6c000 CR4: 0000000000750ef0
> PKRU: 55555554
> Call Trace:
> <TASK>
> fuse_dev_do_read.constprop.0+0xd36/0x1dd0 fs/fuse/dev.c:1334
> fuse_dev_read+0x166/0x200 fs/fuse/dev.c:1367
> call_read_iter include/linux/fs.h:2104 [inline]
> new_sync_read fs/read_write.c:395 [inline]
> vfs_read+0x85b/0xba0 fs/read_write.c:476
> ksys_read+0x12f/0x260 fs/read_write.c:619
> do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> do_syscall_64+0xce/0x260 arch/x86/entry/common.c:83
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x439ae9
> Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 f1 17 00 00 90 48 89 f8 48
> 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d
> 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007febdf6d91f8 EFLAGS: 00000213 ORIG_RAX: 0000000000000000
> RAX: ffffffffffffffda RBX: 00007febdf6d96c0 RCX: 0000000000439ae9
> RDX: 0000000000002020 RSI: 0000000020000140 RDI: 0000000000000004
> RBP: 00007febdf6d9220 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000213 R12: ffffffffffffffb0
> R13: 000000000000006e R14: 00007ffde3c37740 R15: 00007ffde3c37828
> </TASK>
>
> =* repro.c =*

SNIP

> case 4:
> *(uint32_t*)0x20002200 = 0x28;
> *(uint32_t*)0x20002204 = 7;
> *(uint64_t*)0x20002208 = 0;
> *(uint64_t*)0x20002210 = 0;
> *(uint64_t*)0x20002218 = 0;
> *(uint64_t*)0x20002220 = 0;
> syscall(__NR_write, /*fd=*/r[1], /*arg=*/0x20002200ul, /*len=*/0x28ul);

Thanks for the report and the reproducer program.  It seems that the
warning is due to the FUSE_NOTIFY_RESEND notify send by the write()
syscall above and it happens as follows:

(1) the reproducer calls fuse_dev_read() to read the INIT request.
The read succeeds. During the read, bit FR_SENT will be set on req->flags.
(2) the reproducer calls fuse_dev_write() to write a FUSE_NOTIFY_RESEND
to resend all requests.
(3) the INIT request is moved from processing list to pending list again
(4) the reproducer calls fuse_dev_read() with an invalid output address
fuse_dev_read() will try to copy the INIT request to the output address,
but it fails,so the INIT request is ended and triggers the warning in
fuse_request_end().

A straightforward fix is to clear the FR_SENT bit in as show below:

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 3ec8bb5e68ff5..840cefdf24e26 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1814,6 +1814,7 @@ static void fuse_resend(struct fuse_conn *fc)

        list_for_each_entry_safe(req, next, &to_queue, list) {
                __set_bit(FR_PENDING, &req->flags);
+               clear_bit(FR_SENT, &req->flags);
                /* mark the request as resend request */
                req->in.h.unique |= FUSE_UNIQUE_RESEND;
        }

But I think more code checking and tests are needed before posting it as
a formal patch.

> break;
> case 5:
> syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x3000ul, /*prot=*/0ul,
> /*flags=*/0x12ul, /*fd=*/r[0], /*offset=*/0ul);
> break;
> case 6:
> syscall(__NR_read, /*fd=*/r[1], /*buf=*/0x20000140ul, /*len=*/0x2020ul);
> break;
> }
> }
> int main(void)
> {
> syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
> /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
> loop();
> return 0;
> }
>
>
> =* repro.txt =*
> r0 = openat$cgroup_ro(0xffffffffffffff9c,
> &(0x7f0000001cc0)='memory.events\x00', 0x275a, 0x0)
> r1 = openat$fuse(0xffffffffffffff9c, &(0x7f0000000100), 0x2, 0x0)
> syz_mount_image$fuse(&(0x7f0000000080),
> &(0x7f00000000c0)='./file1\x00', 0x0, &(0x7f0000006380)={{'fd', 0x3d,
> r1}, 0x2c, {'rootmode', 0x3d, 0x4000}}, 0x0, 0x0, 0x0)
> read$FUSE(r1, &(0x7f0000000140)={0x2020}, 0x2020)
> write$FUSE_NOTIFY_INVAL_INODE(r1, &(0x7f0000002200)={0x28, 0x7}, 0x28)
> mmap(&(0x7f0000000000/0x3000)=nil, 0x3000, 0x0, 0x12, r0, 0x0)
> read$FUSE(r1, &(0x7f0000000140)={0x2020}, 0x2020)
>
>
> Please also see:
> https://gist.github.com/xrivendell7/346cb2c74cf5da4cad54cbdc8d1f0ded
>
> I hope it helps.
> Best regards.
> xingwei Lee
>
> .