fusefs: add another regression test for bug 236844

This test shows how bug 236844 can lead to a privilege escalation when used
with the -o allow_other mount option.

PR:		236844
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-03-30 17:24:11 +00:00
parent 5fccbf313a
commit 208070583f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=345736

View File

@ -93,6 +93,73 @@ TEST_F(AllowOther, allowed)
);
}
/*
* A variation of the Open.multiple_creds test showing how the bug can lead to a
* privilege elevation. The first process is privileged and opens a file only
* visible to root. The second process is unprivileged and shouldn't be able
* to open the file, but does thanks to the bug
*/
/* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236844 */
TEST_F(AllowOther, DISABLED_privilege_escalation)
{
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 fh = 100;
/* Fork a child to open the file with different credentials */
fork(true, [&] {
expect_lookup(RELPATH, ino, S_IFREG | 0600, 0, 2);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in->header.opcode == FUSE_OPEN &&
in->header.pid == (uint32_t)getpid() &&
in->header.uid == (uint32_t)geteuid() &&
in->header.nodeid == ino);
}, Eq(true)),
_)
).WillOnce(Invoke(
ReturnImmediate([](auto in __unused, auto out) {
out->body.open.fh = fh;
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.uid != (uint32_t)geteuid() &&
in->header.nodeid == ino);
}, Eq(true)),
_)
).Times(AnyNumber())
.WillRepeatedly(Invoke(ReturnErrno(EPERM)));
expect_getattr(ino, 0);
fd1 = open(FULLPATH, O_RDONLY);
EXPECT_LE(0, fd1) << strerror(errno);
}, [] {
int fd0;
fd0 = open(FULLPATH, O_RDONLY);
if (fd0 >= 0) {
fprintf(stderr, "Privilege escalation!\n");
return 1;
}
if (errno != EPERM) {
fprintf(stderr, "Unexpected error %s\n",
strerror(errno));
return 1;
}
return 0;
}
);
/* Deliberately leak fd1. close(2) will be tested in release.cc */
}
TEST_F(NoAllowOther, disallowed)
{
fork(true, [] {