The branch main has been updated by asomers:

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

commit f93a50d69df2e996ff1d4f793d0dcb9de655ebdc
Author:     Alan Somers <asom...@freebsd.org>
AuthorDate: 2024-09-08 21:50:40 +0000
Commit:     Alan Somers <asom...@freebsd.org>
CommitDate: 2024-09-08 21:50:40 +0000

    fusefs: fix an uninitialized memory access in fuse_vnop_deallocate
    
    If the FUSE_GETATTR issued to query a file's size during
    fuse_vnop_deallocate failed for any reason, then fuse_vnop_deallocate
    would attempt to destroy an uninitialized fuse_dispatcher struct, with a
    crash the likely result.  This bug only affects FUSE file systems that
    implement FUSE_FALLOCATE, and is unlikely to be seen on those that don't
    disable attribute caching.
    
    Reported by:    Coverity Scan
    CID:            1505308
    MFC after:      2 weeks
---
 sys/fs/fuse/fuse_vnops.c         |  2 +-
 tests/sys/fs/fusefs/fallocate.cc | 51 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index bf272ab706da..30993441bd72 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -3075,8 +3075,8 @@ fuse_vnop_deallocate(struct vop_deallocate_args *ap)
                            false);
        }
 
-out:
        fdisp_destroy(&fdi);
+out:
        if (closefufh)
                fuse_filehandle_close(vp, fufh, curthread, cred);
 
diff --git a/tests/sys/fs/fusefs/fallocate.cc b/tests/sys/fs/fusefs/fallocate.cc
index ff5e3eb4f4bb..a05760207648 100644
--- a/tests/sys/fs/fusefs/fallocate.cc
+++ b/tests/sys/fs/fusefs/fallocate.cc
@@ -310,6 +310,57 @@ TEST_F(Fspacectl, erofs)
        leak(fd);
 }
 
+/*
+ * If FUSE_GETATTR fails when determining the size of the file, fspacectl
+ * should fail gracefully.  This failure mode is easiest to trigger when
+ * attribute caching is disabled.
+ */
+TEST_F(Fspacectl, getattr_fails)
+{
+       const char FULLPATH[] = "mountpoint/some_file.txt";
+       const char RELPATH[] = "some_file.txt";
+       Sequence seq;
+       struct spacectl_range rqsr;
+       const uint64_t ino = 42;
+       const uint64_t fsize = 2000;
+       int fd;
+
+       expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1, 0);
+       expect_open(ino, 0, 1);
+       EXPECT_CALL(*m_mock, process(
+               ResultOf([](auto in) {
+                       return (in.header.opcode == FUSE_GETATTR &&
+                               in.header.nodeid == ino);
+               }, Eq(true)),
+               _)
+       ).Times(1)
+       .InSequence(seq)
+       .WillOnce(Invoke(ReturnImmediate([](auto i __unused, auto& out) {
+               SET_OUT_HEADER_LEN(out, attr);
+               out.body.attr.attr.ino = ino;
+               out.body.attr.attr.mode = S_IFREG | 0644;
+               out.body.attr.attr.size = fsize;
+               out.body.attr.attr_valid = 0;
+       })));
+       EXPECT_CALL(*m_mock, process(
+               ResultOf([](auto in) {
+                       return (in.header.opcode == FUSE_GETATTR &&
+                               in.header.nodeid == ino);
+               }, Eq(true)),
+               _)
+       ).InSequence(seq)
+       .WillOnce(ReturnErrno(EIO));
+
+       fd = open(FULLPATH, O_RDWR);
+       ASSERT_LE(0, fd) << strerror(errno);
+       rqsr.r_offset = 500;
+       rqsr.r_len = 1000;
+       EXPECT_EQ(-1, fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, NULL));
+       EXPECT_EQ(EIO, errno);
+
+       leak(fd);
+}
+
 TEST_F(Fspacectl, ok)
 {
        const char FULLPATH[] = "mountpoint/some_file.txt";

Reply via email to