fusefs: add a regression test for bug 236844

fusefs should send a FUSE_OPEN for every open(2) so the daemon can validate
accesses.

PR:		236844
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-03-28 03:30:04 +00:00
parent 09c01e67de
commit 42d50d16e2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=345626
6 changed files with 75 additions and 18 deletions

View File

@ -78,7 +78,7 @@ TEST_F(AllowOther, allowed)
expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
expect_open(ino, 0, 1);
expect_release(ino);
expect_release(ino, FH);
expect_getattr(ino, 0);
}, []() {
int fd;

View File

@ -139,7 +139,7 @@ TEST_F(Fsync, close)
}, Eq(true)),
_)
).Times(0);
expect_release(ino);
expect_release(ino, FH);
fd = open(FULLPATH, O_RDWR);
ASSERT_LE(0, fd) << strerror(errno);

View File

@ -204,7 +204,8 @@ void debug_fuseop(const mockfs_buf_in *in)
in->body.readdir.size);
break;
case FUSE_RELEASE:
printf(" flags=%#x lock_owner=%lu",
printf(" fh=%#lx flags=%#x lock_owner=%lu",
in->body.release.fh,
in->body.release.flags,
in->body.release.lock_owner);
break;

View File

@ -62,17 +62,7 @@ void test_ok(int os_flags, int fuse_flags) {
})));
/* Until the attr cache is working, we may send an additional GETATTR */
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_GETATTR &&
in->header.nodeid == ino);
}, Eq(true)),
_)
).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
SET_OUT_HEADER_LEN(out, attr);
out->body.attr.attr.ino = ino; // Must match nodeid
out->body.attr.attr.mode = S_IFREG | 0644;
})));
expect_getattr(ino, 0);
fd = open(FULLPATH, os_flags);
EXPECT_LE(0, fd) << strerror(errno);
@ -170,6 +160,72 @@ TEST_F(Open, fifo)
EXPECT_EQ(EOPNOTSUPP, errno);
}
/*
* fusefs must issue multiple FUSE_OPEN operations if clients with different
* credentials open the same file, even if they use the same mode. This is
* necessary so that the daemon can validate each set of credentials.
*/
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236844 */
TEST_F(Open, DISABLED_multiple_creds)
{
const static char FULLPATH[] = "mountpoint/some_file.txt";
const static char RELPATH[] = "some_file.txt";
int fd1;
const static uint64_t ino = 42;
const static uint64_t fh0 = 100, fh1 = 200;
/* Fork a child to open the file with different credentials */
fork(false, [&] {
expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 2);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_OPEN &&
in->header.pid == (uint32_t)getpid() &&
in->header.nodeid == ino);
}, Eq(true)),
_)
).WillOnce(Invoke(
ReturnImmediate([](auto in __unused, auto out) {
out->body.open.fh = fh0;
out->header.len = sizeof(out->header);
SET_OUT_HEADER_LEN(out, open);
})));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_OPEN &&
in->header.pid != (uint32_t)getpid() &&
in->header.nodeid == ino);
}, Eq(true)),
_)
).WillOnce(Invoke(
ReturnImmediate([](auto in __unused, auto out) {
out->body.open.fh = fh1;
out->header.len = sizeof(out->header);
SET_OUT_HEADER_LEN(out, open);
})));
expect_getattr(ino, 0);
expect_release(ino, fh0);
expect_release(ino, fh1);
fd1 = open(FULLPATH, O_RDONLY);
EXPECT_LE(0, fd1) << strerror(errno);
}, [] {
int fd0;
fd0 = open(FULLPATH, O_RDONLY);
if (fd0 < 0) {
perror("open");
return(1);
}
return 0;
}
);
close(fd1);
}
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236340 */
TEST_F(Open, DISABLED_o_append)
{

View File

@ -206,13 +206,13 @@ void FuseTest::expect_read(uint64_t ino, uint64_t offset, uint64_t isize,
}))).RetiresOnSaturation();
}
void FuseTest::expect_release(uint64_t ino)
void FuseTest::expect_release(uint64_t ino, uint64_t fh)
{
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_RELEASE &&
in->header.nodeid == ino &&
in->body.release.fh == FH);
in->body.release.fh == fh);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(0)));

View File

@ -113,9 +113,9 @@ class FuseTest : public ::testing::Test {
/*
* Create an expectation that FUSE_RELEASE will be called exactly once
* for the given inode, returning success
* for the given inode and filehandle, returning success
*/
void expect_release(uint64_t ino);
void expect_release(uint64_t ino, uint64_t fh);
/*
* Create an expectation that FUSE_WRITE will be called exactly once