summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/BUILD4
-rw-r--r--test/syscalls/linux/32bit.cc4
-rw-r--r--test/syscalls/linux/BUILD20
-rw-r--r--test/syscalls/linux/cgroup.cc52
-rw-r--r--test/syscalls/linux/chdir.cc4
-rw-r--r--test/syscalls/linux/chmod.cc34
-rw-r--r--test/syscalls/linux/chown.cc8
-rw-r--r--test/syscalls/linux/epoll.cc53
-rw-r--r--test/syscalls/linux/fchdir.cc4
-rw-r--r--test/syscalls/linux/fcntl.cc4
-rw-r--r--test/syscalls/linux/flock.cc4
-rw-r--r--test/syscalls/linux/memory_accounting.cc4
-rw-r--r--test/syscalls/linux/mkdir.cc8
-rw-r--r--test/syscalls/linux/mlock.cc24
-rw-r--r--test/syscalls/linux/mount.cc7
-rw-r--r--test/syscalls/linux/open.cc10
-rw-r--r--test/syscalls/linux/open_create.cc15
-rw-r--r--test/syscalls/linux/prctl.cc6
-rw-r--r--test/syscalls/linux/proc.cc23
-rw-r--r--test/syscalls/linux/ptrace.cc28
-rw-r--r--test/syscalls/linux/pty.cc11
-rw-r--r--test/syscalls/linux/raw_socket_hdrincl.cc6
-rw-r--r--test/syscalls/linux/rename.cc16
-rw-r--r--test/syscalls/linux/rlimits.cc4
-rw-r--r--test/syscalls/linux/semaphore.cc12
-rw-r--r--test/syscalls/linux/socket_capability.cc2
-rw-r--r--test/syscalls/linux/socket_ip_tcp_generic.cc2
-rw-r--r--test/syscalls/linux/sticky.cc8
-rw-r--r--test/syscalls/linux/symlink.cc12
-rw-r--r--test/syscalls/linux/tcp_socket.cc8
-rw-r--r--test/syscalls/linux/truncate.cc4
-rw-r--r--test/syscalls/linux/tuntap.cc15
-rw-r--r--test/syscalls/linux/uname.cc4
-rw-r--r--test/syscalls/linux/unlink.cc8
-rw-r--r--test/syscalls/linux/utimes.cc3
-rw-r--r--test/syscalls/linux/verity_ioctl.cc103
-rw-r--r--test/syscalls/linux/verity_mmap.cc158
-rw-r--r--test/syscalls/linux/xattr.cc14
38 files changed, 439 insertions, 267 deletions
diff --git a/test/syscalls/BUILD b/test/syscalls/BUILD
index 0435f61a2..85412f54b 100644
--- a/test/syscalls/BUILD
+++ b/test/syscalls/BUILD
@@ -313,6 +313,10 @@ syscall_test(
)
syscall_test(
+ test = "//test/syscalls/linux:verity_mmap_test",
+)
+
+syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:mount_test",
)
diff --git a/test/syscalls/linux/32bit.cc b/test/syscalls/linux/32bit.cc
index 6080a59b7..cbf1b4f05 100644
--- a/test/syscalls/linux/32bit.cc
+++ b/test/syscalls/linux/32bit.cc
@@ -240,9 +240,9 @@ TEST(Call32Bit, Disallowed) {
}
}
-} // namespace
-
#endif
+} // namespace
+
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 1ff001426..c7d0f9036 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -1024,6 +1024,7 @@ cc_binary(
"//test/util:temp_path",
"//test/util:test_main",
"//test/util:test_util",
+ "//test/util:verity_util",
],
)
@@ -1294,6 +1295,23 @@ cc_binary(
)
cc_binary(
+ name = "verity_mmap_test",
+ testonly = 1,
+ srcs = ["verity_mmap.cc"],
+ linkstatic = 1,
+ deps = [
+ "//test/util:capability_util",
+ gtest,
+ "//test/util:fs_util",
+ "//test/util:memory_util",
+ "//test/util:temp_path",
+ "//test/util:test_main",
+ "//test/util:test_util",
+ "//test/util:verity_util",
+ ],
+)
+
+cc_binary(
name = "mount_test",
testonly = 1,
srcs = ["mount.cc"],
@@ -4248,10 +4266,12 @@ cc_binary(
"//test/util:mount_util",
"@com_google_absl//absl/strings",
gtest,
+ "//test/util:cleanup",
"//test/util:posix_error",
"//test/util:temp_path",
"//test/util:test_main",
"//test/util:test_util",
+ "//test/util:thread_util",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
],
diff --git a/test/syscalls/linux/cgroup.cc b/test/syscalls/linux/cgroup.cc
index 70ad5868f..a009ade7e 100644
--- a/test/syscalls/linux/cgroup.cc
+++ b/test/syscalls/linux/cgroup.cc
@@ -25,9 +25,11 @@
#include "absl/strings/str_split.h"
#include "test/util/capability_util.h"
#include "test/util/cgroup_util.h"
+#include "test/util/cleanup.h"
#include "test/util/mount_util.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
+#include "test/util/thread_util.h"
namespace gvisor {
namespace testing {
@@ -192,6 +194,56 @@ TEST(Cgroup, MoptAllMustBeExclusive) {
SyscallFailsWithErrno(EINVAL));
}
+TEST(Cgroup, MountRace) {
+ SKIP_IF(!CgroupsAvailable());
+
+ TempPath mountpoint = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+
+ const DisableSave ds; // Too many syscalls.
+
+ auto mount_thread = [&mountpoint]() {
+ for (int i = 0; i < 100; ++i) {
+ mount("none", mountpoint.path().c_str(), "cgroup", 0, 0);
+ }
+ };
+ std::list<ScopedThread> threads;
+ for (int i = 0; i < 10; ++i) {
+ threads.emplace_back(mount_thread);
+ }
+ for (auto& t : threads) {
+ t.Join();
+ }
+
+ auto cleanup = Cleanup([&mountpoint] {
+ // We need 1 umount call per successful mount. If some of the mount calls
+ // were unsuccessful, their corresponding umount will silently fail.
+ for (int i = 0; i < (10 * 100) + 1; ++i) {
+ umount(mountpoint.path().c_str());
+ }
+ });
+
+ Cgroup c = Cgroup(mountpoint.path());
+ // c should be a valid cgroup.
+ EXPECT_NO_ERRNO(c.ContainsCallingProcess());
+}
+
+TEST(Cgroup, UnmountRepeated) {
+ SKIP_IF(!CgroupsAvailable());
+
+ const DisableSave ds; // Too many syscalls.
+
+ Mounter m(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()));
+ Cgroup c = ASSERT_NO_ERRNO_AND_VALUE(m.MountCgroupfs(""));
+
+ // First unmount should succeed.
+ EXPECT_THAT(umount(c.Path().c_str()), SyscallSucceeds());
+
+ // We just manually unmounted, so release managed resources.
+ m.release(c);
+
+ EXPECT_THAT(umount(c.Path().c_str()), SyscallFailsWithErrno(EINVAL));
+}
+
TEST(MemoryCgroup, MemoryUsageInBytes) {
SKIP_IF(!CgroupsAvailable());
diff --git a/test/syscalls/linux/chdir.cc b/test/syscalls/linux/chdir.cc
index 3182c228b..3c64b9eab 100644
--- a/test/syscalls/linux/chdir.cc
+++ b/test/syscalls/linux/chdir.cc
@@ -41,8 +41,8 @@ TEST(ChdirTest, Success) {
TEST(ChdirTest, PermissionDenied) {
// Drop capabilities that allow us to override directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto temp_dir = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0666 /* mode */));
diff --git a/test/syscalls/linux/chmod.cc b/test/syscalls/linux/chmod.cc
index 4a5ea84d4..dd82c5fb1 100644
--- a/test/syscalls/linux/chmod.cc
+++ b/test/syscalls/linux/chmod.cc
@@ -33,7 +33,7 @@ namespace {
TEST(ChmodTest, ChmodFileSucceeds) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
@@ -43,8 +43,8 @@ TEST(ChmodTest, ChmodFileSucceeds) {
TEST(ChmodTest, ChmodDirSucceeds) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
const std::string fileInDir = NewTempAbsPathInDir(dir.path());
@@ -55,7 +55,7 @@ TEST(ChmodTest, ChmodDirSucceeds) {
TEST(ChmodTest, FchmodFileSucceeds) {
// Drop capabilities that allow us to file directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666));
int fd;
@@ -72,8 +72,8 @@ TEST(ChmodTest, FchmodFileSucceeds) {
TEST(ChmodTest, FchmodDirSucceeds) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
int fd;
@@ -118,7 +118,7 @@ TEST(ChmodTest, FchmodDirWithOpath) {
TEST(ChmodTest, FchmodatWithOpath) {
SKIP_IF(IsRunningWithVFS1());
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
@@ -140,7 +140,7 @@ TEST(ChmodTest, FchmodatNotDir) {
TEST(ChmodTest, FchmodatFileAbsolutePath) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
@@ -150,8 +150,8 @@ TEST(ChmodTest, FchmodatFileAbsolutePath) {
TEST(ChmodTest, FchmodatDirAbsolutePath) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
@@ -167,7 +167,7 @@ TEST(ChmodTest, FchmodatDirAbsolutePath) {
TEST(ChmodTest, FchmodatFile) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
@@ -188,8 +188,8 @@ TEST(ChmodTest, FchmodatFile) {
TEST(ChmodTest, FchmodatDir) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
@@ -227,8 +227,8 @@ TEST(ChmodTest, ChmodDowngradeWritability) {
TEST(ChmodTest, ChmodFileToNoPermissionsSucceeds) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666));
@@ -254,8 +254,8 @@ TEST(ChmodTest, FchmodDowngradeWritability) {
TEST(ChmodTest, FchmodFileToNoPermissionsSucceeds) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0666));
diff --git a/test/syscalls/linux/chown.cc b/test/syscalls/linux/chown.cc
index ff0d39343..b0c1b6f4a 100644
--- a/test/syscalls/linux/chown.cc
+++ b/test/syscalls/linux/chown.cc
@@ -91,9 +91,7 @@ using Chown =
class ChownParamTest : public ::testing::TestWithParam<Chown> {};
TEST_P(ChownParamTest, ChownFileSucceeds) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_CHOWN))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_CHOWN, false));
- }
+ AutoCapability cap(CAP_CHOWN, false);
const auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
@@ -135,9 +133,7 @@ TEST_P(ChownParamTest, ChownFilePermissionDenied) {
// thread won't be able to open some log files after the test ends.
ScopedThread([&] {
// Drop privileges.
- if (HaveCapability(CAP_CHOWN).ValueOrDie()) {
- EXPECT_NO_ERRNO(SetCapability(CAP_CHOWN, false));
- }
+ AutoCapability cap(CAP_CHOWN, false);
// Change EUID and EGID.
//
diff --git a/test/syscalls/linux/epoll.cc b/test/syscalls/linux/epoll.cc
index b180f633c..af3d27894 100644
--- a/test/syscalls/linux/epoll.cc
+++ b/test/syscalls/linux/epoll.cc
@@ -39,6 +39,15 @@ namespace {
constexpr int kFDsPerEpoll = 3;
constexpr uint64_t kMagicConstant = 0x0102030405060708;
+#ifndef SYS_epoll_pwait2
+#define SYS_epoll_pwait2 441
+#endif
+
+int epoll_pwait2(int fd, struct epoll_event* events, int maxevents,
+ const struct timespec* timeout, const sigset_t* sigset) {
+ return syscall(SYS_epoll_pwait2, fd, events, maxevents, timeout, sigset);
+}
+
TEST(EpollTest, AllWritable) {
auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
std::vector<FileDescriptor> eventfds;
@@ -144,6 +153,50 @@ TEST(EpollTest, Timeout) {
EXPECT_GT(ms_elapsed(begin, end), kTimeoutMs - 1);
}
+TEST(EpollTest, EpollPwait2Timeout) {
+ auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
+ // 200 milliseconds.
+ constexpr int kTimeoutNs = 200000000;
+ struct timespec timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 0;
+ struct timespec begin;
+ struct timespec end;
+ struct epoll_event result[kFDsPerEpoll];
+
+ std::vector<FileDescriptor> eventfds;
+ for (int i = 0; i < kFDsPerEpoll; i++) {
+ eventfds.push_back(ASSERT_NO_ERRNO_AND_VALUE(NewEventFD()));
+ ASSERT_NO_ERRNO(RegisterEpollFD(epollfd.get(), eventfds[i].get(), EPOLLIN,
+ kMagicConstant + i));
+ }
+
+ // Pass valid arguments so that the syscall won't be blocked indefinitely
+ // nor return errno EINVAL.
+ //
+ // The syscall returns immediately when timeout is zero,
+ // even if no events are available.
+ SKIP_IF(!IsRunningOnGvisor() &&
+ epoll_pwait2(epollfd.get(), result, kFDsPerEpoll, &timeout, nullptr) <
+ 0 &&
+ errno == ENOSYS);
+
+ {
+ const DisableSave ds; // Timing-related.
+ EXPECT_THAT(clock_gettime(CLOCK_MONOTONIC, &begin), SyscallSucceeds());
+
+ timeout.tv_nsec = kTimeoutNs;
+ ASSERT_THAT(RetryEINTR(epoll_pwait2)(epollfd.get(), result, kFDsPerEpoll,
+ &timeout, nullptr),
+ SyscallSucceedsWithValue(0));
+ EXPECT_THAT(clock_gettime(CLOCK_MONOTONIC, &end), SyscallSucceeds());
+ }
+
+ // Check the lower bound on the timeout. Checking for an upper bound is
+ // fragile because Linux can overrun the timeout due to scheduling delays.
+ EXPECT_GT(ns_elapsed(begin, end), kTimeoutNs - 1);
+}
+
void* writer(void* arg) {
int fd = *reinterpret_cast<int*>(arg);
uint64_t tmp = 1;
diff --git a/test/syscalls/linux/fchdir.cc b/test/syscalls/linux/fchdir.cc
index c6675802d..0383f3f85 100644
--- a/test/syscalls/linux/fchdir.cc
+++ b/test/syscalls/linux/fchdir.cc
@@ -46,8 +46,8 @@ TEST(FchdirTest, InvalidFD) {
TEST(FchdirTest, PermissionDenied) {
// Drop capabilities that allow us to override directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto temp_dir = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0666 /* mode */));
diff --git a/test/syscalls/linux/fcntl.cc b/test/syscalls/linux/fcntl.cc
index 4fa6751ff..91526572b 100644
--- a/test/syscalls/linux/fcntl.cc
+++ b/test/syscalls/linux/fcntl.cc
@@ -390,9 +390,7 @@ TEST_F(FcntlLockTest, SetLockDir) {
}
TEST_F(FcntlLockTest, SetLockSymlink) {
- // TODO(gvisor.dev/issue/2782): Replace with IsRunningWithVFS1() when O_PATH
- // is supported.
- SKIP_IF(IsRunningOnGvisor());
+ SKIP_IF(IsRunningWithVFS1());
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
auto symlink = ASSERT_NO_ERRNO_AND_VALUE(
diff --git a/test/syscalls/linux/flock.cc b/test/syscalls/linux/flock.cc
index fd387aa45..10dad042f 100644
--- a/test/syscalls/linux/flock.cc
+++ b/test/syscalls/linux/flock.cc
@@ -662,9 +662,7 @@ TEST(FlockTestNoFixture, FlockDir) {
}
TEST(FlockTestNoFixture, FlockSymlink) {
- // TODO(gvisor.dev/issue/2782): Replace with IsRunningWithVFS1() when O_PATH
- // is supported.
- SKIP_IF(IsRunningOnGvisor());
+ SKIP_IF(IsRunningWithVFS1());
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
auto symlink = ASSERT_NO_ERRNO_AND_VALUE(
diff --git a/test/syscalls/linux/memory_accounting.cc b/test/syscalls/linux/memory_accounting.cc
index 94aea4077..867a4513b 100644
--- a/test/syscalls/linux/memory_accounting.cc
+++ b/test/syscalls/linux/memory_accounting.cc
@@ -83,7 +83,7 @@ TEST(MemoryAccounting, AnonAccountingPreservedOnSaveRestore) {
uint64_t anon_after_alloc = ASSERT_NO_ERRNO_AND_VALUE(AnonUsageFromMeminfo());
EXPECT_THAT(anon_after_alloc,
- EquivalentWithin(anon_initial + map_bytes, 0.03));
+ EquivalentWithin(anon_initial + map_bytes, 0.04));
// We have many implicit S/R cycles from scraping /proc/meminfo throughout the
// test, but throw an explicit S/R in here as well.
@@ -91,7 +91,7 @@ TEST(MemoryAccounting, AnonAccountingPreservedOnSaveRestore) {
// Usage should remain the same across S/R.
uint64_t anon_after_sr = ASSERT_NO_ERRNO_AND_VALUE(AnonUsageFromMeminfo());
- EXPECT_THAT(anon_after_sr, EquivalentWithin(anon_after_alloc, 0.03));
+ EXPECT_THAT(anon_after_sr, EquivalentWithin(anon_after_alloc, 0.04));
}
} // namespace
diff --git a/test/syscalls/linux/mkdir.cc b/test/syscalls/linux/mkdir.cc
index 11fbfa5c5..36504fe6d 100644
--- a/test/syscalls/linux/mkdir.cc
+++ b/test/syscalls/linux/mkdir.cc
@@ -72,8 +72,8 @@ TEST_F(MkdirTest, HonorsUmask2) {
TEST_F(MkdirTest, FailsOnDirWithoutWritePerms) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
ASSERT_THAT(mkdir(dirname_.c_str(), 0555), SyscallSucceeds());
auto dir = JoinPath(dirname_.c_str(), "foo");
@@ -84,8 +84,8 @@ TEST_F(MkdirTest, FailsOnDirWithoutWritePerms) {
TEST_F(MkdirTest, DirAlreadyExists) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
auto dir = JoinPath(dirname_.c_str(), "foo");
diff --git a/test/syscalls/linux/mlock.cc b/test/syscalls/linux/mlock.cc
index 78ac96bed..dfa5b7133 100644
--- a/test/syscalls/linux/mlock.cc
+++ b/test/syscalls/linux/mlock.cc
@@ -114,9 +114,7 @@ TEST(MlockTest, Fork) {
}
TEST(MlockTest, RlimitMemlockZero) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit =
ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_MEMLOCK, 0));
auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(
@@ -127,9 +125,7 @@ TEST(MlockTest, RlimitMemlockZero) {
}
TEST(MlockTest, RlimitMemlockInsufficient) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit =
ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_MEMLOCK, kPageSize));
auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(
@@ -255,9 +251,7 @@ TEST(MapLockedTest, Basic) {
}
TEST(MapLockedTest, RlimitMemlockZero) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit =
ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_MEMLOCK, 0));
EXPECT_THAT(
@@ -266,9 +260,7 @@ TEST(MapLockedTest, RlimitMemlockZero) {
}
TEST(MapLockedTest, RlimitMemlockInsufficient) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit =
ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_MEMLOCK, kPageSize));
EXPECT_THAT(
@@ -298,9 +290,7 @@ TEST(MremapLockedTest, RlimitMemlockZero) {
MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_LOCKED));
EXPECT_TRUE(IsPageMlocked(mapping.addr()));
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit =
ASSERT_NO_ERRNO_AND_VALUE(ScopedSetSoftRlimit(RLIMIT_MEMLOCK, 0));
void* addr = mremap(mapping.ptr(), mapping.len(), 2 * mapping.len(),
@@ -315,9 +305,7 @@ TEST(MremapLockedTest, RlimitMemlockInsufficient) {
MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_LOCKED));
EXPECT_TRUE(IsPageMlocked(mapping.addr()));
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_IPC_LOCK))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_LOCK, false));
- }
+ AutoCapability cap(CAP_IPC_LOCK, false);
Cleanup reset_rlimit = ASSERT_NO_ERRNO_AND_VALUE(
ScopedSetSoftRlimit(RLIMIT_MEMLOCK, mapping.len()));
void* addr = mremap(mapping.ptr(), mapping.len(), 2 * mapping.len(),
diff --git a/test/syscalls/linux/mount.cc b/test/syscalls/linux/mount.cc
index 92d0fb05c..3c7311782 100644
--- a/test/syscalls/linux/mount.cc
+++ b/test/syscalls/linux/mount.cc
@@ -45,6 +45,7 @@ namespace testing {
namespace {
+using ::testing::AnyOf;
using ::testing::Contains;
using ::testing::Pair;
@@ -360,7 +361,8 @@ TEST(MountTest, MountInfo) {
if (e.mount_point == dir.path()) {
EXPECT_EQ(e.fstype, "tmpfs");
auto mopts = ParseMountOptions(e.mount_opts);
- EXPECT_THAT(mopts, Contains(Pair("mode", "0123")));
+ EXPECT_THAT(mopts, AnyOf(Contains(Pair("mode", "0123")),
+ Contains(Pair("mode", "123"))));
}
}
@@ -371,7 +373,8 @@ TEST(MountTest, MountInfo) {
if (e.mount_point == dir.path()) {
EXPECT_EQ(e.fstype, "tmpfs");
auto mopts = ParseMountOptions(e.super_opts);
- EXPECT_THAT(mopts, Contains(Pair("mode", "0123")));
+ EXPECT_THAT(mopts, AnyOf(Contains(Pair("mode", "0123")),
+ Contains(Pair("mode", "123"))));
}
}
}
diff --git a/test/syscalls/linux/open.cc b/test/syscalls/linux/open.cc
index 4697c404c..ab9d19fef 100644
--- a/test/syscalls/linux/open.cc
+++ b/test/syscalls/linux/open.cc
@@ -433,7 +433,7 @@ TEST_F(OpenTest, CanTruncateReadOnly) {
// O_TRUNC should fail.
TEST_F(OpenTest, CanTruncateReadOnlyNoWritePermission) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
const DisableSave ds; // Permissions are dropped.
ASSERT_THAT(chmod(test_file_name_.c_str(), S_IRUSR | S_IRGRP),
@@ -473,8 +473,8 @@ TEST_F(OpenTest, CanTruncateWriteOnlyNoReadPermission) {
}
TEST_F(OpenTest, CanTruncateWithStrangePermissions) {
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
const DisableSave ds; // Permissions are dropped.
std::string path = NewTempAbsPath();
// Create a file without user permissions.
@@ -510,8 +510,8 @@ TEST_F(OpenTest, OpenWithStrangeFlags) {
TEST_F(OpenTest, OpenWithOpath) {
SKIP_IF(IsRunningWithVFS1());
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
const DisableSave ds; // Permissions are dropped.
std::string path = NewTempAbsPath();
diff --git a/test/syscalls/linux/open_create.cc b/test/syscalls/linux/open_create.cc
index 43d446926..177bda54d 100644
--- a/test/syscalls/linux/open_create.cc
+++ b/test/syscalls/linux/open_create.cc
@@ -93,7 +93,8 @@ TEST(CreateTest, CreatFileWithOTruncAndReadOnly) {
TEST(CreateTest, CreateFailsOnDirWithoutWritePerms) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// always override directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
+
auto parent = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0555));
auto file = JoinPath(parent.path(), "foo");
@@ -123,8 +124,8 @@ TEST(CreateTest, ChmodReadToWriteBetweenOpens) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// override file read/write permissions. CAP_DAC_READ_SEARCH needs to be
// cleared for the same reason.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
const TempPath file =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0400));
@@ -152,7 +153,7 @@ TEST(CreateTest, ChmodReadToWriteBetweenOpens) {
TEST(CreateTest, ChmodWriteToReadBetweenOpens) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// override file read/write permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
const TempPath file =
ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileMode(0200));
@@ -186,8 +187,8 @@ TEST(CreateTest, CreateWithReadFlagNotAllowedByMode) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// override file read/write permissions. CAP_DAC_READ_SEARCH needs to be
// cleared for the same reason.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
// Create and open a file with read flag but without read permissions.
const std::string path = NewTempAbsPath();
@@ -212,7 +213,7 @@ TEST(CreateTest, CreateWithWriteFlagNotAllowedByMode) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// override file read/write permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
// Create and open a file with write flag but without write permissions.
const std::string path = NewTempAbsPath();
diff --git a/test/syscalls/linux/prctl.cc b/test/syscalls/linux/prctl.cc
index f675dc430..19a57d353 100644
--- a/test/syscalls/linux/prctl.cc
+++ b/test/syscalls/linux/prctl.cc
@@ -184,10 +184,8 @@ TEST(PrctlTest, PDeathSig) {
// This test is to validate that calling prctl with PR_SET_MM without the
// CAP_SYS_RESOURCE returns EPERM.
TEST(PrctlTest, InvalidPrSetMM) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_RESOURCE))) {
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_RESOURCE,
- false)); // Drop capability to test below.
- }
+ // Drop capability to test below.
+ AutoCapability cap(CAP_SYS_RESOURCE, false);
ASSERT_THAT(prctl(PR_SET_MM, 0, 0, 0, 0), SyscallFailsWithErrno(EPERM));
}
diff --git a/test/syscalls/linux/proc.cc b/test/syscalls/linux/proc.cc
index 9e48fbca5..24928d876 100644
--- a/test/syscalls/linux/proc.cc
+++ b/test/syscalls/linux/proc.cc
@@ -1201,6 +1201,15 @@ TEST(ProcSelfCwd, Absolute) {
EXPECT_EQ(exe[0], '/');
}
+// Sanity check that /proc/cmdline is present.
+TEST(ProcCmdline, IsPresent) {
+ SKIP_IF(IsRunningWithVFS1());
+
+ std::string proc_cmdline =
+ ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/cmdline"));
+ ASSERT_FALSE(proc_cmdline.empty());
+}
+
// Sanity check for /proc/cpuinfo fields that must be present.
TEST(ProcCpuinfo, RequiredFieldsArePresent) {
std::string proc_cpuinfo =
@@ -1849,8 +1858,8 @@ TEST(ProcPidSymlink, SubprocessRunning) {
}
TEST(ProcPidSymlink, SubprocessZombied) {
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
char buf[1];
@@ -2252,7 +2261,7 @@ TEST(ProcTask, VerifyTaskDir) {
TEST(ProcTask, TaskDirCannotBeDeleted) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
EXPECT_THAT(rmdir("/proc/self/task"), SyscallFails());
EXPECT_THAT(rmdir(absl::StrCat("/proc/self/task/", getpid()).c_str()),
@@ -2698,6 +2707,14 @@ TEST(Proc, Statfs) {
EXPECT_EQ(st.f_namelen, NAME_MAX);
}
+// Tests that /proc/[pid]/fd/[num] can resolve to a path inside /proc.
+TEST(Proc, ResolveSymlinkToProc) {
+ const auto proc = ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/cmdline", 0));
+ const auto path = JoinPath("/proc/self/fd/", absl::StrCat(proc.get()));
+ const auto target = ASSERT_NO_ERRNO_AND_VALUE(ReadLink(path));
+ EXPECT_EQ(target, JoinPath("/proc/", absl::StrCat(getpid()), "/cmdline"));
+}
+
} // namespace
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/ptrace.cc b/test/syscalls/linux/ptrace.cc
index 2d9fec371..d519b65e6 100644
--- a/test/syscalls/linux/ptrace.cc
+++ b/test/syscalls/linux/ptrace.cc
@@ -175,7 +175,7 @@ TEST(PtraceTest, AttachSameThreadGroup) {
TEST(PtraceTest, TraceParentNotAllowed) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) < 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
pid_t const child_pid = fork();
if (child_pid == 0) {
@@ -193,7 +193,7 @@ TEST(PtraceTest, TraceParentNotAllowed) {
TEST(PtraceTest, TraceNonDescendantNotAllowed) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) < 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
pid_t const tracee_pid = fork();
if (tracee_pid == 0) {
@@ -259,7 +259,7 @@ TEST(PtraceTest, TraceNonDescendantWithCapabilityAllowed) {
TEST(PtraceTest, TraceDescendantsAllowed) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) > 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use socket pair to communicate tids to this process from its grandchild.
int sockets[2];
@@ -346,7 +346,7 @@ TEST(PtraceTest, PrctlSetPtracerInvalidPID) {
TEST(PtraceTest, PrctlSetPtracerPID) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -410,7 +410,7 @@ TEST(PtraceTest, PrctlSetPtracerPID) {
TEST(PtraceTest, PrctlSetPtracerAny) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -475,7 +475,7 @@ TEST(PtraceTest, PrctlSetPtracerAny) {
TEST(PtraceTest, PrctlClearPtracer) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -543,7 +543,7 @@ TEST(PtraceTest, PrctlClearPtracer) {
TEST(PtraceTest, PrctlReplacePtracer) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
pid_t const unused_pid = fork();
if (unused_pid == 0) {
@@ -633,7 +633,7 @@ TEST(PtraceTest, PrctlReplacePtracer) {
// thread group leader is still around.
TEST(PtraceTest, PrctlSetPtracerPersistsPastTraceeThreadExit) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -703,7 +703,7 @@ TEST(PtraceTest, PrctlSetPtracerPersistsPastTraceeThreadExit) {
// even if the tracee thread is terminated.
TEST(PtraceTest, PrctlSetPtracerPersistsPastLeaderExec) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -770,7 +770,7 @@ TEST(PtraceTest, PrctlSetPtracerPersistsPastLeaderExec) {
// exec.
TEST(PtraceTest, PrctlSetPtracerDoesNotPersistPastNonLeaderExec) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -904,7 +904,7 @@ TEST(PtraceTest, PrctlSetPtracerDoesNotPersistPastTracerThreadExit) {
[[noreturn]] void RunPrctlSetPtracerDoesNotPersistPastTracerThreadExit(
int tracee_tid, int fd) {
- TEST_PCHECK(SetCapability(CAP_SYS_PTRACE, false).ok());
+ AutoCapability cap(CAP_SYS_PTRACE, false);
ScopedThread t([fd] {
pid_t const tracer_tid = gettid();
@@ -1033,7 +1033,7 @@ TEST(PtraceTest, PrctlSetPtracerRespectsTracerThreadID) {
// attached.
TEST(PtraceTest, PrctlClearPtracerDoesNotAffectCurrentTracer) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Use sockets to synchronize between tracer and tracee.
int sockets[2];
@@ -1118,7 +1118,7 @@ TEST(PtraceTest, PrctlClearPtracerDoesNotAffectCurrentTracer) {
TEST(PtraceTest, PrctlNotInherited) {
SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(YamaPtraceScope()) != 1);
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
// Allow any ptracer. This should not affect the child processes.
ASSERT_THAT(prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY), SyscallSucceeds());
@@ -2302,7 +2302,7 @@ TEST(PtraceTest, SetYAMAPtraceScope) {
EXPECT_STREQ(buf.data(), "0\n");
// Test that a child can attach to its parent when ptrace_scope is 0.
- ASSERT_NO_ERRNO(SetCapability(CAP_SYS_PTRACE, false));
+ AutoCapability cap(CAP_SYS_PTRACE, false);
pid_t const child_pid = fork();
if (child_pid == 0) {
TEST_PCHECK(CheckPtraceAttach(getppid()) == 0);
diff --git a/test/syscalls/linux/pty.cc b/test/syscalls/linux/pty.cc
index 541b2744c..1c83e2656 100644
--- a/test/syscalls/linux/pty.cc
+++ b/test/syscalls/linux/pty.cc
@@ -396,12 +396,13 @@ TEST(PtyTrunc, Truncate) {
setsid();
// Make sure we're ignoring SIGHUP, which will be sent to this process once we
- // disconnect they TTY.
+ // disconnect the TTY.
struct sigaction sa = {};
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
- auto const cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGHUP, sa));
+ const Cleanup cleanup =
+ ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGHUP, sa));
// Opening PTYs with O_TRUNC shouldn't cause an error, but calls to
// (f)truncate should.
@@ -484,7 +485,7 @@ TEST(BasicPtyTest, OpenSetsControllingTTY) {
setsid();
// Make sure we're ignoring SIGHUP, which will be sent to this process once we
- // disconnect they TTY.
+ // disconnect the TTY.
struct sigaction sa = {};
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
@@ -1422,7 +1423,7 @@ TEST_F(JobControlTest, ReleaseTTY) {
ASSERT_THAT(ioctl(replica_.get(), TIOCSCTTY, 0), SyscallSucceeds());
// Make sure we're ignoring SIGHUP, which will be sent to this process once we
- // disconnect they TTY.
+ // disconnect the TTY.
struct sigaction sa = {};
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
@@ -1543,7 +1544,7 @@ TEST_F(JobControlTest, ReleaseTTYSignals) {
EXPECT_THAT(setpgid(diff_pgrp_child, diff_pgrp_child), SyscallSucceeds());
// Make sure we're ignoring SIGHUP, which will be sent to this process once we
- // disconnect they TTY.
+ // disconnect the TTY.
struct sigaction sighup_sa = {};
sighup_sa.sa_handler = SIG_IGN;
sighup_sa.sa_flags = 0;
diff --git a/test/syscalls/linux/raw_socket_hdrincl.cc b/test/syscalls/linux/raw_socket_hdrincl.cc
index 2f25aceb2..8b3d02d97 100644
--- a/test/syscalls/linux/raw_socket_hdrincl.cc
+++ b/test/syscalls/linux/raw_socket_hdrincl.cc
@@ -177,10 +177,8 @@ TEST_F(RawHDRINCL, ConnectToLoopback) {
SyscallSucceeds());
}
-TEST_F(RawHDRINCL, SendWithoutConnectSucceeds) {
- // FIXME(gvisor.dev/issue/3159): Test currently flaky.
- SKIP_IF(true);
-
+// FIXME(gvisor.dev/issue/3159): Test currently flaky.
+TEST_F(RawHDRINCL, DISABLED_SendWithoutConnectSucceeds) {
struct iphdr hdr = LoopbackHeader();
ASSERT_THAT(send(socket_, &hdr, sizeof(hdr), 0),
SyscallSucceedsWithValue(sizeof(hdr)));
diff --git a/test/syscalls/linux/rename.cc b/test/syscalls/linux/rename.cc
index b1a813de0..76a8da65f 100644
--- a/test/syscalls/linux/rename.cc
+++ b/test/syscalls/linux/rename.cc
@@ -259,8 +259,8 @@ TEST(RenameTest, DirectoryDoesNotOverwriteNonemptyDirectory) {
TEST(RenameTest, FailsWhenOldParentNotWritable) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
@@ -275,8 +275,8 @@ TEST(RenameTest, FailsWhenOldParentNotWritable) {
TEST(RenameTest, FailsWhenNewParentNotWritable) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
@@ -293,8 +293,8 @@ TEST(RenameTest, FailsWhenNewParentNotWritable) {
// to overwrite.
TEST(RenameTest, OverwriteFailsWhenNewParentNotWritable) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
@@ -312,8 +312,8 @@ TEST(RenameTest, OverwriteFailsWhenNewParentNotWritable) {
// because the user cannot determine if source exists.
TEST(RenameTest, FileDoesNotExistWhenNewParentNotExecutable) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
// No execute permission.
auto dir = ASSERT_NO_ERRNO_AND_VALUE(
diff --git a/test/syscalls/linux/rlimits.cc b/test/syscalls/linux/rlimits.cc
index 860f0f688..d31a2a880 100644
--- a/test/syscalls/linux/rlimits.cc
+++ b/test/syscalls/linux/rlimits.cc
@@ -41,9 +41,7 @@ TEST(RlimitTest, SetRlimitHigher) {
TEST(RlimitTest, UnprivilegedSetRlimit) {
// Drop privileges if necessary.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_RESOURCE))) {
- EXPECT_NO_ERRNO(SetCapability(CAP_SYS_RESOURCE, false));
- }
+ AutoCapability cap(CAP_SYS_RESOURCE, false);
struct rlimit rl = {};
rl.rlim_cur = 1000;
diff --git a/test/syscalls/linux/semaphore.cc b/test/syscalls/linux/semaphore.cc
index 207377efb..2ce8f836c 100644
--- a/test/syscalls/linux/semaphore.cc
+++ b/test/syscalls/linux/semaphore.cc
@@ -535,7 +535,7 @@ TEST(SemaphoreTest, SemCtlGetPidFork) {
TEST(SemaphoreTest, SemIpcSet) {
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT));
ASSERT_THAT(sem.get(), SyscallSucceeds());
@@ -560,7 +560,7 @@ TEST(SemaphoreTest, SemIpcSet) {
TEST(SemaphoreTest, SemCtlIpcStat) {
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
const uid_t kUid = getuid();
const gid_t kGid = getgid();
time_t start_time = time(nullptr);
@@ -635,7 +635,7 @@ PosixErrorOr<int> WaitSemctl(int semid, int target, int cmd) {
TEST(SemaphoreTest, SemopGetzcnt) {
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
// Create a write only semaphore set.
AutoSem sem(semget(IPC_PRIVATE, 1, 0200 | IPC_CREAT));
ASSERT_THAT(sem.get(), SyscallSucceeds());
@@ -743,7 +743,7 @@ TEST(SemaphoreTest, SemopGetzcntOnSignal) {
TEST(SemaphoreTest, SemopGetncnt) {
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
// Create a write only semaphore set.
AutoSem sem(semget(IPC_PRIVATE, 1, 0200 | IPC_CREAT));
ASSERT_THAT(sem.get(), SyscallSucceeds());
@@ -853,7 +853,7 @@ TEST(SemaphoreTest, IpcInfo) {
std::set<int> sem_ids;
struct seminfo info;
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
for (int i = 0; i < kLoops; i++) {
AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT));
ASSERT_THAT(sem.get(), SyscallSucceeds());
@@ -923,7 +923,7 @@ TEST(SemaphoreTest, SemInfo) {
std::set<int> sem_ids;
struct seminfo info;
// Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ AutoCapability cap(CAP_IPC_OWNER, false);
for (int i = 0; i < kLoops; i++) {
AutoSem sem(semget(IPC_PRIVATE, kSemSetSize, 0600 | IPC_CREAT));
ASSERT_THAT(sem.get(), SyscallSucceeds());
diff --git a/test/syscalls/linux/socket_capability.cc b/test/syscalls/linux/socket_capability.cc
index 84b5b2b21..f75482aba 100644
--- a/test/syscalls/linux/socket_capability.cc
+++ b/test/syscalls/linux/socket_capability.cc
@@ -40,7 +40,7 @@ TEST(SocketTest, UnixConnectNeedsWritePerm) {
// Drop capabilites that allow us to override permision checks. Otherwise if
// the test is run as root, the connect below will bypass permission checks
// and succeed unexpectedly.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
// Connect should fail without write perms.
ASSERT_THAT(chmod(addr.sun_path, 0500), SyscallSucceeds());
diff --git a/test/syscalls/linux/socket_ip_tcp_generic.cc b/test/syscalls/linux/socket_ip_tcp_generic.cc
index 59b56dc1a..2f5743cda 100644
--- a/test/syscalls/linux/socket_ip_tcp_generic.cc
+++ b/test/syscalls/linux/socket_ip_tcp_generic.cc
@@ -1155,7 +1155,7 @@ TEST_P(TCPSocketPairTest, IpMulticastLoopDefault) {
TEST_P(TCPSocketPairTest, TCPResetDuringClose) {
DisableSave ds; // Too many syscalls.
- constexpr int kThreadCount = 1000;
+ constexpr int kThreadCount = 100;
std::unique_ptr<ScopedThread> instances[kThreadCount];
for (int i = 0; i < kThreadCount; i++) {
instances[i] = absl::make_unique<ScopedThread>([&]() {
diff --git a/test/syscalls/linux/sticky.cc b/test/syscalls/linux/sticky.cc
index 4afed6d08..5a2841899 100644
--- a/test/syscalls/linux/sticky.cc
+++ b/test/syscalls/linux/sticky.cc
@@ -56,9 +56,7 @@ TEST(StickyTest, StickyBitPermDenied) {
// thread won't be able to open some log files after the test ends.
ScopedThread([&] {
// Drop privileges.
- if (HaveCapability(CAP_FOWNER).ValueOrDie()) {
- EXPECT_NO_ERRNO(SetCapability(CAP_FOWNER, false));
- }
+ AutoCapability cap(CAP_FOWNER, false);
// Change EUID and EGID.
EXPECT_THAT(
@@ -98,9 +96,7 @@ TEST(StickyTest, StickyBitSameUID) {
// thread won't be able to open some log files after the test ends.
ScopedThread([&] {
// Drop privileges.
- if (HaveCapability(CAP_FOWNER).ValueOrDie()) {
- EXPECT_NO_ERRNO(SetCapability(CAP_FOWNER, false));
- }
+ AutoCapability cap(CAP_FOWNER, false);
// Change EGID.
EXPECT_THAT(
diff --git a/test/syscalls/linux/symlink.cc b/test/syscalls/linux/symlink.cc
index 9f6c59446..fa6849f11 100644
--- a/test/syscalls/linux/symlink.cc
+++ b/test/syscalls/linux/symlink.cc
@@ -100,8 +100,8 @@ TEST(SymlinkTest, CanCreateSymlinkDir) {
TEST(SymlinkTest, CannotCreateSymlinkInReadOnlyDir) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
const std::string olddir = NewTempAbsPath();
ASSERT_THAT(mkdir(olddir.c_str(), 0444), SyscallSucceeds());
@@ -250,8 +250,8 @@ TEST(SymlinkTest, PwriteToSymlink) {
TEST(SymlinkTest, SymlinkAtDegradedPermissions) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
@@ -301,8 +301,8 @@ TEST(SymlinkTest, ReadlinkAtDirWithOpath) {
TEST(SymlinkTest, ReadlinkAtDegradedPermissions) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
const std::string oldpath = NewTempAbsPathInDir(dir.path());
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc
index 011b60f0e..5bfdecc79 100644
--- a/test/syscalls/linux/tcp_socket.cc
+++ b/test/syscalls/linux/tcp_socket.cc
@@ -1164,7 +1164,13 @@ TEST_P(SimpleTcpSocketTest, SelfConnectSend) {
ASSERT_THAT(RetryEINTR(connect)(s.get(), AsSockAddr(&addr), addrlen),
SyscallSucceeds());
- std::vector<char> writebuf(512 << 10); // 512 KiB.
+ // Ensure the write buffer is large enough not to block on a single write.
+ size_t write_size = 512 << 10; // 512 KiB.
+ EXPECT_THAT(setsockopt(s.get(), SOL_SOCKET, SO_SNDBUF, &write_size,
+ sizeof(write_size)),
+ SyscallSucceedsWithValue(0));
+
+ std::vector<char> writebuf(write_size);
// Try to send the whole thing.
int n;
diff --git a/test/syscalls/linux/truncate.cc b/test/syscalls/linux/truncate.cc
index 5db0b8276..0f08d9996 100644
--- a/test/syscalls/linux/truncate.cc
+++ b/test/syscalls/linux/truncate.cc
@@ -181,7 +181,7 @@ TEST(TruncateTest, FtruncateDir) {
TEST(TruncateTest, TruncateNonWriteable) {
// Make sure we don't have CAP_DAC_OVERRIDE, since that allows the user to
// always override write permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
auto temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
GetAbsoluteTestTmpdir(), absl::string_view(), 0555 /* mode */));
EXPECT_THAT(truncate(temp_file.path().c_str(), 0),
@@ -210,7 +210,7 @@ TEST(TruncateTest, FtruncateWithOpath) {
// regardless of whether the file permissions allow writing.
TEST(TruncateTest, FtruncateWithoutWritePermission) {
// Drop capabilities that allow us to override file permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
+ AutoCapability cap(CAP_DAC_OVERRIDE, false);
// The only time we can open a file with flags forbidden by its permissions
// is when we are creating the file. We cannot re-open with the same flags,
diff --git a/test/syscalls/linux/tuntap.cc b/test/syscalls/linux/tuntap.cc
index 6e3a00d2c..279fe342c 100644
--- a/test/syscalls/linux/tuntap.cc
+++ b/test/syscalls/linux/tuntap.cc
@@ -170,10 +170,10 @@ TEST(TuntapStaticTest, NetTunExists) {
class TuntapTest : public ::testing::Test {
protected:
void SetUp() override {
- have_net_admin_cap_ =
+ const bool have_net_admin_cap =
ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN));
- if (have_net_admin_cap_ && !IsRunningOnGvisor()) {
+ if (have_net_admin_cap && !IsRunningOnGvisor()) {
// gVisor always creates enabled/up'd interfaces, while Linux does not (as
// observed in b/110961832). Some of the tests require the Linux stack to
// notify the socket of any link-address-resolution failures. Those
@@ -183,21 +183,12 @@ class TuntapTest : public ::testing::Test {
ASSERT_NO_ERRNO(LinkChangeFlags(link.index, IFF_UP, IFF_UP));
}
}
-
- void TearDown() override {
- if (have_net_admin_cap_) {
- // Bring back capability if we had dropped it in test case.
- ASSERT_NO_ERRNO(SetCapability(CAP_NET_ADMIN, true));
- }
- }
-
- bool have_net_admin_cap_;
};
TEST_F(TuntapTest, CreateInterfaceNoCap) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
- ASSERT_NO_ERRNO(SetCapability(CAP_NET_ADMIN, false));
+ AutoCapability cap(CAP_NET_ADMIN, false);
FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(kDevNetTun, O_RDWR));
diff --git a/test/syscalls/linux/uname.cc b/test/syscalls/linux/uname.cc
index d8824b171..759ea4f53 100644
--- a/test/syscalls/linux/uname.cc
+++ b/test/syscalls/linux/uname.cc
@@ -76,9 +76,7 @@ TEST(UnameTest, SetNames) {
}
TEST(UnameTest, UnprivilegedSetNames) {
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))) {
- EXPECT_NO_ERRNO(SetCapability(CAP_SYS_ADMIN, false));
- }
+ AutoCapability cap(CAP_SYS_ADMIN, false);
EXPECT_THAT(sethostname("", 0), SyscallFailsWithErrno(EPERM));
EXPECT_THAT(setdomainname("", 0), SyscallFailsWithErrno(EPERM));
diff --git a/test/syscalls/linux/unlink.cc b/test/syscalls/linux/unlink.cc
index 7c301c305..75dcf4465 100644
--- a/test/syscalls/linux/unlink.cc
+++ b/test/syscalls/linux/unlink.cc
@@ -66,8 +66,8 @@ TEST(UnlinkTest, AtDir) {
TEST(UnlinkTest, AtDirDegradedPermissions) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
@@ -86,8 +86,8 @@ TEST(UnlinkTest, AtDirDegradedPermissions) {
// Files cannot be unlinked if the parent is not writable and executable.
TEST(UnlinkTest, ParentDegradedPermissions) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
diff --git a/test/syscalls/linux/utimes.cc b/test/syscalls/linux/utimes.cc
index e647d2896..e711d6657 100644
--- a/test/syscalls/linux/utimes.cc
+++ b/test/syscalls/linux/utimes.cc
@@ -225,7 +225,8 @@ void TestUtimensat(int dirFd, std::string const& path) {
EXPECT_GE(mtime3, before);
EXPECT_LE(mtime3, after);
- EXPECT_EQ(atime3, mtime3);
+ // TODO(b/187074006): atime/mtime may differ with local_gofer_uncached.
+ // EXPECT_EQ(atime3, mtime3);
}
TEST(UtimensatTest, OnAbsPath) {
diff --git a/test/syscalls/linux/verity_ioctl.cc b/test/syscalls/linux/verity_ioctl.cc
index 822e16f3c..be91b23d0 100644
--- a/test/syscalls/linux/verity_ioctl.cc
+++ b/test/syscalls/linux/verity_ioctl.cc
@@ -28,40 +28,13 @@
#include "test/util/mount_util.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
+#include "test/util/verity_util.h"
namespace gvisor {
namespace testing {
namespace {
-#ifndef FS_IOC_ENABLE_VERITY
-#define FS_IOC_ENABLE_VERITY 1082156677
-#endif
-
-#ifndef FS_IOC_MEASURE_VERITY
-#define FS_IOC_MEASURE_VERITY 3221513862
-#endif
-
-#ifndef FS_VERITY_FL
-#define FS_VERITY_FL 1048576
-#endif
-
-#ifndef FS_IOC_GETFLAGS
-#define FS_IOC_GETFLAGS 2148034049
-#endif
-
-struct fsverity_digest {
- __u16 digest_algorithm;
- __u16 digest_size; /* input/output */
- __u8 digest[];
-};
-
-constexpr int kMaxDigestSize = 64;
-constexpr int kDefaultDigestSize = 32;
-constexpr char kContents[] = "foobarbaz";
-constexpr char kMerklePrefix[] = ".merkle.verity.";
-constexpr char kMerkleRootPrefix[] = ".merkleroot.verity.";
-
class IoctlTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -85,80 +58,6 @@ class IoctlTest : public ::testing::Test {
std::string filename_;
};
-// Provide a function to convert bytes to hex string, since
-// absl::BytesToHexString does not seem to be compatible with golang
-// hex.DecodeString used in verity due to zero-padding.
-std::string BytesToHexString(uint8_t bytes[], int size) {
- std::stringstream ss;
- ss << std::hex;
- for (int i = 0; i < size; ++i) {
- ss << std::setw(2) << std::setfill('0') << static_cast<int>(bytes[i]);
- }
- return ss.str();
-}
-
-std::string MerklePath(absl::string_view path) {
- return JoinPath(Dirname(path),
- std::string(kMerklePrefix) + std::string(Basename(path)));
-}
-
-std::string MerkleRootPath(absl::string_view path) {
- return JoinPath(Dirname(path),
- std::string(kMerkleRootPrefix) + std::string(Basename(path)));
-}
-
-// Flip a random bit in the file represented by fd.
-PosixError FlipRandomBit(int fd, int size) {
- // Generate a random offset in the file.
- srand(time(nullptr));
- unsigned int seed = 0;
- int random_offset = rand_r(&seed) % size;
-
- // Read a random byte and flip a bit in it.
- char buf[1];
- RETURN_ERROR_IF_SYSCALL_FAIL(PreadFd(fd, buf, 1, random_offset));
- buf[0] ^= 1;
- RETURN_ERROR_IF_SYSCALL_FAIL(PwriteFd(fd, buf, 1, random_offset));
- return NoError();
-}
-
-// Mount a verity on the tmpfs and enable both the file and the direcotry. Then
-// mount a new verity with measured root hash.
-PosixErrorOr<std::string> MountVerity(std::string tmpfs_dir,
- std::string filename) {
- // Mount a verity fs on the existing tmpfs mount.
- std::string mount_opts = "lower_path=" + tmpfs_dir;
- ASSIGN_OR_RETURN_ERRNO(TempPath verity_dir, TempPath::CreateDir());
- RETURN_ERROR_IF_SYSCALL_FAIL(
- mount("", verity_dir.path().c_str(), "verity", 0, mount_opts.c_str()));
-
- // Enable both the file and the directory.
- ASSIGN_OR_RETURN_ERRNO(
- auto fd, Open(JoinPath(verity_dir.path(), filename), O_RDONLY, 0777));
- RETURN_ERROR_IF_SYSCALL_FAIL(ioctl(fd.get(), FS_IOC_ENABLE_VERITY));
- ASSIGN_OR_RETURN_ERRNO(auto dir_fd, Open(verity_dir.path(), O_RDONLY, 0777));
- RETURN_ERROR_IF_SYSCALL_FAIL(ioctl(dir_fd.get(), FS_IOC_ENABLE_VERITY));
-
- // Measure the root hash.
- uint8_t digest_array[sizeof(struct fsverity_digest) + kMaxDigestSize] = {0};
- struct fsverity_digest* digest =
- reinterpret_cast<struct fsverity_digest*>(digest_array);
- digest->digest_size = kMaxDigestSize;
- RETURN_ERROR_IF_SYSCALL_FAIL(
- ioctl(dir_fd.get(), FS_IOC_MEASURE_VERITY, digest));
-
- // Mount a verity fs with specified root hash.
- mount_opts +=
- ",root_hash=" + BytesToHexString(digest->digest, digest->digest_size);
- ASSIGN_OR_RETURN_ERRNO(TempPath verity_with_hash_dir, TempPath::CreateDir());
- RETURN_ERROR_IF_SYSCALL_FAIL(mount("", verity_with_hash_dir.path().c_str(),
- "verity", 0, mount_opts.c_str()));
- // Verity directories should not be deleted. Release the TempPath objects to
- // prevent those directories from being deleted by the destructor.
- verity_dir.release();
- return verity_with_hash_dir.release();
-}
-
TEST_F(IoctlTest, Enable) {
// Mount a verity fs on the existing tmpfs mount.
std::string mount_opts = "lower_path=" + tmpfs_dir_.path();
diff --git a/test/syscalls/linux/verity_mmap.cc b/test/syscalls/linux/verity_mmap.cc
new file mode 100644
index 000000000..dde74cc91
--- /dev/null
+++ b/test/syscalls/linux/verity_mmap.cc
@@ -0,0 +1,158 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "test/util/capability_util.h"
+#include "test/util/fs_util.h"
+#include "test/util/memory_util.h"
+#include "test/util/temp_path.h"
+#include "test/util/test_util.h"
+#include "test/util/verity_util.h"
+
+namespace gvisor {
+namespace testing {
+
+namespace {
+
+class MmapTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ // Verity is implemented in VFS2.
+ SKIP_IF(IsRunningWithVFS1());
+
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+ // Mount a tmpfs file system, to be wrapped by a verity fs.
+ tmpfs_dir_ = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ ASSERT_THAT(mount("", tmpfs_dir_.path().c_str(), "tmpfs", 0, ""),
+ SyscallSucceeds());
+
+ // Create a new file in the tmpfs mount.
+ file_ = ASSERT_NO_ERRNO_AND_VALUE(
+ TempPath::CreateFileWith(tmpfs_dir_.path(), kContents, 0777));
+ filename_ = Basename(file_.path());
+ }
+
+ TempPath tmpfs_dir_;
+ TempPath file_;
+ std::string filename_;
+};
+
+TEST_F(MmapTest, MmapRead) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ // Make sure the file can be open and mmapped in the mounted verity fs.
+ auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir, filename_), O_RDONLY, 0777));
+
+ Mapping const m =
+ ASSERT_NO_ERRNO_AND_VALUE(Mmap(nullptr, sizeof(kContents) - 1, PROT_READ,
+ MAP_SHARED, verity_fd.get(), 0));
+ EXPECT_THAT(std::string(m.view()), ::testing::StrEq(kContents));
+}
+
+TEST_F(MmapTest, ModifiedBeforeMmap) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ // Modify the file and check verification failure upon mmapping.
+ auto const fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(tmpfs_dir_.path(), filename_), O_RDWR, 0777));
+ ASSERT_NO_ERRNO(FlipRandomBit(fd.get(), sizeof(kContents) - 1));
+
+ auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir, filename_), O_RDONLY, 0777));
+ Mapping const m =
+ ASSERT_NO_ERRNO_AND_VALUE(Mmap(nullptr, sizeof(kContents) - 1, PROT_READ,
+ MAP_SHARED, verity_fd.get(), 0));
+
+ // Memory fault is expected when Translate fails.
+ EXPECT_EXIT(std::string(m.view()), ::testing::KilledBySignal(SIGSEGV), "");
+}
+
+TEST_F(MmapTest, ModifiedAfterMmap) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir, filename_), O_RDONLY, 0777));
+ Mapping const m =
+ ASSERT_NO_ERRNO_AND_VALUE(Mmap(nullptr, sizeof(kContents) - 1, PROT_READ,
+ MAP_SHARED, verity_fd.get(), 0));
+
+ // Modify the file after mapping and check verification failure upon mmapping.
+ auto const fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(tmpfs_dir_.path(), filename_), O_RDWR, 0777));
+ ASSERT_NO_ERRNO(FlipRandomBit(fd.get(), sizeof(kContents) - 1));
+
+ // Memory fault is expected when Translate fails.
+ EXPECT_EXIT(std::string(m.view()), ::testing::KilledBySignal(SIGSEGV), "");
+}
+
+class MmapParamTest
+ : public MmapTest,
+ public ::testing::WithParamInterface<std::tuple<int, int>> {
+ protected:
+ int prot() const { return std::get<0>(GetParam()); }
+ int flags() const { return std::get<1>(GetParam()); }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ WriteExecNoneSharedPrivate, MmapParamTest,
+ ::testing::Combine(::testing::ValuesIn({
+ PROT_WRITE,
+ PROT_EXEC,
+ PROT_NONE,
+ }),
+ ::testing::ValuesIn({MAP_SHARED, MAP_PRIVATE})));
+
+TEST_P(MmapParamTest, Mmap) {
+ std::string verity_dir =
+ ASSERT_NO_ERRNO_AND_VALUE(MountVerity(tmpfs_dir_.path(), filename_));
+
+ // Make sure the file can be open and mmapped in the mounted verity fs.
+ auto const verity_fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(JoinPath(verity_dir, filename_), O_RDONLY, 0777));
+
+ if (prot() == PROT_WRITE && flags() == MAP_SHARED) {
+ // Verity file system is read-only.
+ EXPECT_THAT(
+ reinterpret_cast<intptr_t>(mmap(nullptr, sizeof(kContents) - 1, prot(),
+ flags(), verity_fd.get(), 0)),
+ SyscallFailsWithErrno(EACCES));
+ } else {
+ Mapping const m = ASSERT_NO_ERRNO_AND_VALUE(Mmap(
+ nullptr, sizeof(kContents) - 1, prot(), flags(), verity_fd.get(), 0));
+ if (prot() == PROT_NONE) {
+ // Memory mapped by MAP_NONE cannot be accessed.
+ EXPECT_EXIT(std::string(m.view()), ::testing::KilledBySignal(SIGSEGV),
+ "");
+ } else {
+ EXPECT_THAT(std::string(m.view()), ::testing::StrEq(kContents));
+ }
+ }
+}
+
+} // namespace
+
+} // namespace testing
+} // namespace gvisor
diff --git a/test/syscalls/linux/xattr.cc b/test/syscalls/linux/xattr.cc
index dd8067807..c8a97df6b 100644
--- a/test/syscalls/linux/xattr.cc
+++ b/test/syscalls/linux/xattr.cc
@@ -109,8 +109,8 @@ TEST_F(XattrTest, XattrInvalidPrefix) {
// the restore will fail to open it with r/w permissions.
TEST_F(XattrTest, XattrReadOnly) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
const char* path = test_file_name_.c_str();
const char name[] = "user.test";
@@ -140,8 +140,8 @@ TEST_F(XattrTest, XattrReadOnly) {
// the restore will fail to open it with r/w permissions.
TEST_F(XattrTest, XattrWriteOnly) {
// Drop capabilities that allow us to override file and directory permissions.
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_OVERRIDE, false));
- ASSERT_NO_ERRNO(SetCapability(CAP_DAC_READ_SEARCH, false));
+ AutoCapability cap1(CAP_DAC_OVERRIDE, false);
+ AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
DisableSave ds;
ASSERT_NO_ERRNO(testing::Chmod(test_file_name_, S_IWUSR));
@@ -632,7 +632,7 @@ TEST_F(XattrTest, TrustedNamespaceWithCapSysAdmin) {
// Trusted namespace not supported in VFS1.
SKIP_IF(IsRunningWithVFS1());
- // TODO(b/66162845): Only gVisor tmpfs currently supports trusted namespace.
+ // TODO(b/166162845): Only gVisor tmpfs currently supports trusted namespace.
SKIP_IF(IsRunningOnGvisor() &&
!ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(test_file_name_)));
@@ -680,9 +680,7 @@ TEST_F(XattrTest, TrustedNamespaceWithoutCapSysAdmin) {
!ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(test_file_name_)));
// Drop CAP_SYS_ADMIN if we have it.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))) {
- EXPECT_NO_ERRNO(SetCapability(CAP_SYS_ADMIN, false));
- }
+ AutoCapability cap(CAP_SYS_ADMIN, false);
const char* path = test_file_name_.c_str();
const char name[] = "trusted.test";