Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153041834
D19752.id55595.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D19752.id55595.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D19752: fusefs: add a test suite
Attached
Detach File
Event Timeline
Log In to Comment