Page MenuHomeFreeBSD

D19752.id55595.diff
No OneTemporary

D19752.id55595.diff

Index: etc/mtree/BSD.tests.dist
===================================================================
--- etc/mtree/BSD.tests.dist
+++ etc/mtree/BSD.tests.dist
@@ -713,6 +713,8 @@
file
..
fs
+ fusefs
+ ..
tmpfs
..
..
Index: sys/fs/fuse/fuse_kernel.h
===================================================================
--- sys/fs/fuse/fuse_kernel.h
+++ sys/fs/fuse/fuse_kernel.h
@@ -194,6 +194,11 @@
struct fuse_attr attr;
};
+struct fuse_mknod_in {
+ __u32 mode;
+ __u32 rdev;
+};
+
struct fuse_mkdir_in {
__u32 mode;
__u32 padding;
Index: tests/sys/fs/Makefile
===================================================================
--- tests/sys/fs/Makefile
+++ tests/sys/fs/Makefile
@@ -7,6 +7,7 @@
TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs
#TESTS_SUBDIRS+= nullfs # XXX: needs rump
+TESTS_SUBDIRS+= fusefs
TESTS_SUBDIRS+= tmpfs
${PACKAGE}FILES+= h_funcs.subr
Index: tests/sys/fs/fusefs/Makefile
===================================================================
--- tests/sys/fs/fusefs/Makefile
+++ tests/sys/fs/fusefs/Makefile
@@ -8,6 +8,7 @@
# Kyua treats googletest programs as plain tests, it's better to separate them
# out, so we get more granular reporting.
GTESTS+= access
+GTESTS+= allow_other
GTESTS+= create
GTESTS+= default_permissions
GTESTS+= destroy
@@ -42,6 +43,11 @@
SRCS.access+= mockfs.cc
SRCS.access+= utils.cc
+SRCS.allow_other+= allow_other.cc
+SRCS.allow_other+= getmntopts.c
+SRCS.allow_other+= mockfs.cc
+SRCS.allow_other+= utils.cc
+
SRCS.create+= create.cc
SRCS.create+= getmntopts.c
SRCS.create+= mockfs.cc
@@ -194,10 +200,6 @@
CFLAGS+= -I${MOUNT}
.PATH: ${MOUNT}
CXXSTD= c++14
-
-# XXX Setting CXXFLAGS globally seems to be necessary to get mockfs.cc and
-# utils.cc to build correctly.
-CXXFLAGS+= ${GTESTS_CXXFLAGS}
LIBADD+= pthread
LIBADD+= gmock gtest
Index: tests/sys/fs/fusefs/access.cc
===================================================================
--- tests/sys/fs/fusefs/access.cc
+++ tests/sys/fs/fusefs/access.cc
@@ -40,18 +40,6 @@
class Access: public FuseTest {
public:
-void expect_access(uint64_t ino, mode_t access_mode, int error)
-{
- EXPECT_CALL(*m_mock, process(
- ResultOf([=](auto in) {
- return (in->header.opcode == FUSE_ACCESS &&
- in->header.nodeid == ino &&
- in->body.access.mask == access_mode);
- }, Eq(true)),
- _)
- ).WillOnce(Invoke(ReturnErrno(error)));
-}
-
void expect_lookup(const char *relpath, uint64_t ino)
{
FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1);
Index: tests/sys/fs/fusefs/allow_other.cc
===================================================================
--- /dev/null
+++ tests/sys/fs/fusefs/allow_other.cc
@@ -35,10 +35,11 @@
extern "C" {
#include <sys/types.h>
+#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pwd.h>
-#include <signal.h>
+#include <semaphore.h>
}
#include "mockfs.hh"
@@ -101,27 +102,39 @@
uint64_t ino = 42;
int fd;
pid_t child;
+ sem_t *sem;
+ int mprot = PROT_READ | PROT_WRITE;
+ int mflags = MAP_ANON | MAP_SHARED;
- signal(SIGUSR2, sighandler);
+ sem = (sem_t*)mmap(NULL, sizeof(*sem), mprot, mflags, -1, 0);
+ ASSERT_NE(MAP_FAILED, sem) << strerror(errno);
+ ASSERT_EQ(0, sem_init(sem, 1, 0)) << strerror(errno);
if ((child = fork()) == 0) {
/* In child */
- pause();
+ int err = 0;
+ ASSERT_EQ(0, sem_wait(sem)) << strerror(errno);
+
/* Drop privileges before accessing */
if (0 != setreuid(-1, m_uid)) {
perror("setreuid");
- _exit(1);
+ err = 1;
+ goto out;
}
fd = open(FULLPATH, O_RDONLY);
if (fd < 0) {
perror("open");
- _exit(1);
+ err = 1;
}
- _exit(0);
+out:
+ sem_destroy(sem);
+ _exit(err);
/* Deliberately leak fd */
} else if (child > 0) {
+ int child_status;
+
/*
* In parent. Cleanup must happen here, because it's still
* privileged.
@@ -134,14 +147,14 @@
expect_getattr(ino, 0);
m_mock->m_child_pid = child;
/* Signal the child process to go */
- kill(child, SIGUSR2);
- int child_status;
+ ASSERT_EQ(0, sem_post(sem)) << strerror(errno);
wait(&child_status);
ASSERT_EQ(0, WEXITSTATUS(child_status));
} else {
FAIL() << strerror(errno);
}
+ munmap(sem, sizeof(*sem));
}
TEST_F(NoAllowOther, disallowed)
@@ -149,29 +162,39 @@
const char FULLPATH[] = "mountpoint/some_file.txt";
int fd;
pid_t child;
-
- signal(SIGUSR2, sighandler);
+ sem_t *sem;
+ int mprot = PROT_READ | PROT_WRITE;
+ int mflags = MAP_ANON | MAP_SHARED;
+ sem = (sem_t*)mmap(NULL, sizeof(*sem), mprot, mflags, -1, 0);
+ ASSERT_NE(MAP_FAILED, sem) << strerror(errno);
+ ASSERT_EQ(0, sem_init(sem, 1, 0)) << strerror(errno);
+
if ((child = fork()) == 0) {
/* In child */
- pause();
+ int err = 0;
+ ASSERT_EQ(0, sem_wait(sem)) << strerror(errno);
+
/* Drop privileges before accessing */
if (0 != setreuid(-1, m_uid)) {
perror("setreuid");
- _exit(1);
+ err = 1;
+ goto out;
}
fd = open(FULLPATH, O_RDONLY);
if (fd >= 0) {
fprintf(stderr, "open should've failed\n");
- _exit(1);
+ err = 1;
} else if (errno != EPERM) {
fprintf(stderr,
"Unexpected error: %s\n", strerror(errno));
- _exit(1);
+ err = 1;
}
- _exit(0);
+out:
+ sem_destroy(sem);
+ _exit(0);
/* Deliberately leak fd */
} else if (child > 0) {
/*
@@ -180,7 +203,7 @@
*/
m_mock->m_child_pid = child;
/* Signal the child process to go */
- kill(child, SIGUSR2);
+ ASSERT_EQ(0, sem_post(sem)) << strerror(errno);
int child_status;
wait(&child_status);
@@ -188,4 +211,5 @@
} else {
FAIL() << strerror(errno);
}
+ munmap(sem, sizeof(*sem));
}
Index: tests/sys/fs/fusefs/default_permissions.cc
===================================================================
--- tests/sys/fs/fusefs/default_permissions.cc
+++ tests/sys/fs/fusefs/default_permissions.cc
@@ -84,7 +84,8 @@
ASSERT_EQ(EACCES, errno);
}
-TEST_F(Access, ok)
+/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236291 */
+TEST_F(Access, DISABLED_ok)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
@@ -92,10 +93,10 @@
mode_t access_mode = R_OK;
expect_lookup(RELPATH, ino, S_IFREG | 0644);
+ expect_access(ino, access_mode, 0);
/*
* Once default_permissions is properly implemented, there might be
- * another FUSE_GETATTR or something in here. But there should not be
- * a FUSE_ACCESS
+ * another FUSE_GETATTR or something in here.
*/
ASSERT_EQ(0, access(FULLPATH, access_mode)) << strerror(errno);
Index: tests/sys/fs/fusefs/mockfs.hh
===================================================================
--- tests/sys/fs/fusefs/mockfs.hh
+++ tests/sys/fs/fusefs/mockfs.hh
@@ -208,12 +208,16 @@
void read_request(mockfs_buf_in*);
public:
+ /* pid of child process, for two-process test cases */
+ pid_t m_child_pid;
+
/* Maximum size of a FUSE_WRITE write */
uint32_t m_max_write;
/* Create a new mockfs and mount it to a tempdir */
- MockFS(int max_readahead, bool push_symlinks_in,
- bool default_permissions, uint32_t flags);
+ MockFS(int max_readahead, bool allow_other,
+ bool default_permissions, bool push_symlinks_in,
+ uint32_t flags);
virtual ~MockFS();
/* Kill the filesystem daemon without unmounting the filesystem */
Index: tests/sys/fs/fusefs/mockfs.cc
===================================================================
--- tests/sys/fs/fusefs/mockfs.cc
+++ tests/sys/fs/fusefs/mockfs.cc
@@ -243,12 +243,13 @@
printf("\n");
}
-MockFS::MockFS(int max_readahead, bool push_symlinks_in,
- bool default_permissions, uint32_t flags)
+MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
+ bool push_symlinks_in, uint32_t flags)
{
struct iovec *iov = NULL;
int iovlen = 0;
char fdstr[15];
+ const bool trueval = true;
m_daemon_id = NULL;
m_maxreadahead = max_readahead;
@@ -262,33 +263,36 @@
* googletest doesn't allow ASSERT_ in constructors, so we must throw
* instead.
*/
- if (mkdir("mountpoint" , 0644) && errno != EEXIST)
+ if (mkdir("mountpoint" , 0755) && errno != EEXIST)
throw(std::system_error(errno, std::system_category(),
"Couldn't make mountpoint directory"));
- m_fuse_fd = open("/dev/fuse", O_RDWR);
+ m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR);
if (m_fuse_fd < 0)
throw(std::system_error(errno, std::system_category(),
"Couldn't open /dev/fuse"));
sprintf(fdstr, "%d", m_fuse_fd);
m_pid = getpid();
+ m_child_pid = -1;
build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
build_iovec(&iov, &iovlen, "fspath",
__DECONST(void *, "mountpoint"), -1);
build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
build_iovec(&iov, &iovlen, "fd", fdstr, -1);
- if (push_symlinks_in) {
- const bool trueval = true;
- build_iovec(&iov, &iovlen, "push_symlinks_in",
+ if (allow_other) {
+ build_iovec(&iov, &iovlen, "allow_other",
__DECONST(void*, &trueval), sizeof(bool));
}
if (default_permissions) {
- const bool trueval = true;
build_iovec(&iov, &iovlen, "default_permissions",
__DECONST(void*, &trueval), sizeof(bool));
}
+ if (push_symlinks_in) {
+ build_iovec(&iov, &iovlen, "push_symlinks_in",
+ __DECONST(void*, &trueval), sizeof(bool));
+ }
if (nmount(iov, iovlen, 0))
throw(std::system_error(errno, std::system_category(),
"Couldn't mount filesystem"));
@@ -396,6 +400,8 @@
bool MockFS::pid_ok(pid_t pid) {
if (pid == m_pid) {
+ return (true);
+ } else if (pid == m_child_pid) {
return (true);
} else {
struct kinfo_proc *ki;
Index: tests/sys/fs/fusefs/utils.hh
===================================================================
--- tests/sys/fs/fusefs/utils.hh
+++ tests/sys/fs/fusefs/utils.hh
@@ -41,6 +41,7 @@
protected:
uint32_t m_maxreadahead;
uint32_t m_init_flags;
+ bool m_allow_other;
bool m_default_permissions;
bool m_push_symlinks_in;
MockFS *m_mock = NULL;
@@ -56,6 +57,7 @@
*/
m_maxreadahead(UINT_MAX),
m_init_flags(0),
+ m_allow_other(false),
m_default_permissions(false),
m_push_symlinks_in(false)
{}
@@ -66,6 +68,12 @@
if (m_mock)
delete m_mock;
}
+
+ /*
+ * Create an expectation that FUSE_ACCESS will be called oncde for the
+ * given inode with the given access_mode, returning the given errno
+ */
+ void expect_access(uint64_t ino, mode_t access_mode, int error);
/*
* Create an expectation that FUSE_GETATTR will be called for the given
Index: tests/sys/fs/fusefs/utils.cc
===================================================================
--- tests/sys/fs/fusefs/utils.cc
+++ tests/sys/fs/fusefs/utils.cc
@@ -43,15 +43,10 @@
/* Check that fusefs(4) is accessible and the current user can mount(2) */
void check_environment()
{
- const char *mod_name = "fusefs";
const char *devnode = "/dev/fuse";
const char *usermount_node = "vfs.usermount";
int usermount_val = 0;
size_t usermount_size = sizeof(usermount_val);
- if (modfind(mod_name) == -1) {
- GTEST_SKIP() << "Module " << mod_name <<
- " could not be resolved";
- }
if (eaccess(devnode, R_OK | W_OK)) {
if (errno == ENOENT) {
GTEST_SKIP() << devnode << " does not exist";
@@ -91,11 +86,25 @@
m_maxbcachebuf = val;
try {
- m_mock = new MockFS(m_maxreadahead, m_push_symlinks_in,
- m_default_permissions, m_init_flags);
+ m_mock = new MockFS(m_maxreadahead, m_allow_other,
+ m_default_permissions, m_push_symlinks_in,
+ m_init_flags);
} catch (std::system_error err) {
FAIL() << err.what();
}
+}
+
+void
+FuseTest::expect_access(uint64_t ino, mode_t access_mode, int error)
+{
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in->header.opcode == FUSE_ACCESS &&
+ in->header.nodeid == ino &&
+ in->body.access.mask == access_mode);
+ }, Eq(true)),
+ _)
+ ).WillOnce(Invoke(ReturnErrno(error)));
}
void FuseTest::expect_getattr(uint64_t ino, uint64_t size)

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 19, 7:28 PM (13 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31792898
Default Alt Text
D19752.id55595.diff (11 KB)

Event Timeline