From a639731ba9d38108bb8b061db42d6694c64bcb37 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 3 Jun 2019 23:24:07 +0000 Subject: [PATCH] fusefs: respect RLIMIT_FSIZE Sponsored by: The FreeBSD Foundation --- sys/fs/fuse/fuse_io.c | 6 ++++ tests/sys/fs/fusefs/write.cc | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c index e76ec80584f4..d760a93146ba 100644 --- a/sys/fs/fuse/fuse_io.c +++ b/sys/fs/fuse/fuse_io.c @@ -447,6 +447,9 @@ fuse_write_directbackend(struct vnode *vp, struct uio *uio, if (ioflag & IO_APPEND) uio_setoffset(uio, filesize); + if (vn_rlimit_fsize(vp, uio, uio->uio_td)) + return (EFBIG); + fdisp_init(&fdi, 0); while (uio->uio_resid > 0) { @@ -579,6 +582,9 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio, if (ioflag & IO_APPEND) uio_setoffset(uio, filesize); + if (vn_rlimit_fsize(vp, uio, uio->uio_td)) + return (EFBIG); + /* * Find all of this file's B_NEEDCOMMIT buffers. If our writes * would exceed the local maximum per-file write commit size when diff --git a/tests/sys/fs/fusefs/write.cc b/tests/sys/fs/fusefs/write.cc index 95ad364edf94..242f442c6a9a 100644 --- a/tests/sys/fs/fusefs/write.cc +++ b/tests/sys/fs/fusefs/write.cc @@ -31,12 +31,15 @@ extern "C" { #include #include +#include #include #include +#include #include #include #include +#include #include } @@ -48,6 +51,22 @@ using namespace testing; class Write: public FuseTest { public: +static sig_atomic_t s_sigxfsz; + +void SetUp() { + s_sigxfsz = 0; + FuseTest::SetUp(); +} + +void TearDown() { + struct sigaction sa; + + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGXFSZ, &sa, NULL); + + FuseTest::TearDown(); +} void expect_lookup(const char *relpath, uint64_t ino, uint64_t size) { @@ -73,6 +92,8 @@ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, }; +sig_atomic_t Write::s_sigxfsz = 0; + class Write_7_8: public FuseTest { public: @@ -158,6 +179,10 @@ void expect_write(uint64_t ino, uint64_t offset, uint64_t isize, } }; +void sigxfsz_handler(int __unused sig) { + Write::s_sigxfsz = 1; +} + /* AIO writes need to set the header's pid field correctly */ /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236379 */ TEST_F(AioWrite, DISABLED_aio_write) @@ -372,6 +397,36 @@ TEST_F(Write, direct_io_short_write_iov) /* Deliberately leak fd. close(2) will be tested in release.cc */ } +/* fusefs should respect RLIMIT_FSIZE */ +TEST_F(Write, rlimit_fsize) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const char *CONTENTS = "abcdefgh"; + struct rlimit rl; + ssize_t bufsize = strlen(CONTENTS); + off_t offset = 1'000'000'000; + uint64_t ino = 42; + int fd; + + expect_lookup(RELPATH, ino, 0); + expect_open(ino, 0, 1); + + rl.rlim_cur = offset; + rl.rlim_max = 10 * offset; + ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rl)) << strerror(errno); + ASSERT_NE(SIG_ERR, signal(SIGXFSZ, sigxfsz_handler)) << strerror(errno); + + fd = open(FULLPATH, O_WRONLY); + + EXPECT_LE(0, fd) << strerror(errno); + + ASSERT_EQ(-1, pwrite(fd, CONTENTS, bufsize, offset)); + EXPECT_EQ(EFBIG, errno); + EXPECT_EQ(1, s_sigxfsz); + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + /* * If the kernel cannot be sure which uid, gid, or pid was responsible for a * write, then it must set the FUSE_WRITE_CACHE bit