Bug 263625

Summary: FUSE_CREATE is broken on anything older than protocol version 7.9
Product: Base System Reporter: Ali Abdallah <ali.abdallah>
Component: kernAssignee: Alan Somers <asomers>
Status: Closed FIXED    
Severity: Affects Only Me CC: asomers, emaste
Priority: --- Flags: asomers: mfc-stable13+
asomers: mfc-stable12-
Version: CURRENT   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
Fix FUSE_CREATE compat entry size read
none
Type cast test for version 7.8 or earlier none

Description Ali Abdallah 2022-04-28 09:42:39 UTC
Created attachment 233558 [details]
Fix FUSE_CREATE compat entry size read

While porting webdav fuse filesystem to FreeBSD, which uses protocol version 7.5, I noticed that FUSE_CREATE always fails. After digging into the code, I noticed that on FUSE_CREATE, the cast of fuse_open_out to fuse_entry_out has the wrong offset for protocol versions prior to 7.9.

AFAIK, prior to 7.9 version, fuse_attr didn't have blksize and padding fields, so FUSE_COMPAT_ENTRY_OUT_SIZE offset should be used instead in this case.

The attached patch should fix the issue.
Comment 1 Alan Somers freebsd_committer freebsd_triage 2022-04-28 16:07:44 UTC
7.5, mein gott!  I've never seen any fuse file systems that use protocols earlier than 7.8.  Are you sure that FUSE_CREATE is broken for protocol 7.8?  There is a regression test for that.  So does it actually work on 7.8, or is the regression test incomplete?  Would you mind taking a look?  The test is in tests/sys/fs/fusefs/create.cc, and it's named "Create_7_8".
Comment 2 Ali Abdallah 2022-04-28 17:35:14 UTC
Created attachment 233566 [details]
Type cast test for version 7.8 or earlier

I didn't read the code of tests/sys/fs/fusefs/create.cc, but the test runs ok with or without the attached patch, the issue is not create itself, but subsequent write after create, let me try to explain it better.

fuse_attr prior to version 7.8 didn't have blksize and padding [1].

When using fuse with protocol version earlier than 7.8, FUSE_CREATE goes fine, but then on FUSE_WRITE for the same file, I was getting strange file handle in my fuse program (and so the program was returning Bad file descriptor to the kernel).

The cast in fuse_vnops.c:L1045

foo = (struct fuse_open_out*)(feo + 1);

cast feo + 1 to fuse_open_out, feo is fuse_entry_out, which is 

struct fuse_entry_out {
	uint64_t	nodeid;		/* Inode ID */
	uint64_t	generation;	/* Inode generation: nodeid:gen must
					   be unique for the fs's lifetime */
	uint64_t	entry_valid;	/* Cache timeout for the name */
	uint64_t	attr_valid;	/* Cache timeout for the attributes */
	uint32_t	entry_valid_nsec;
	uint32_t	attr_valid_nsec;
	struct fuse_attr attr;
};

Which has fuse_attr attributes at last field, so if a userspace fuse program is using protocol version earlier than 7.9, the cast above gets you invalid data, as the fuse_attr field filled in userspace are shorter by 8 bytes than the one used in the fuse driver.

Attached a test code which hopefully explains better what is happening between a fuse 7.8 userspace program and the FreeBSD fuse driver.

[1] https://github.com/torvalds/linux/blob/e9168c189fd54171124b5d25644024d99869e6a8/include/linux/fuse.h
Comment 3 Alan Somers freebsd_committer freebsd_triage 2022-04-28 19:08:33 UTC
I get it.  With protocol 7.8, the kernel reads the fh and open_flags fields wrong.  But most users don't notice, because use of those fields is actually fairly rare.  That's why nobody has noticed it so far, including me and I use fuse 7.8 file systems that don't set fh.  I can reproduce it.
Comment 4 commit-hook freebsd_committer freebsd_triage 2022-04-28 21:20:40 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=45825a12f9851213e627cf41398706bacb793f83

commit 45825a12f9851213e627cf41398706bacb793f83
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-04-28 21:13:09 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-04-28 21:13:09 +0000

    fusefs: fix FUSE_CREATE with file handles and fuse protocol < 7.9

    Prior to fuse protocol version 7.9, the fuse_entry_out structure had a
    smaller size.  But fuse_vnop_create did not take that into account when
    working with servers that use older protocols.  The bug does not matter
    for servers which don't use file handles or open flags (the only fields
    affected).

    PR:             263625
    Submitted by:   Ali Abdallah <ali.abdallah@suse.com>
    MFC after:      2 weeks

 sys/fs/fuse/fuse_vnops.c      |  6 +++++-
 tests/sys/fs/fusefs/create.cc | 13 ++++++++-----
 2 files changed, 13 insertions(+), 6 deletions(-)
Comment 5 commit-hook freebsd_committer freebsd_triage 2022-05-12 20:45:06 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=c7b4932df66d8a5cd299898a2c477ba7d7248654

commit c7b4932df66d8a5cd299898a2c477ba7d7248654
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-04-28 21:13:09 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-05-12 20:43:22 +0000

    fusefs: fix FUSE_CREATE with file handles and fuse protocol < 7.9

    Prior to fuse protocol version 7.9, the fuse_entry_out structure had a
    smaller size.  But fuse_vnop_create did not take that into account when
    working with servers that use older protocols.  The bug does not matter
    for servers which don't use file handles or open flags (the only fields
    affected).

    PR:             263625
    Submitted by:   Ali Abdallah <ali.abdallah@suse.com>

    (cherry picked from commit 45825a12f9851213e627cf41398706bacb793f83)

 sys/fs/fuse/fuse_vnops.c      |  6 +++++-
 tests/sys/fs/fusefs/create.cc | 13 ++++++++-----
 2 files changed, 13 insertions(+), 6 deletions(-)
Comment 6 Ali Abdallah 2022-05-13 06:43:37 UTC
Many thanks for applying the fix! FYI, I will submit a port of fuse-davfs that I recently ported to FreeBSD [1] that only works with v >= 1400057 and v >= 1301504.

[1] https://git.savannah.nongnu.org/cgit/davfs2.git/log/?h=fbsd-support
Comment 7 commit-hook freebsd_committer freebsd_triage 2022-08-20 01:17:13 UTC
A commit in branch stable/12 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=e2182a594d84a84a0ff3edf2a7ad9ee141027a60

commit e2182a594d84a84a0ff3edf2a7ad9ee141027a60
Author:     Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2022-04-28 21:13:09 +0000
Commit:     Alan Somers <asomers@FreeBSD.org>
CommitDate: 2022-08-20 01:11:23 +0000

    fusefs: fix FUSE_CREATE with file handles and fuse protocol < 7.9

    Prior to fuse protocol version 7.9, the fuse_entry_out structure had a
    smaller size.  But fuse_vnop_create did not take that into account when
    working with servers that use older protocols.  The bug does not matter
    for servers which don't use file handles or open flags (the only fields
    affected).

    PR:             263625
    Submitted by:   Ali Abdallah <ali.abdallah@suse.com>

    (cherry picked from commit 45825a12f9851213e627cf41398706bacb793f83)

 sys/fs/fuse/fuse_vnops.c      |  6 +++++-
 tests/sys/fs/fusefs/create.cc | 13 ++++++++-----
 2 files changed, 13 insertions(+), 6 deletions(-)