Bug 88021

Summary: [PATCH]9P2000/9P2000.u infinite loop on invalid size field in v9fs_dir_readdir
Product: File System Reporter: Gertjan Halkes (kbt)
Component: v9fsAssignee: Eric Van Hensbergen (ericvh)
Status: ASSIGNED ---    
Severity: normal CC: alan, asmadeus, gertjan, szg00000
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 3.13.0 Subsystem:
Regression: No Bisected commit-id:
Attachments: Patch to fix the bug
Reupload of the patch, with Signed-off-by line as requested.

Description Gertjan Halkes 2014-11-11 07:16:54 UTC
When a faulty server sends a directory/stat entry with the size field set to (u16) -2, or the last entry in a message has its size field set to a size larger then the actual size of the entry, the 9p driver goes into an infinite loop and all subsequent operations hang.

The reason for the inifite loop is in vfs_file.c:148. The function blindly trusts that the server sets the size field correctly, and calculates the length of the consumed record as st.size+2. This is then used in line 156 to increment the pointer to the start of the unread data (rdir->head).

If st.size is (u16) -2 however, this means that the consumed record length is calculated as 0, which means that rdir->head is not changed and the while loop (line 139) will never terminate as the condition rdir->head < rdir->tail is never reached. It will simply try to read the same record again and again.

If the last record in a message has a size field set to a value larger than the actual record, rdir->head will end up larger than rdir->tail. The inner while loop will terminate, starting a new iteration of the outer while loop (line 129: while(1)). The problem in this case is that rdir->head > rdir->tail, thus the conditional block starting on line 130 is not executed. The result is that no new data is read from the server, and rdir->head and rdir->tail are not updated. Hence the while loop at vfs_file.c:148 is attempted again, and skipped because rdir->head is still larger than rdir->tail, starting a new iteration of the outer loop with the same result.
Comment 1 Gertjan Halkes 2014-11-11 07:22:46 UTC
Apologies, the file should of course be vfs_dir.c, not vfs_file.c.
Comment 2 Gertjan Halkes 2014-11-11 19:06:58 UTC
Created attachment 157321 [details]
Patch to fix the bug

I've created a patch which uses the length of the parsed record instead of the size supplied by the server.
Comment 3 Alan 2014-12-08 22:06:57 UTC
Please see Documentation/SubmittingPatches. Our lawyers require that we get patches submitted with a proper Signed-off-by: line.
Comment 4 Gertjan Halkes 2014-12-09 07:24:40 UTC
Created attachment 160191 [details]
Reupload of the patch, with Signed-off-by line as requested.
Comment 5 Dominique Martinet 2018-09-05 06:45:47 UTC
I just found out that this bugzilla had open bugs for 9p, with patches non-the-less!

Gertjan, it's a bit late, but this patch still applies give or take context.
I'll send it for you under your name upstream and it should get merged for 4.20, you'll be in Cc to the mails so feel free to say either here or in reply to the mails if you'd rather not be author or if the commit message I came up with is bad :)

On a less positive note, I have no idea how to manage the bug status here (I don't think I have accesses for that), I'll try to figure out who to ask eventually...

Thanks!
Comment 6 Gertjan Halkes 2018-09-05 07:54:12 UTC
Yes, please send it upstream under my name and my work email address (gertjan@google.com).

Thanks!
Comment 7 Alan 2018-09-05 23:54:14 UTC
The bugzilla maintainer at kernel.org 

But while that gets figured out if you email me a list of bugs you need closing or whater I should still have the super-power to do it 8)
Comment 8 Dominique Martinet 2018-09-05 23:58:00 UTC
Thanks Alan, I sent the kernel helpdesk a mail yesterday and they already sorted that out :)

I'll mark this resolved when the patch gets merged, it's not like there's a huge volume of bugs to work through.