Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107575743
D31994.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D31994.diff
View Options
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2199,25 +2199,23 @@
}
static int
-fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *sz)
+fuse_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *blksz)
{
off_t filesize;
- int blksz, err;
+ int err;
const int biosize = fuse_iosize(vp);
err = fuse_vnode_size(vp, &filesize, NULL, NULL);
- KASSERT(err == 0, ("vfs_bio_getpages can't handle errors here"));
- if (err)
- return biosize;
-
- if ((off_t)lbn * biosize >= filesize) {
- blksz = 0;
+ if (err) {
+ /* This will turn into a SIGBUS */
+ return (EIO);
+ } else if ((off_t)lbn * biosize >= filesize) {
+ *blksz = 0;
} else if ((off_t)(lbn + 1) * biosize > filesize) {
- blksz = filesize - (off_t)lbn *biosize;
+ *blksz = filesize - (off_t)lbn *biosize;
} else {
- blksz = biosize;
+ *blksz = biosize;
}
- *sz = blksz;
return (0);
}
diff --git a/tests/sys/fs/fusefs/read.cc b/tests/sys/fs/fusefs/read.cc
--- a/tests/sys/fs/fusefs/read.cc
+++ b/tests/sys/fs/fusefs/read.cc
@@ -40,6 +40,8 @@
#include <aio.h>
#include <fcntl.h>
#include <semaphore.h>
+#include <setjmp.h>
+#include <signal.h>
#include <unistd.h>
}
@@ -103,6 +105,33 @@
}
};
+class ReadSigbus: public Read
+{
+public:
+static jmp_buf s_jmpbuf;
+static sig_atomic_t s_si_addr;
+
+void TearDown() {
+ struct sigaction sa;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGBUS, &sa, NULL);
+
+ FuseTest::TearDown();
+}
+
+};
+
+static void
+handle_sigbus(int signo __unused, siginfo_t *info, void *uap __unused) {
+ ReadSigbus::s_si_addr = (sig_atomic_t)info->si_addr;
+ longjmp(ReadSigbus::s_jmpbuf, 1);
+}
+
+jmp_buf ReadSigbus::s_jmpbuf;
+sig_atomic_t ReadSigbus::s_si_addr;
+
/* AIO reads need to set the header's pid field correctly */
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */
TEST_F(AioRead, aio_read)
@@ -584,6 +613,56 @@
leak(fd);
}
+/* Read of an mmap()ed file fails */
+TEST_F(ReadSigbus, mmap_eio)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const char *CONTENTS = "abcdefgh";
+ struct sigaction sa;
+ uint64_t ino = 42;
+ int fd;
+ ssize_t len;
+ size_t bufsize = strlen(CONTENTS);
+ void *p;
+
+ len = getpagesize();
+
+ expect_lookup(RELPATH, ino, bufsize);
+ expect_open(ino, 0, 1);
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in.header.opcode == FUSE_READ &&
+ in.header.nodeid == ino &&
+ in.body.read.fh == Read::FH);
+ }, Eq(true)),
+ _)
+ ).WillRepeatedly(Invoke(ReturnErrno(EIO)));
+
+ fd = open(FULLPATH, O_RDONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+ ASSERT_NE(MAP_FAILED, p) << strerror(errno);
+
+ /* Accessing the mapped page should return SIGBUS. */
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sa.sa_sigaction = handle_sigbus;
+ sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
+ ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
+ if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
+ atomic_signal_fence(std::memory_order::memory_order_seq_cst);
+ volatile char x __unused = *(volatile char*)p;
+ FAIL() << "shouldn't get here";
+ }
+
+ ASSERT_EQ(p, (void*)ReadSigbus::s_si_addr);
+ ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
+ leak(fd);
+}
+
/*
* A read via mmap comes up short, indicating that the file was truncated
* server-side.
@@ -634,6 +713,83 @@
leak(fd);
}
+/*
+ * During VOP_GETPAGES, the FUSE server fails a FUSE_GETATTR operation. This
+ * almost certainly indicates a buggy FUSE server, and our goal should be not
+ * to panic. Instead, generate SIGBUS.
+ */
+TEST_F(ReadSigbus, mmap_getblksz_fail)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const char *CONTENTS = "abcdefgh";
+ struct sigaction sa;
+ Sequence seq;
+ uint64_t ino = 42;
+ int fd;
+ ssize_t len;
+ size_t bufsize = strlen(CONTENTS);
+ mode_t mode = S_IFREG | 0644;
+ void *p;
+
+ len = getpagesize();
+
+ FuseTest::expect_lookup(RELPATH, ino, mode, bufsize, 1, 0);
+ /* Expect two GETATTR calls that succeed, followed by one that fail. */
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in.header.opcode == FUSE_GETATTR &&
+ in.header.nodeid == ino);
+ }, Eq(true)),
+ _)
+ ).Times(2)
+ .InSequence(seq)
+ .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
+ SET_OUT_HEADER_LEN(out, attr);
+ out.body.attr.attr.ino = ino;
+ out.body.attr.attr.mode = mode;
+ out.body.attr.attr.size = bufsize;
+ 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)
+ .WillRepeatedly(Invoke(ReturnErrno(EIO)));
+ expect_open(ino, 0, 1);
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in.header.opcode == FUSE_READ);
+ }, Eq(true)),
+ _)
+ ).Times(0);
+
+ fd = open(FULLPATH, O_RDONLY);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ p = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+ ASSERT_NE(MAP_FAILED, p) << strerror(errno);
+
+ /* Accessing the mapped page should return SIGBUS. */
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ sa.sa_sigaction = handle_sigbus;
+ sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
+ ASSERT_EQ(0, sigaction(SIGBUS, &sa, NULL)) << strerror(errno);
+ if (setjmp(ReadSigbus::s_jmpbuf) == 0) {
+ atomic_signal_fence(std::memory_order::memory_order_seq_cst);
+ volatile char x __unused = *(volatile char*)p;
+ FAIL() << "shouldn't get here";
+ }
+
+ ASSERT_EQ(p, (void*)ReadSigbus::s_si_addr);
+ ASSERT_EQ(0, munmap(p, len)) << strerror(errno);
+ leak(fd);
+}
+
/*
* Just as when FOPEN_DIRECT_IO is used, reads with O_DIRECT should bypass
* cache and to straight to the daemon
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 17, 3:13 AM (21 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15832621
Default Alt Text
D31994.diff (5 KB)
Attached To
Mode
D31994: fusefs: don't panic if FUSE_GETATTR fails durint VOP_GETPAGES
Attached
Detach File
Event Timeline
Log In to Comment