summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls/linux')
-rw-r--r--test/syscalls/linux/BUILD1
-rw-r--r--test/syscalls/linux/dev.cc13
-rw-r--r--test/syscalls/linux/futex.cc92
-rw-r--r--test/syscalls/linux/getdents.cc3
-rw-r--r--test/syscalls/linux/mount.cc28
-rw-r--r--test/syscalls/linux/raw_socket.cc21
6 files changed, 157 insertions, 1 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 662d780d8..66a31cd28 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -943,6 +943,7 @@ cc_binary(
"//test/util:eventfd_util",
"//test/util:file_descriptor",
"//test/util:fs_util",
+ "@com_google_absl//absl/container:node_hash_set",
"@com_google_absl//absl/strings",
gtest,
"//test/util:posix_error",
diff --git a/test/syscalls/linux/dev.cc b/test/syscalls/linux/dev.cc
index 6fa16208e..1d0d584cd 100644
--- a/test/syscalls/linux/dev.cc
+++ b/test/syscalls/linux/dev.cc
@@ -161,6 +161,19 @@ TEST(DevTest, OpenDevFuse) {
ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/fuse", O_RDONLY));
}
+TEST(DevTest, ReadDevFuseWithoutMount) {
+ // Note(gvisor.dev/issue/3076) This won't work in the sentry until the new
+ // device registration is complete.
+ SKIP_IF(IsRunningWithVFS1() || IsRunningOnGvisor());
+
+ const FileDescriptor fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/fuse", O_RDONLY));
+
+ std::vector<char> buf(1);
+ EXPECT_THAT(ReadFd(fd.get(), buf.data(), sizeof(buf)),
+ SyscallFailsWithErrno(EPERM));
+}
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/futex.cc b/test/syscalls/linux/futex.cc
index 40c80a6e1..90b1f0508 100644
--- a/test/syscalls/linux/futex.cc
+++ b/test/syscalls/linux/futex.cc
@@ -18,6 +18,7 @@
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <syscall.h>
#include <unistd.h>
#include <algorithm>
@@ -737,6 +738,97 @@ TEST_P(PrivateAndSharedFutexTest, PITryLockConcurrency_NoRandomSave) {
}
}
+int get_robust_list(int pid, struct robust_list_head** head_ptr,
+ size_t* len_ptr) {
+ return syscall(__NR_get_robust_list, pid, head_ptr, len_ptr);
+}
+
+int set_robust_list(struct robust_list_head* head, size_t len) {
+ return syscall(__NR_set_robust_list, head, len);
+}
+
+TEST(RobustFutexTest, BasicSetGet) {
+ struct robust_list_head hd = {};
+ struct robust_list_head* hd_ptr = &hd;
+
+ // Set!
+ EXPECT_THAT(set_robust_list(hd_ptr, sizeof(hd)), SyscallSucceedsWithValue(0));
+
+ // Get!
+ struct robust_list_head* new_hd_ptr = hd_ptr;
+ size_t len;
+ EXPECT_THAT(get_robust_list(0, &new_hd_ptr, &len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(new_hd_ptr, hd_ptr);
+ EXPECT_EQ(len, sizeof(hd));
+}
+
+TEST(RobustFutexTest, GetFromOtherTid) {
+ // Get the current tid and list head.
+ pid_t tid = gettid();
+ struct robust_list_head* hd_ptr = {};
+ size_t len;
+ EXPECT_THAT(get_robust_list(0, &hd_ptr, &len), SyscallSucceedsWithValue(0));
+
+ // Create a new thread.
+ ScopedThread t([&] {
+ // Current tid list head should be different from parent tid.
+ struct robust_list_head* got_hd_ptr = {};
+ EXPECT_THAT(get_robust_list(0, &got_hd_ptr, &len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_NE(hd_ptr, got_hd_ptr);
+
+ // Get the parent list head by passing its tid.
+ EXPECT_THAT(get_robust_list(tid, &got_hd_ptr, &len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(hd_ptr, got_hd_ptr);
+ });
+
+ // Wait for thread.
+ t.Join();
+}
+
+TEST(RobustFutexTest, InvalidSize) {
+ struct robust_list_head* hd = {};
+ EXPECT_THAT(set_robust_list(hd, sizeof(*hd) + 1),
+ SyscallFailsWithErrno(EINVAL));
+}
+
+TEST(RobustFutexTest, PthreadMutexAttr) {
+ constexpr int kNumMutexes = 3;
+
+ // Create a bunch of robust mutexes.
+ pthread_mutexattr_t attrs[kNumMutexes];
+ pthread_mutex_t mtxs[kNumMutexes];
+ for (int i = 0; i < kNumMutexes; i++) {
+ TEST_PCHECK(pthread_mutexattr_init(&attrs[i]) == 0);
+ TEST_PCHECK(pthread_mutexattr_setrobust(&attrs[i], PTHREAD_MUTEX_ROBUST) ==
+ 0);
+ TEST_PCHECK(pthread_mutex_init(&mtxs[i], &attrs[i]) == 0);
+ }
+
+ // Start thread to lock the mutexes and then exit.
+ ScopedThread t([&] {
+ for (int i = 0; i < kNumMutexes; i++) {
+ TEST_PCHECK(pthread_mutex_lock(&mtxs[i]) == 0);
+ }
+ pthread_exit(NULL);
+ });
+
+ // Wait for thread.
+ t.Join();
+
+ // Now try to take the mutexes.
+ for (int i = 0; i < kNumMutexes; i++) {
+ // Should get EOWNERDEAD.
+ EXPECT_EQ(pthread_mutex_lock(&mtxs[i]), EOWNERDEAD);
+ // Make the mutex consistent.
+ EXPECT_EQ(pthread_mutex_consistent(&mtxs[i]), 0);
+ // Unlock.
+ EXPECT_EQ(pthread_mutex_unlock(&mtxs[i]), 0);
+ }
+}
+
} // namespace
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/getdents.cc b/test/syscalls/linux/getdents.cc
index b147d6181..b040cdcf7 100644
--- a/test/syscalls/linux/getdents.cc
+++ b/test/syscalls/linux/getdents.cc
@@ -32,6 +32,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/container/node_hash_set.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "test/util/eventfd_util.h"
@@ -393,7 +394,7 @@ TYPED_TEST(GetdentsTest, ProcSelfFd) {
// Make the buffer very small since we want to iterate.
typename TestFixture::DirentBufferType dirents(
2 * sizeof(typename TestFixture::LinuxDirentType));
- std::unordered_set<int> prev_fds;
+ absl::node_hash_set<int> prev_fds;
while (true) {
dirents.Reset();
int rv;
diff --git a/test/syscalls/linux/mount.cc b/test/syscalls/linux/mount.cc
index a3e9745cf..7664fa73d 100644
--- a/test/syscalls/linux/mount.cc
+++ b/test/syscalls/linux/mount.cc
@@ -321,6 +321,34 @@ TEST(MountTest, RenameRemoveMountPoint) {
ASSERT_THAT(rmdir(dir.path().c_str()), SyscallFailsWithErrno(EBUSY));
}
+TEST(MountTest, MountFuseFilesystemNoDevice) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+
+ // Note(gvisor.dev/issue/3076) This won't work in the sentry until the new
+ // device registration is complete.
+ SKIP_IF(IsRunningWithVFS1() || IsRunningOnGvisor());
+
+ auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ EXPECT_THAT(mount("", dir.path().c_str(), "fuse", 0, ""),
+ SyscallFailsWithErrno(EINVAL));
+}
+
+TEST(MountTest, MountFuseFilesystem) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
+
+ // Note(gvisor.dev/issue/3076) This won't work in the sentry until the new
+ // device registration is complete.
+ SKIP_IF(IsRunningWithVFS1() || IsRunningOnGvisor());
+
+ const FileDescriptor fd =
+ ASSERT_NO_ERRNO_AND_VALUE(Open("/dev/fuse", O_WRONLY));
+ std::string mopts = "fd=" + std::to_string(fd.get());
+
+ auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ auto const mount =
+ ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), "fuse", 0, mopts, 0));
+}
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/raw_socket.cc b/test/syscalls/linux/raw_socket.cc
index ce54dc064..8d6e5c913 100644
--- a/test/syscalls/linux/raw_socket.cc
+++ b/test/syscalls/linux/raw_socket.cc
@@ -262,6 +262,27 @@ TEST_P(RawSocketTest, SendWithoutConnectFails) {
SyscallFailsWithErrno(EDESTADDRREQ));
}
+// Wildcard Bind.
+TEST_P(RawSocketTest, BindToWildcard) {
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ struct sockaddr_storage addr;
+ addr = {};
+
+ // We don't set ports because raw sockets don't have a notion of ports.
+ if (Family() == AF_INET) {
+ struct sockaddr_in* sin = reinterpret_cast<struct sockaddr_in*>(&addr);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ struct sockaddr_in6* sin6 = reinterpret_cast<struct sockaddr_in6*>(&addr);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = in6addr_any;
+ }
+
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
+}
+
// Bind to localhost.
TEST_P(RawSocketTest, BindToLocalhost) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));