git: cf2ed0edaefb - stable/14 - fusefs: fix an uninitialized memory access in fuse_vnop_deallocate
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 10 Oct 2024 19:07:24 UTC
The branch stable/14 has been updated by asomers:
URL: https://cgit.FreeBSD.org/src/commit/?id=cf2ed0edaefbd273da4dc4fc51392fddb2165891
commit cf2ed0edaefbd273da4dc4fc51392fddb2165891
Author: Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2024-09-08 21:50:40 +0000
Commit: Alan Somers <asomers@FreeBSD.org>
CommitDate: 2024-10-10 18:48:39 +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
(cherry picked from commit f93a50d69df2e996ff1d4f793d0dcb9de655ebdc)
---
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 8eb37423618c..22564c65c44d 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -3082,8 +3082,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";