Date: Tue, 03 Sep 2019 14:06:06 -0000 From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r345768 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs Message-ID: <201904011636.x31Ga3Rv014748@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Mon Apr 1 16:36:02 2019 New Revision: 345768 URL: https://svnweb.freebsd.org/changeset/base/345768 Log: fusefs: allow opening files O_EXEC O_EXEC is useful for fexecve(2) and fchdir(2). Treat it as another fufh type alongside the existing RDONLY, WRONLY, and RDWR. Prior to r345742 this would've caused a memory and performance penalty. PR: 236329 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_file.c projects/fuse2/sys/fs/fuse/fuse_file.h projects/fuse2/sys/fs/fuse/fuse_vnops.c projects/fuse2/tests/sys/fs/fusefs/mockfs.cc projects/fuse2/tests/sys/fs/fusefs/open.cc projects/fuse2/tests/sys/fs/fusefs/opendir.cc projects/fuse2/tests/sys/fs/fusefs/readdir.cc projects/fuse2/tests/sys/fs/fusefs/releasedir.cc projects/fuse2/tests/sys/fs/fusefs/utils.cc Modified: projects/fuse2/sys/fs/fuse/fuse_file.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_file.c Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/sys/fs/fuse/fuse_file.c Mon Apr 1 16:36:02 2019 (r345768) @@ -121,12 +121,8 @@ fuse_filehandle_open(struct vnode *vp, fufh_type_t fuf if (vnode_isdir(vp)) { op = FUSE_OPENDIR; - if (fufh_type != FUFH_RDONLY) { - SDT_PROBE2(fuse, , file, trace, 1, - "non-rdonly fh requested for a directory?"); - printf("FUSE:non-rdonly fh requested for a directory?\n"); - fufh_type = FUFH_RDONLY; - } + /* vn_open_vnode already rejects FWRITE on directories */ + MPASS(fufh_type == FUFH_RDONLY || fufh_type == FUFH_EXEC); } fdisp_init(&fdi, sizeof(*foi)); fdisp_make_vp(&fdi, op, vp, td, cred); Modified: projects/fuse2/sys/fs/fuse/fuse_file.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_file.h Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/sys/fs/fuse/fuse_file.h Mon Apr 1 16:36:02 2019 (r345768) @@ -72,14 +72,11 @@ */ typedef enum fufh_type { FUFH_INVALID = -1, - FUFH_RDONLY = 0, - FUFH_WRONLY = 1, - FUFH_RDWR = 2, - /* TODO: add FUFH_EXEC */ + FUFH_RDONLY = O_RDONLY, + FUFH_WRONLY = O_WRONLY, + FUFH_RDWR = O_RDWR, + FUFH_EXEC = O_EXEC, } fufh_type_t; -_Static_assert(FUFH_RDONLY == O_RDONLY, "RDONLY"); -_Static_assert(FUFH_WRONLY == O_WRONLY, "WRONLY"); -_Static_assert(FUFH_RDWR == O_RDWR, "RDWR"); struct fuse_filehandle { LIST_ENTRY(fuse_filehandle) next; @@ -110,6 +107,8 @@ fuse_filehandle_xlate_from_fflags(int fflags) return FUFH_WRONLY; else if (fflags & (FREAD)) return FUFH_RDONLY; + else if (fflags & (FEXEC)) + return FUFH_EXEC; else panic("FUSE: What kind of a flag is this (%x)?", fflags); } @@ -123,6 +122,7 @@ fuse_filehandle_xlate_to_oflags(fufh_type_t type) case FUFH_RDONLY: case FUFH_WRONLY: case FUFH_RDWR: + case FUFH_EXEC: oflags = type; break; default: Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vnops.c Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Mon Apr 1 16:36:02 2019 (r345768) @@ -285,7 +285,8 @@ fuse_vnop_close(struct vop_close_args *ap) if (vnode_isdir(vp)) { struct fuse_filehandle *fufh; - if (fuse_filehandle_get(vp, O_RDONLY, &fufh) == 0) + if ((fuse_filehandle_get(vp, O_RDONLY, &fufh) == 0) || + (fuse_filehandle_get(vp, O_EXEC, &fufh) == 0)) fuse_filehandle_close(vp, fufh, NULL, cred); return 0; } @@ -1201,16 +1202,12 @@ fuse_vnop_open(struct vop_open_args *ap) return ENXIO; if (vp->v_type == VCHR || vp->v_type == VBLK || vp->v_type == VFIFO) return (EOPNOTSUPP); - if ((mode & (FREAD | FWRITE)) == 0) + if ((mode & (FREAD | FWRITE | FEXEC)) == 0) return EINVAL; fvdat = VTOFUD(vp); - if (vnode_isdir(vp)) { - fufh_type = FUFH_RDONLY; - } else { - fufh_type = fuse_filehandle_xlate_from_fflags(mode); - } + fufh_type = fuse_filehandle_xlate_from_fflags(mode); if (fuse_filehandle_validrw(vp, fufh_type) != FUFH_INVALID) { fuse_vnode_open(vp, 0, td); @@ -1303,7 +1300,7 @@ fuse_vnop_readdir(struct vop_readdir_args *ap) return EINVAL; } - if ((err = fuse_filehandle_get(vp, O_RDONLY, &fufh)) != 0) { + if ((err = fuse_filehandle_get(vp, FUFH_RDONLY, &fufh)) != 0) { SDT_PROBE2(fuse, , vnops, trace, 1, "calling readdir() before open()"); err = fuse_filehandle_open(vp, O_RDONLY, &fufh, NULL, cred); Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -200,7 +200,8 @@ void debug_fuseop(const mockfs_buf_in *in) in->body.read.size); break; case FUSE_READDIR: - printf(" offset=%lu size=%u", in->body.readdir.offset, + printf(" fh=%#lx offset=%lu size=%u", + in->body.readdir.fh, in->body.readdir.offset, in->body.readdir.size); break; case FUSE_RELEASE: Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/open.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/open.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -250,8 +250,7 @@ TEST_F(Open, o_excl) test_ok(O_WRONLY | O_EXCL, O_WRONLY); } -/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236329 */ -TEST_F(Open, DISABLED_o_exec) +TEST_F(Open, o_exec) { test_ok(O_EXEC, O_EXEC); } Modified: projects/fuse2/tests/sys/fs/fusefs/opendir.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/opendir.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/opendir.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -44,6 +44,29 @@ void expect_lookup(const char *relpath, uint64_t ino) { FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 0, 1); } + +void expect_opendir(uint64_t ino, uint32_t flags, ProcessMockerT r) +{ + /* opendir(3) calls fstatfs */ + EXPECT_CALL(*m_mock, process( + ResultOf([](auto in) { + return (in->header.opcode == FUSE_STATFS); + }, Eq(true)), + _) + ).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) { + SET_OUT_HEADER_LEN(out, statfs); + }))); + + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_OPENDIR && + in->header.nodeid == ino && + in->body.opendir.flags == flags); + }, Eq(true)), + _) + ).WillOnce(Invoke(r)); +} + }; @@ -59,14 +82,8 @@ TEST_F(Opendir, enoent) uint64_t ino = 42; expect_lookup(RELPATH, ino); + expect_opendir(ino, O_RDONLY, ReturnErrno(ENOENT)); - EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { - return (in->header.opcode == FUSE_OPENDIR && - in->header.nodeid == ino); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnErrno(ENOENT))); EXPECT_NE(0, open(FULLPATH, O_DIRECTORY)); EXPECT_EQ(ENOENT, errno); } @@ -82,15 +99,8 @@ TEST_F(Opendir, eperm) uint64_t ino = 42; expect_lookup(RELPATH, ino); + expect_opendir(ino, O_RDONLY, ReturnErrno(EPERM)); - EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { - return (in->header.opcode == FUSE_OPENDIR && - in->header.nodeid == ino); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnErrno(EPERM))); - EXPECT_NE(0, open(FULLPATH, O_DIRECTORY)); EXPECT_EQ(EPERM, errno); } @@ -102,45 +112,43 @@ TEST_F(Opendir, open) uint64_t ino = 42; expect_lookup(RELPATH, ino); - - EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { - return (in->header.opcode == FUSE_OPENDIR && - in->header.nodeid == ino); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { + expect_opendir(ino, O_RDONLY, + ReturnImmediate([=](auto in __unused, auto out) { SET_OUT_HEADER_LEN(out, open); - }))); + })); EXPECT_LE(0, open(FULLPATH, O_DIRECTORY)) << strerror(errno); } -TEST_F(Opendir, opendir) +/* Directories can be opened O_EXEC for stuff like fchdir(2) */ +TEST_F(Opendir, open_exec) { const char FULLPATH[] = "mountpoint/some_dir"; const char RELPATH[] = "some_dir"; uint64_t ino = 42; + int fd; expect_lookup(RELPATH, ino); - EXPECT_CALL(*m_mock, process( - ResultOf([](auto in) { - return (in->header.opcode == FUSE_STATFS); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { - SET_OUT_HEADER_LEN(out, statfs); - }))); + expect_opendir(ino, O_EXEC, + ReturnImmediate([=](auto in __unused, auto out) { + SET_OUT_HEADER_LEN(out, open); + })); - EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { - return (in->header.opcode == FUSE_OPENDIR && - in->header.nodeid == ino); - }, Eq(true)), - _) - ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { + fd = open(FULLPATH, O_EXEC | O_DIRECTORY); + ASSERT_LE(0, fd) << strerror(errno); +} + +TEST_F(Opendir, opendir) +{ + const char FULLPATH[] = "mountpoint/some_dir"; + const char RELPATH[] = "some_dir"; + uint64_t ino = 42; + + expect_lookup(RELPATH, ino); + expect_opendir(ino, O_RDONLY, + ReturnImmediate([=](auto in __unused, auto out) { SET_OUT_HEADER_LEN(out, open); - }))); + })); errno = 0; EXPECT_NE(NULL, opendir(FULLPATH)) << strerror(errno); Modified: projects/fuse2/tests/sys/fs/fusefs/readdir.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/readdir.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/readdir.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -52,6 +52,7 @@ void expect_readdir(uint64_t ino, uint64_t off, vector ResultOf([=](auto in) { return (in->header.opcode == FUSE_READDIR && in->header.nodeid == ino && + in->body.readdir.fh == FH && in->body.readdir.offset == off); }, Eq(true)), _) Modified: projects/fuse2/tests/sys/fs/fusefs/releasedir.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/releasedir.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/releasedir.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -30,6 +30,7 @@ extern "C" { #include <dirent.h> +#include <fcntl.h> } #include "mockfs.hh" @@ -106,4 +107,22 @@ TEST_F(ReleaseDir, ok) ASSERT_NE(NULL, dir) << strerror(errno); ASSERT_EQ(0, closedir(dir)) << strerror(errno); +} + +/* Directories opened O_EXEC should be properly released, too */ +TEST_F(ReleaseDir, o_exec) +{ + const char FULLPATH[] = "mountpoint/some_dir"; + const char RELPATH[] = "some_dir"; + uint64_t ino = 42; + int fd; + + expect_lookup(RELPATH, ino); + expect_opendir(ino); + expect_releasedir(ino, ReturnErrno(0)); + + fd = open(FULLPATH, O_EXEC | O_DIRECTORY); + EXPECT_LE(0, fd) << strerror(errno); + + ASSERT_EQ(0, close(fd)) << strerror(errno); } Modified: projects/fuse2/tests/sys/fs/fusefs/utils.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon Apr 1 16:15:29 2019 (r345767) +++ projects/fuse2/tests/sys/fs/fusefs/utils.cc Mon Apr 1 16:36:02 2019 (r345768) @@ -166,6 +166,7 @@ void FuseTest::expect_open(uint64_t ino, uint32_t flag void FuseTest::expect_opendir(uint64_t ino) { + /* opendir(3) calls fstatfs */ EXPECT_CALL(*m_mock, process( ResultOf([](auto in) { return (in->header.opcode == FUSE_STATFS);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904011636.x31Ga3Rv014748>