Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F166131061
D31994.id95266.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D31994.id95266.diff
View Options
Index: sys/fs/fuse/fuse_vnops.c
===================================================================
--- sys/fs/fuse/fuse_vnops.c
+++ sys/fs/fuse/fuse_vnops.c
@@ -2206,11 +2206,10 @@
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) {
+ if (err) {
+ /* Returning -1 effectively causes a SIGBUS */
+ blksz = -1;
+ } else if ((off_t)lbn * biosize >= filesize) {
blksz = 0;
} else if ((off_t)(lbn + 1) * biosize > filesize) {
blksz = filesize - (off_t)lbn *biosize;
Index: sys/kern/vfs_bio.c
===================================================================
--- sys/kern/vfs_bio.c
+++ sys/kern/vfs_bio.c
@@ -5222,6 +5222,8 @@
la += PAGE_SIZE;
lpart = la > object->un_pager.vnp.vnp_size;
bo_bs = get_blksize(vp, get_lblkno(vp, IDX_TO_OFF(ma[0]->pindex)));
+ if (bo_bs < 0)
+ return (VM_PAGER_ERROR);
/*
* Calculate read-ahead, behind and total pages.
@@ -5278,6 +5280,10 @@
lbnp = lbn;
bsize = get_blksize(vp, lbn);
+ if (bsize < 0) {
+ error = 1;
+ goto end_pages;
+ }
error = bread_gb(vp, lbn, bsize, curthread->td_ucred,
br_flags, &bp);
if (error != 0)
Index: tests/sys/fs/fusefs/read.cc
===================================================================
--- tests/sys/fs/fusefs/read.cc
+++ tests/sys/fs/fusefs/read.cc
@@ -584,6 +584,52 @@
leak(fd);
}
+/* Read of an mmap()ed file fails */
+TEST_F(Read, mmap_eio)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const char *CONTENTS = "abcdefgh";
+ 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);
+
+ /*
+ * Actually accessing the mapped page would SIGBUS, which would break
+ * googletest's TearDown. But mlock will return ENOMEM if the memory
+ * access would've SIGBUSsed
+ */
+ ASSERT_NE(0, mlock(p, bufsize));
+ ASSERT_EQ(errno, ENOMEM);
+ //ASSERT_NE(SIG_ERR, signal(SIGBUS, sigbus_handler)) << strerror(errno);
+ //ASSERT_NE(0, memcmp(p, CONTENTS, bufsize));
+ //ASSERT_EQ(1, ReadSigbus::s_signaled);
+
+ 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 +680,77 @@
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(Read, mmap_getblksz_fail)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ const char *CONTENTS = "abcdefgh";
+ 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);
+
+ /*
+ * Actually accessing the mapped page would SIGBUS, which would break
+ * googletest's TearDown. But mlock will return ENOMEM if the memory
+ * access would've SIGBUSsed
+ */
+ ASSERT_NE(0, mlock(p, bufsize));
+ ASSERT_EQ(errno, ENOMEM);
+
+ 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
Wed, Aug 12, 10:58 PM (7 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36583716
Default Alt Text
D31994.id95266.diff (4 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