| Summary: | FUSE_CREATE is broken on anything older than protocol version 7.9 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | Ali Abdallah <ali.abdallah> | ||||||
| Component: | kern | Assignee: | 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: |
|
||||||||
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". 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 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. 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(-) 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(-) 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 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(-) |
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.