summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/BUILD11
-rw-r--r--test/syscalls/linux/cgroup.cc17
-rw-r--r--test/syscalls/linux/link.cc3
-rw-r--r--test/syscalls/linux/lseek.cc3
-rw-r--r--test/syscalls/linux/memfd.cc5
-rw-r--r--test/syscalls/linux/mmap.cc61
-rw-r--r--test/syscalls/linux/msgqueue.cc416
-rw-r--r--test/syscalls/linux/packet_socket.cc13
-rw-r--r--test/syscalls/linux/packet_socket_raw.cc42
-rw-r--r--test/syscalls/linux/pipe.cc24
-rw-r--r--test/syscalls/linux/prctl.cc6
-rw-r--r--test/syscalls/linux/proc_net.cc51
-rw-r--r--test/syscalls/linux/raw_socket.cc124
-rw-r--r--test/syscalls/linux/raw_socket_hdrincl.cc5
-rw-r--r--test/syscalls/linux/raw_socket_icmp.cc27
-rw-r--r--test/syscalls/linux/stat.cc2
-rw-r--r--test/syscalls/linux/statfs.cc2
-rw-r--r--test/syscalls/linux/tcp_socket.cc60
18 files changed, 552 insertions, 320 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 7129a797b..01ee432cb 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -7,6 +7,11 @@ package(
exports_files(
[
+ "packet_socket.cc",
+ "packet_socket_raw.cc",
+ "raw_socket.cc",
+ "raw_socket_hdrincl.cc",
+ "raw_socket_icmp.cc",
"socket.cc",
"socket_inet_loopback.cc",
"socket_inet_loopback_isolated.cc",
@@ -1443,6 +1448,7 @@ cc_binary(
deps = [
":unix_domain_socket_test_util",
"//test/util:capability_util",
+ "//test/util:cleanup",
"//test/util:file_descriptor",
"//test/util:socket_util",
"@com_google_absl//absl/base:core_headers",
@@ -1461,6 +1467,7 @@ cc_binary(
deps = [
":unix_domain_socket_test_util",
"//test/util:capability_util",
+ "//test/util:cleanup",
"//test/util:file_descriptor",
"//test/util:socket_util",
"@com_google_absl//absl/base:core_headers",
@@ -4173,9 +4180,11 @@ cc_binary(
linkstatic = 1,
deps = [
"//test/util:capability_util",
+ "//test/util:signal_util",
"//test/util:temp_path",
- "//test/util:test_main",
"//test/util:test_util",
+ "//test/util:thread_util",
+ "@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
],
)
diff --git a/test/syscalls/linux/cgroup.cc b/test/syscalls/linux/cgroup.cc
index f29891571..ca23dfeee 100644
--- a/test/syscalls/linux/cgroup.cc
+++ b/test/syscalls/linux/cgroup.cc
@@ -279,6 +279,23 @@ TEST(Cgroup, UnmountRepeated) {
EXPECT_THAT(umount(c.Path().c_str()), SyscallFailsWithErrno(EINVAL));
}
+TEST(Cgroup, Create) {
+ SKIP_IF(!CgroupsAvailable());
+ Mounter m(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()));
+ Cgroup c = ASSERT_NO_ERRNO_AND_VALUE(m.MountCgroupfs(""));
+ ASSERT_NO_ERRNO(c.CreateChild("child1"));
+ EXPECT_TRUE(ASSERT_NO_ERRNO_AND_VALUE(Exists(c.Path())));
+}
+
+TEST(Cgroup, SubcontainerInitiallyEmpty) {
+ SKIP_IF(!CgroupsAvailable());
+ Mounter m(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()));
+ Cgroup c = ASSERT_NO_ERRNO_AND_VALUE(m.MountCgroupfs(""));
+ Cgroup child = ASSERT_NO_ERRNO_AND_VALUE(c.CreateChild("child1"));
+ auto procs = ASSERT_NO_ERRNO_AND_VALUE(child.Procs());
+ EXPECT_TRUE(procs.empty());
+}
+
TEST(MemoryCgroup, MemoryUsageInBytes) {
SKIP_IF(!CgroupsAvailable());
diff --git a/test/syscalls/linux/link.cc b/test/syscalls/linux/link.cc
index 4f9ca1a65..8b208f99a 100644
--- a/test/syscalls/linux/link.cc
+++ b/test/syscalls/linux/link.cc
@@ -142,7 +142,8 @@ TEST(LinkTest, OldnameIsEmpty) {
TEST(LinkTest, OldnameDoesNotExist) {
const std::string oldname = NewTempAbsPath();
const std::string newname = NewTempAbsPath();
- EXPECT_THAT(link("", newname.c_str()), SyscallFailsWithErrno(ENOENT));
+ EXPECT_THAT(link(oldname.c_str(), newname.c_str()),
+ SyscallFailsWithErrno(ENOENT));
}
TEST(LinkTest, NewnameCannotExist) {
diff --git a/test/syscalls/linux/lseek.cc b/test/syscalls/linux/lseek.cc
index d4f89527c..dbc21833f 100644
--- a/test/syscalls/linux/lseek.cc
+++ b/test/syscalls/linux/lseek.cc
@@ -121,7 +121,8 @@ TEST(LseekTest, InvalidFD) {
}
TEST(LseekTest, DirCurEnd) {
- const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open("/tmp", O_RDONLY));
+ const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
+ Open(GetAbsoluteTestTmpdir().c_str(), O_RDONLY));
ASSERT_THAT(lseek(fd.get(), 0, SEEK_CUR), SyscallSucceedsWithValue(0));
}
diff --git a/test/syscalls/linux/memfd.cc b/test/syscalls/linux/memfd.cc
index 4a450742b..dbd1c93ae 100644
--- a/test/syscalls/linux/memfd.cc
+++ b/test/syscalls/linux/memfd.cc
@@ -445,9 +445,10 @@ TEST(MemfdTest, SealsAreInodeLevelProperties) {
// Tmpfs files also support seals, but are created with F_SEAL_SEAL.
TEST(MemfdTest, TmpfsFilesHaveSealSeal) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs("/tmp")));
+ std::string tmpdir = GetAbsoluteTestTmpdir();
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(tmpdir.c_str())));
const TempPath tmpfs_file =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn("/tmp"));
+ ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(tmpdir.c_str()));
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(tmpfs_file.path(), O_RDWR, 0644));
EXPECT_THAT(fcntl(fd.get(), F_GET_SEALS),
diff --git a/test/syscalls/linux/mmap.cc b/test/syscalls/linux/mmap.cc
index 93a6d9cde..fda176261 100644
--- a/test/syscalls/linux/mmap.cc
+++ b/test/syscalls/linux/mmap.cc
@@ -793,6 +793,19 @@ class MMapFileTest : public MMapTest {
ASSERT_THAT(unlink(filename_.c_str()), SyscallSucceeds());
}
+ bool FSSupportsMap() const {
+ bool supported = true;
+ void* ret = mmap(nullptr, 1, PROT_NONE, MAP_PRIVATE, fd_.get(), 0);
+ if (ret == MAP_FAILED && errno != ENODEV) {
+ supported = false;
+ }
+ if (ret != MAP_FAILED) {
+ munmap(ret, 1);
+ }
+
+ return supported;
+ }
+
ssize_t Read(char* buf, size_t count) {
ssize_t len = 0;
do {
@@ -840,12 +853,14 @@ class MMapFileParamTest
// MAP_POPULATE allowed.
// There isn't a good way to verify it actually did anything.
TEST_P(MMapFileParamTest, MapPopulate) {
+ SKIP_IF(!FSSupportsMap());
ASSERT_THAT(Map(0, kPageSize, prot(), flags() | MAP_POPULATE, fd_.get(), 0),
SyscallSucceeds());
}
// MAP_POPULATE on a short file.
TEST_P(MMapFileParamTest, MapPopulateShort) {
+ SKIP_IF(!FSSupportsMap());
ASSERT_THAT(
Map(0, 2 * kPageSize, prot(), flags() | MAP_POPULATE, fd_.get(), 0),
SyscallSucceeds());
@@ -853,6 +868,7 @@ TEST_P(MMapFileParamTest, MapPopulateShort) {
// Read contents from mapped file.
TEST_F(MMapFileTest, Read) {
+ SKIP_IF(!FSSupportsMap());
size_t len = strlen(kFileContents);
ASSERT_EQ(len, Write(kFileContents, len));
@@ -866,6 +882,7 @@ TEST_F(MMapFileTest, Read) {
// Map at an offset.
TEST_F(MMapFileTest, MapOffset) {
+ SKIP_IF(!FSSupportsMap());
ASSERT_THAT(lseek(fd_.get(), kPageSize, SEEK_SET), SyscallSucceeds());
size_t len = strlen(kFileContents);
@@ -881,6 +898,7 @@ TEST_F(MMapFileTest, MapOffset) {
}
TEST_F(MMapFileTest, MapOffsetBeyondEnd) {
+ SKIP_IF(!FSSupportsMap());
SetupGvisorDeathTest();
uintptr_t addr;
@@ -897,6 +915,7 @@ TEST_F(MMapFileTest, MapOffsetBeyondEnd) {
// Verify mmap fails when sum of length and offset overflows.
TEST_F(MMapFileTest, MapLengthPlusOffsetOverflows) {
+ SKIP_IF(!FSSupportsMap());
const size_t length = static_cast<size_t>(-kPageSize);
const off_t offset = kPageSize;
ASSERT_THAT(Map(0, length, PROT_READ, MAP_PRIVATE, fd_.get(), offset),
@@ -905,6 +924,7 @@ TEST_F(MMapFileTest, MapLengthPlusOffsetOverflows) {
// MAP_PRIVATE PROT_WRITE is allowed on read-only FDs.
TEST_F(MMapFileTest, WritePrivateOnReadOnlyFd) {
+ SKIP_IF(!FSSupportsMap());
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(filename_, O_RDONLY));
@@ -921,6 +941,7 @@ TEST_F(MMapFileTest, WritePrivateOnReadOnlyFd) {
// MAP_SHARED PROT_WRITE not allowed on read-only FDs.
TEST_F(MMapFileTest, WriteSharedOnReadOnlyFd) {
+ SKIP_IF(!FSSupportsMap());
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(filename_, O_RDONLY));
@@ -932,6 +953,7 @@ TEST_F(MMapFileTest, WriteSharedOnReadOnlyFd) {
// Mmap not allowed on O_PATH FDs.
TEST_F(MMapFileTest, MmapFileWithOpath) {
+ SKIP_IF(!FSSupportsMap());
SKIP_IF(IsRunningWithVFS1());
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
const FileDescriptor fd =
@@ -944,6 +966,7 @@ TEST_F(MMapFileTest, MmapFileWithOpath) {
// The FD must be readable.
TEST_P(MMapFileParamTest, WriteOnlyFd) {
+ SKIP_IF(!FSSupportsMap());
const FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Open(filename_, O_WRONLY));
@@ -955,6 +978,7 @@ TEST_P(MMapFileParamTest, WriteOnlyFd) {
// Overwriting the contents of a file mapped MAP_SHARED PROT_READ
// should cause the new data to be reflected in the mapping.
TEST_F(MMapFileTest, ReadSharedConsistentWithOverwrite) {
+ SKIP_IF(!FSSupportsMap());
// Start from scratch.
EXPECT_THAT(ftruncate(fd_.get(), 0), SyscallSucceeds());
@@ -994,6 +1018,7 @@ TEST_F(MMapFileTest, ReadSharedConsistentWithOverwrite) {
// Partially overwriting a file mapped MAP_SHARED PROT_READ should be reflected
// in the mapping.
TEST_F(MMapFileTest, ReadSharedConsistentWithPartialOverwrite) {
+ SKIP_IF(!FSSupportsMap());
// Start from scratch.
EXPECT_THAT(ftruncate(fd_.get(), 0), SyscallSucceeds());
@@ -1034,6 +1059,7 @@ TEST_F(MMapFileTest, ReadSharedConsistentWithPartialOverwrite) {
// Overwriting a file mapped MAP_SHARED PROT_READ should be reflected in the
// mapping and the file.
TEST_F(MMapFileTest, ReadSharedConsistentWithWriteAndFile) {
+ SKIP_IF(!FSSupportsMap());
// Start from scratch.
EXPECT_THAT(ftruncate(fd_.get(), 0), SyscallSucceeds());
@@ -1077,6 +1103,7 @@ TEST_F(MMapFileTest, ReadSharedConsistentWithWriteAndFile) {
// Write data to mapped file.
TEST_F(MMapFileTest, WriteShared) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd_.get(), 0),
@@ -1101,6 +1128,7 @@ TEST_F(MMapFileTest, WriteShared) {
// Write data to portion of mapped page beyond the end of the file.
// These writes are not reflected in the file.
TEST_F(MMapFileTest, WriteSharedBeyondEnd) {
+ SKIP_IF(!FSSupportsMap());
// The file is only half of a page. We map an entire page. Writes to the
// end of the mapping must not be reflected in the file.
uintptr_t addr;
@@ -1137,6 +1165,7 @@ TEST_F(MMapFileTest, WriteSharedBeyondEnd) {
// The portion of a mapped page that becomes part of the file after a truncate
// is reflected in the file.
TEST_F(MMapFileTest, WriteSharedTruncateUp) {
+ SKIP_IF(!FSSupportsMap());
// The file is only half of a page. We map an entire page. Writes to the
// end of the mapping must not be reflected in the file.
uintptr_t addr;
@@ -1174,6 +1203,7 @@ TEST_F(MMapFileTest, WriteSharedTruncateUp) {
}
TEST_F(MMapFileTest, ReadSharedTruncateDownThenUp) {
+ SKIP_IF(!FSSupportsMap());
// Start from scratch.
EXPECT_THAT(ftruncate(fd_.get(), 0), SyscallSucceeds());
@@ -1213,6 +1243,7 @@ TEST_F(MMapFileTest, ReadSharedTruncateDownThenUp) {
}
TEST_F(MMapFileTest, WriteSharedTruncateDownThenUp) {
+ SKIP_IF(!FSSupportsMap());
// The file is only half of a page. We map an entire page. Writes to the
// end of the mapping must not be reflected in the file.
uintptr_t addr;
@@ -1247,6 +1278,7 @@ TEST_F(MMapFileTest, WriteSharedTruncateDownThenUp) {
}
TEST_F(MMapFileTest, ReadSharedTruncateSIGBUS) {
+ SKIP_IF(!FSSupportsMap());
SetupGvisorDeathTest();
// Start from scratch.
@@ -1277,6 +1309,7 @@ TEST_F(MMapFileTest, ReadSharedTruncateSIGBUS) {
}
TEST_F(MMapFileTest, WriteSharedTruncateSIGBUS) {
+ SKIP_IF(!FSSupportsMap());
SetupGvisorDeathTest();
uintptr_t addr;
@@ -1298,6 +1331,7 @@ TEST_F(MMapFileTest, WriteSharedTruncateSIGBUS) {
}
TEST_F(MMapFileTest, ReadSharedTruncatePartialPage) {
+ SKIP_IF(!FSSupportsMap());
// Start from scratch.
EXPECT_THAT(ftruncate(fd_.get(), 0), SyscallSucceeds());
@@ -1327,6 +1361,7 @@ TEST_F(MMapFileTest, ReadSharedTruncatePartialPage) {
// Page can still be accessed and contents are intact after truncating a partial
// page.
TEST_F(MMapFileTest, WriteSharedTruncatePartialPage) {
+ SKIP_IF(!FSSupportsMap());
// Expand the file to a full page.
EXPECT_THAT(ftruncate(fd_.get(), kPageSize), SyscallSucceeds());
@@ -1354,6 +1389,7 @@ TEST_F(MMapFileTest, WriteSharedTruncatePartialPage) {
// MAP_PRIVATE writes are not carried through to the underlying file.
TEST_F(MMapFileTest, WritePrivate) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd_.get(), 0),
@@ -1378,6 +1414,7 @@ TEST_F(MMapFileTest, WritePrivate) {
// SIGBUS raised when reading or writing past end of a mapped file.
TEST_P(MMapFileParamTest, SigBusDeath) {
+ SKIP_IF(!FSSupportsMap());
SetupGvisorDeathTest();
uintptr_t addr;
@@ -1406,6 +1443,7 @@ TEST_P(MMapFileParamTest, SigBusDeath) {
//
// See b/27877699.
TEST_P(MMapFileParamTest, NoSigBusOnPagesBeforeEOF) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, 2 * kPageSize, prot(), flags(), fd_.get(), 0),
SyscallSucceeds());
@@ -1424,6 +1462,7 @@ TEST_P(MMapFileParamTest, NoSigBusOnPagesBeforeEOF) {
// Tests that SIGBUS is not raised when reading or writing from a file-mapped
// page containing EOF, *after* the EOF.
TEST_P(MMapFileParamTest, NoSigBusOnPageContainingEOF) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, 2 * kPageSize, prot(), flags(), fd_.get(), 0),
SyscallSucceeds());
@@ -1446,6 +1485,7 @@ TEST_P(MMapFileParamTest, NoSigBusOnPageContainingEOF) {
// page cache (which does not yet support writing to shared mappings), a bug
// caused reads to fail unnecessarily on such mappings. See b/28913513.
TEST_F(MMapFileTest, ReadingWritableSharedFilePageSucceeds) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
size_t len = strlen(kFileContents);
@@ -1463,6 +1503,7 @@ TEST_F(MMapFileTest, ReadingWritableSharedFilePageSucceeds) {
// read past end of file (resulting in a fault in sentry context in the gVisor
// case). See b/28913513.
TEST_F(MMapFileTest, InternalSigBus) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, 2 * kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd_.get(), 0),
@@ -1483,6 +1524,7 @@ TEST_F(MMapFileTest, InternalSigBus) {
// /dev/zero to a shared mapping (so that the SIGBUS isn't caught during
// copy-on-write breaking).
TEST_F(MMapFileTest, InternalSigBusZeroing) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, 2 * kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd_.get(), 0),
@@ -1578,6 +1620,7 @@ TEST_F(MMapTest, NoReserve) {
// Map more than the gVisor page-cache map unit (64k) and ensure that
// it is consistent with reading from the file.
TEST_F(MMapFileTest, Bug38498194) {
+ SKIP_IF(!FSSupportsMap());
// Choose a sufficiently large map unit.
constexpr int kSize = 4 * 1024 * 1024;
EXPECT_THAT(ftruncate(fd_.get(), kSize), SyscallSucceeds());
@@ -1606,6 +1649,7 @@ TEST_F(MMapFileTest, Bug38498194) {
// Tests that reading from a file to a memory mapping of the same file does not
// deadlock. See b/34813270.
TEST_F(MMapFileTest, SelfRead) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, kPageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd_.get(), 0),
@@ -1618,6 +1662,7 @@ TEST_F(MMapFileTest, SelfRead) {
// Tests that writing to a file from a memory mapping of the same file does not
// deadlock. Regression test for b/34813270.
TEST_F(MMapFileTest, SelfWrite) {
+ SKIP_IF(!FSSupportsMap());
uintptr_t addr;
ASSERT_THAT(addr = Map(0, kPageSize, PROT_READ, MAP_SHARED, fd_.get(), 0),
SyscallSucceeds());
@@ -1633,8 +1678,12 @@ TEST(MMapDeathTest, TruncateAfterCOWBreak) {
auto const temp_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(temp_file.path(), O_RDWR));
ASSERT_THAT(ftruncate(fd.get(), kPageSize), SyscallSucceeds());
- auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(Mmap(
- nullptr, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd.get(), 0));
+
+ auto maybe_mapping = Mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd.get(), 0);
+ // Does FS support mmap?
+ SKIP_IF(maybe_mapping.error().errno_value() == ENODEV);
+ auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(std::move(maybe_mapping));
// Write to this mapping, causing the page to be copied for write.
memset(mapping.ptr(), 'a', mapping.len());
@@ -1661,8 +1710,12 @@ TEST(MMapNoFixtureTest, MapReadOnlyAfterCreateWriteOnly) {
auto const wo_fd = ASSERT_NO_ERRNO_AND_VALUE(Open(filename, O_WRONLY));
ASSERT_THAT(ftruncate(wo_fd.get(), kPageSize), SyscallSucceeds());
- auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(
- Mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, ro_fd.get(), 0));
+ auto maybe_mapping =
+ Mmap(nullptr, kPageSize, PROT_READ, MAP_SHARED, ro_fd.get(), 0);
+ // Does FS support mmap?
+ SKIP_IF(maybe_mapping.error().errno_value() == ENODEV);
+ auto const mapping = ASSERT_NO_ERRNO_AND_VALUE(std::move(maybe_mapping));
+
std::vector<char> buf(kPageSize);
// The test passes if this survives.
std::copy(static_cast<char*>(mapping.ptr()),
diff --git a/test/syscalls/linux/msgqueue.cc b/test/syscalls/linux/msgqueue.cc
index 6804478fd..aaf46625d 100644
--- a/test/syscalls/linux/msgqueue.cc
+++ b/test/syscalls/linux/msgqueue.cc
@@ -13,14 +13,18 @@
// limitations under the License.
#include <errno.h>
+#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
+#include "absl/synchronization/notification.h"
#include "absl/time/clock.h"
#include "test/util/capability_util.h"
+#include "test/util/signal_util.h"
#include "test/util/temp_path.h"
#include "test/util/test_util.h"
+#include "test/util/thread_util.h"
namespace gvisor {
namespace testing {
@@ -36,10 +40,16 @@ constexpr int msgMax = 8192; // Maximum number of bytes in a single message.
constexpr int msgSsz = 16; // Message segment size.
constexpr int msgTql = msgMnb; // Maximum number of messages on all queues.
+constexpr int kInterruptSignal = SIGALRM;
+
// Queue is a RAII class used to automatically clean message queues.
class Queue {
public:
explicit Queue(int id) : id_(id) {}
+ Queue(const Queue&) = delete;
+ Queue& operator=(const Queue&) = delete;
+
+ Queue(Queue&& other) { id_ = other.release(); }
~Queue() {
if (id_ >= 0) {
@@ -59,6 +69,14 @@ class Queue {
int id_ = -1;
};
+PosixErrorOr<Queue> Msgget(key_t key, int flags) {
+ int id = msgget(key, flags);
+ if (id == -1) {
+ return PosixError(errno, absl::StrFormat("msgget(%d, %d)", key, flags));
+ }
+ return Queue(id);
+}
+
// Default size for messages.
constexpr size_t msgSize = 50;
@@ -78,14 +96,19 @@ bool operator==(msgbuf& a, msgbuf& b) {
return a.mtype == b.mtype;
}
+// msgmax represents a buffer for the largest possible single message.
+struct msgmax {
+ int64_t mtype;
+ char mtext[msgMax];
+};
+
// Test simple creation and retrieval for msgget(2).
TEST(MsgqueueTest, MsgGet) {
const TempPath keyfile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
const key_t key = ftok(keyfile.path().c_str(), 1);
ASSERT_THAT(key, SyscallSucceeds());
- Queue queue(msgget(key, IPC_CREAT));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(key, IPC_CREAT));
EXPECT_THAT(msgget(key, 0), SyscallSucceedsWithValue(queue.get()));
}
@@ -97,27 +120,20 @@ TEST(MsgqueueTest, MsgGetFail) {
EXPECT_THAT(msgget(key, 0), SyscallFailsWithErrno(ENOENT));
- Queue queue(msgget(key, IPC_CREAT));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(key, IPC_CREAT));
EXPECT_THAT(msgget(key, IPC_CREAT | IPC_EXCL), SyscallFailsWithErrno(EEXIST));
}
// Test using msgget(2) with IPC_PRIVATE option.
TEST(MsgqueueTest, MsgGetIpcPrivate) {
- Queue queue1(msgget(IPC_PRIVATE, 0));
- ASSERT_THAT(queue1.get(), SyscallSucceeds());
-
- Queue queue2(msgget(IPC_PRIVATE, 0));
- ASSERT_THAT(queue2.get(), SyscallSucceeds());
-
+ Queue queue1 = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0));
+ Queue queue2 = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0));
EXPECT_NE(queue1.get(), queue2.get());
}
// Test simple msgsnd and msgrcv.
TEST(MsgqueueTest, MsgOpSimple) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, "A message."};
msgbuf rcv;
@@ -132,8 +148,7 @@ TEST(MsgqueueTest, MsgOpSimple) {
// Test msgsnd and msgrcv of an empty message.
TEST(MsgqueueTest, MsgOpEmpty) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, ""};
msgbuf rcv;
@@ -145,8 +160,7 @@ TEST(MsgqueueTest, MsgOpEmpty) {
// Test truncation of message with MSG_NOERROR flag.
TEST(MsgqueueTest, MsgOpTruncate) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, ""};
msgbuf rcv;
@@ -160,8 +174,7 @@ TEST(MsgqueueTest, MsgOpTruncate) {
// Test msgsnd and msgrcv using invalid arguments.
TEST(MsgqueueTest, MsgOpInvalidArgs) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, ""};
@@ -178,8 +191,7 @@ TEST(MsgqueueTest, MsgOpInvalidArgs) {
// Test non-blocking msgrcv with an empty queue.
TEST(MsgqueueTest, MsgOpNoMsg) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf rcv;
EXPECT_THAT(msgrcv(queue.get(), &rcv, sizeof(rcv.mtext) + 1, 0, IPC_NOWAIT),
@@ -189,8 +201,7 @@ TEST(MsgqueueTest, MsgOpNoMsg) {
// Test non-blocking msgrcv with a non-empty queue, but no messages of wanted
// type.
TEST(MsgqueueTest, MsgOpNoMsgType) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, ""};
ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
@@ -202,8 +213,7 @@ TEST(MsgqueueTest, MsgOpNoMsgType) {
// Test msgrcv with a larger size message than wanted, and truncation disabled.
TEST(MsgqueueTest, MsgOpTooBig) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, ""};
ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
@@ -215,8 +225,7 @@ TEST(MsgqueueTest, MsgOpTooBig) {
// Test receiving messages based on type.
TEST(MsgqueueTest, MsgRcvType) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
// Send messages in an order and receive them in reverse, based on type,
// which shouldn't block.
@@ -242,8 +251,7 @@ TEST(MsgqueueTest, MsgRcvType) {
// Test using MSG_EXCEPT to receive a different-type message.
TEST(MsgqueueTest, MsgExcept) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
std::map<int64_t, msgbuf> typeToBuf = {
{1, msgbuf{1, "Message 1."}},
@@ -268,8 +276,7 @@ TEST(MsgqueueTest, MsgExcept) {
// Test msgrcv with a negative type.
TEST(MsgqueueTest, MsgRcvTypeNegative) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
// When msgtyp is negative, msgrcv returns the first message with mtype less
// than or equal to the absolute value.
@@ -292,8 +299,7 @@ TEST(MsgqueueTest, MsgRcvTypeNegative) {
TEST(MsgqueueTest, MsgOpPermissions) {
AutoCapability cap(CAP_IPC_OWNER, false);
- Queue queue(msgget(IPC_PRIVATE, 0000));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0000));
msgbuf buf{1, ""};
@@ -305,8 +311,7 @@ TEST(MsgqueueTest, MsgOpPermissions) {
// Test limits for messages and queues.
TEST(MsgqueueTest, MsgOpLimits) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, "A message."};
@@ -315,13 +320,6 @@ TEST(MsgqueueTest, MsgOpLimits) {
SyscallFailsWithErrno(EINVAL));
// Limit for queue.
- // Use a buffer with the maximum mount of bytes that can be transformed to
- // make it easier to exhaust the queue limit.
- struct msgmax {
- int64_t mtype;
- char mtext[msgMax];
- };
-
msgmax limit{1, ""};
for (size_t i = 0, msgCount = msgMnb / msgMax; i < msgCount; i++) {
EXPECT_THAT(msgsnd(queue.get(), &limit, sizeof(limit.mtext), 0),
@@ -341,11 +339,14 @@ bool MsgCopySupported() {
// test if errno == ENOSYS. This means that the test will always run on
// gVisor, but may be skipped on native linux.
- Queue queue(msgget(IPC_PRIVATE, 0600));
-
+ auto maybe_id = Msgget(IPC_PRIVATE, 0600);
+ if (!maybe_id.ok()) {
+ return false;
+ }
+ Queue queue(std::move(maybe_id.ValueOrDie()));
msgbuf buf{1, "Test message."};
- msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0);
+ msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0);
return !(msgrcv(queue.get(), &buf, sizeof(buf.mtext) + 1, 0,
MSG_COPY | IPC_NOWAIT) == -1 &&
errno == ENOSYS);
@@ -355,9 +356,7 @@ bool MsgCopySupported() {
TEST(MsgqueueTest, MsgCopy) {
SKIP_IF(!MsgCopySupported());
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf bufs[5] = {
msgbuf{1, "Message 1."}, msgbuf{2, "Message 2."}, msgbuf{3, "Message 3."},
msgbuf{4, "Message 4."}, msgbuf{5, "Message 5."},
@@ -391,9 +390,7 @@ TEST(MsgqueueTest, MsgCopy) {
TEST(MsgqueueTest, MsgCopyInvalidArgs) {
SKIP_IF(!MsgCopySupported());
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf rcv;
EXPECT_THAT(msgrcv(queue.get(), &rcv, msgSize, 1, MSG_COPY),
SyscallFailsWithErrno(EINVAL));
@@ -407,9 +404,7 @@ TEST(MsgqueueTest, MsgCopyInvalidArgs) {
TEST(MsgqueueTest, MsgCopyInvalidIndex) {
SKIP_IF(!MsgCopySupported());
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf rcv;
EXPECT_THAT(msgrcv(queue.get(), &rcv, msgSize, -3, MSG_COPY | IPC_NOWAIT),
SyscallFailsWithErrno(ENOMSG));
@@ -420,52 +415,41 @@ TEST(MsgqueueTest, MsgCopyInvalidIndex) {
// Test msgrcv (most probably) blocking on an empty queue.
TEST(MsgqueueTest, MsgRcvBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf buf{1, "A message."};
- const pid_t child_pid = fork();
- if (child_pid == 0) {
+ ScopedThread t([&] {
msgbuf rcv;
- TEST_PCHECK(RetryEINTR(msgrcv)(queue.get(), &rcv, sizeof(buf.mtext) + 1, 0,
- 0) == sizeof(buf.mtext) &&
- buf == rcv);
- _exit(0);
- }
+ ASSERT_THAT(
+ RetryEINTR(msgrcv)(queue.get(), &rcv, sizeof(buf.mtext) + 1, 0, 0),
+ SyscallSucceedsWithValue(sizeof(buf.mtext)));
+ EXPECT_TRUE(rcv == buf);
+ });
// Sleep to try and make msgrcv block before sending a message.
absl::SleepFor(absl::Milliseconds(150));
EXPECT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
SyscallSucceeds());
-
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0),
- SyscallSucceedsWithValue(child_pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
// Test msgrcv (most probably) waiting for a specific-type message.
TEST(MsgqueueTest, MsgRcvTypeBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgbuf bufs[5] = {{1, "A message."},
{1, "A message."},
{1, "A message."},
{1, "A message."},
{2, "A different message."}};
- const pid_t child_pid = fork();
- if (child_pid == 0) {
+ ScopedThread t([&] {
msgbuf buf = bufs[4]; // Buffer that should be received.
msgbuf rcv;
- TEST_PCHECK(RetryEINTR(msgrcv)(queue.get(), &rcv, sizeof(buf.mtext) + 1, 2,
- 0) == sizeof(buf.mtext) &&
- buf == rcv);
- _exit(0);
- }
+ ASSERT_THAT(
+ RetryEINTR(msgrcv)(queue.get(), &rcv, sizeof(buf.mtext) + 1, 2, 0),
+ SyscallSucceedsWithValue(sizeof(buf.mtext)));
+ EXPECT_TRUE(rcv == buf);
+ });
// Sleep to try and make msgrcv block before sending messages.
absl::SleepFor(absl::Milliseconds(150));
@@ -475,42 +459,29 @@ TEST(MsgqueueTest, MsgRcvTypeBlocking) {
EXPECT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
SyscallSucceeds());
}
-
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0),
- SyscallSucceedsWithValue(child_pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
// Test msgsnd (most probably) blocking on a full queue.
TEST(MsgqueueTest, MsgSndBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
- // Use a buffer with the maximum mount of bytes that can be transformed to
- // make it easier to exhaust the queue limit.
- struct msgmax {
- int64_t mtype;
- char mtext[msgMax];
- };
-
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
msgmax buf{1, ""}; // Has max amount of bytes.
const size_t msgCount = msgMnb / msgMax; // Number of messages that can be
// sent without blocking.
- const pid_t child_pid = fork();
- if (child_pid == 0) {
+ ScopedThread t([&] {
// Fill the queue.
for (size_t i = 0; i < msgCount; i++) {
- TEST_PCHECK(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0) == 0);
+ ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallSucceeds());
}
// Next msgsnd should block.
- TEST_PCHECK(RetryEINTR(msgsnd)(queue.get(), &buf, sizeof(buf.mtext), 0) ==
- 0);
- _exit(0);
- }
+ ASSERT_THAT(RetryEINTR(msgsnd)(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallSucceeds());
+ });
+
+ const DisableSave ds; // Too many syscalls.
// To increase the chance of the last msgsnd blocking before doing a msgrcv,
// we use MSG_COPY option to copy the last index in the queue. As long as
@@ -527,29 +498,16 @@ TEST(MsgqueueTest, MsgSndBlocking) {
EXPECT_THAT(msgrcv(queue.get(), &rcv, sizeof(buf.mtext), 0, 0),
SyscallSucceedsWithValue(sizeof(buf.mtext)));
-
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0),
- SyscallSucceedsWithValue(child_pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
// Test removing a queue while a blocking msgsnd is executing.
TEST(MsgqueueTest, MsgSndRmWhileBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
- // Use a buffer with the maximum mount of bytes that can be transformed to
- // make it easier to exhaust the queue limit.
- struct msgmax {
- int64_t mtype;
- char mtext[msgMax];
- };
+ // Number of messages that can be sent without blocking.
+ const size_t msgCount = msgMnb / msgMax;
- const size_t msgCount = msgMnb / msgMax; // Number of messages that can be
- // sent without blocking.
- const pid_t child_pid = fork();
- if (child_pid == 0) {
+ ScopedThread t([&] {
// Fill the queue.
msgmax buf{1, ""};
for (size_t i = 0; i < msgCount; i++) {
@@ -559,11 +517,12 @@ TEST(MsgqueueTest, MsgSndRmWhileBlocking) {
// Next msgsnd should block. Because we're repeating on EINTR, msgsnd may
// race with msgctl(IPC_RMID) and return EINVAL.
- TEST_PCHECK(RetryEINTR(msgsnd)(queue.get(), &buf, sizeof(buf.mtext), 0) ==
- -1 &&
- (errno == EIDRM || errno == EINVAL));
- _exit(0);
- }
+ EXPECT_THAT(RetryEINTR(msgsnd)(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallFails());
+ EXPECT_TRUE((errno == EIDRM || errno == EINVAL));
+ });
+
+ const DisableSave ds; // Too many syscalls.
// Similar to MsgSndBlocking, we do this to increase the chance of msgsnd
// blocking before removing the queue.
@@ -575,89 +534,165 @@ TEST(MsgqueueTest, MsgSndRmWhileBlocking) {
absl::SleepFor(absl::Milliseconds(100));
EXPECT_THAT(msgctl(queue.release(), IPC_RMID, nullptr), SyscallSucceeds());
-
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0),
- SyscallSucceedsWithValue(child_pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
// Test removing a queue while a blocking msgrcv is executing.
TEST(MsgqueueTest, MsgRcvRmWhileBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
- const pid_t child_pid = fork();
- if (child_pid == 0) {
+ ScopedThread t([&] {
// Because we're repeating on EINTR, msgsnd may race with msgctl(IPC_RMID)
// and return EINVAL.
msgbuf rcv;
- TEST_PCHECK(RetryEINTR(msgrcv)(queue.get(), &rcv, 1, 2, 0) == -1 &&
- (errno == EIDRM || errno == EINVAL));
- _exit(0);
- }
+ EXPECT_THAT(RetryEINTR(msgrcv)(queue.get(), &rcv, 1, 2, 0), SyscallFails());
+ EXPECT_TRUE(errno == EIDRM || errno == EINVAL);
+ });
// Sleep to try and make msgrcv block before sending messages.
absl::SleepFor(absl::Milliseconds(150));
EXPECT_THAT(msgctl(queue.release(), IPC_RMID, nullptr), SyscallSucceeds());
-
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(child_pid, &status, 0),
- SyscallSucceedsWithValue(child_pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
// Test a collection of msgsnd/msgrcv operations in different processes.
TEST(MsgqueueTest, MsgOpGeneral) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
+
+ // Create multiple sending/receiving threads that send messages back and
+ // forth. There's a matching recv for each send, so by the end of the test,
+ // all threads should succeed and return.
+ const std::vector<msgbuf> msgs = {
+ msgbuf{1, "Message 1."}, msgbuf{2, "Message 2."}, msgbuf{3, "Message 3."},
+ msgbuf{4, "Message 4."}, msgbuf{5, "Message 5."}};
- // Create 50 sending, and 50 receiving processes. There are only 5 messages to
- // be sent and received, each with a different type. All messages will be sent
- // and received equally (10 of each.) By the end of the test all processes
- // should unblock and return normally.
- const size_t msgCount = 5;
- std::map<int64_t, msgbuf> typeToBuf = {{1, msgbuf{1, "Message 1."}},
- {2, msgbuf{2, "Message 2."}},
- {3, msgbuf{3, "Message 3."}},
- {4, msgbuf{4, "Message 4."}},
- {5, msgbuf{5, "Message 5."}}};
-
- std::vector<pid_t> children;
-
- const size_t pCount = 50;
- for (size_t i = 1; i <= pCount; i++) {
- const pid_t child_pid = fork();
- if (child_pid == 0) {
- msgbuf buf = typeToBuf[(i % msgCount) + 1];
+ auto receiver = [&](int i) {
+ return [i, &msgs, &queue]() {
+ const msgbuf& target = msgs[i];
msgbuf rcv;
- TEST_PCHECK(RetryEINTR(msgrcv)(queue.get(), &rcv, sizeof(buf.mtext) + 1,
- (i % msgCount) + 1,
- 0) == sizeof(buf.mtext) &&
- buf == rcv);
- _exit(0);
- }
- children.push_back(child_pid);
- }
+ EXPECT_THAT(RetryEINTR(msgrcv)(queue.get(), &rcv,
+ sizeof(target.mtext) + 1, target.mtype, 0),
+ SyscallSucceedsWithValue(sizeof(target.mtext)));
+ EXPECT_EQ(rcv.mtype, target.mtype);
+ EXPECT_EQ(0, memcmp(rcv.mtext, target.mtext, sizeof(target.mtext)));
+ };
+ };
- for (size_t i = 1; i <= pCount; i++) {
- const pid_t child_pid = fork();
- if (child_pid == 0) {
- msgbuf buf = typeToBuf[(i % msgCount) + 1];
- TEST_PCHECK(RetryEINTR(msgsnd)(queue.get(), &buf, sizeof(buf.mtext), 0) ==
- 0);
- _exit(0);
- }
- children.push_back(child_pid);
- }
+ ScopedThread r1(receiver(0));
+ ScopedThread r2(receiver(1));
+ ScopedThread r3(receiver(2));
+ ScopedThread r4(receiver(3));
+ ScopedThread r5(receiver(4));
+ ScopedThread r6(receiver(0));
+ ScopedThread r7(receiver(1));
+ ScopedThread r8(receiver(2));
+ ScopedThread r9(receiver(3));
+ ScopedThread r10(receiver(4));
+
+ auto sender = [&](int i) {
+ return [i, &msgs, &queue]() {
+ const msgbuf& target = msgs[i];
+ EXPECT_THAT(
+ RetryEINTR(msgsnd)(queue.get(), &target, sizeof(target.mtext), 0),
+ SyscallSucceeds());
+ };
+ };
- for (auto const& pid : children) {
- int status;
- ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0),
- SyscallSucceedsWithValue(pid));
- EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ ScopedThread s1(sender(0));
+ ScopedThread s2(sender(1));
+ ScopedThread s3(sender(2));
+ ScopedThread s4(sender(3));
+ ScopedThread s5(sender(4));
+ ScopedThread s6(sender(0));
+ ScopedThread s7(sender(1));
+ ScopedThread s8(sender(2));
+ ScopedThread s9(sender(3));
+ ScopedThread s10(sender(4));
+}
+
+void empty_sighandler(int sig, siginfo_t* info, void* context) {}
+
+TEST(MsgqueueTest, InterruptRecv) {
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
+ char buf[64];
+
+ absl::Notification done, exit;
+
+ // Thread calling msgrcv with no corresponding send. It would block forever,
+ // but we'll interrupt with a signal below.
+ ScopedThread t([&] {
+ struct sigaction sa = {};
+ sa.sa_sigaction = empty_sighandler;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ auto cleanup_sigaction =
+ ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(kInterruptSignal, sa));
+ auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(
+ ScopedSignalMask(SIG_UNBLOCK, kInterruptSignal));
+
+ EXPECT_THAT(msgrcv(queue.get(), &buf, sizeof(buf), 0, 0),
+ SyscallFailsWithErrno(EINTR));
+
+ done.Notify();
+ exit.WaitForNotification();
+ });
+
+ const DisableSave ds; // Too many syscalls.
+
+ // We want the signal to arrive while msgrcv is blocking, but not after the
+ // thread has exited. Signals that arrive before msgrcv are no-ops.
+ do {
+ EXPECT_THAT(kill(getpid(), kInterruptSignal), SyscallSucceeds());
+ absl::SleepFor(absl::Milliseconds(100)); // Rate limit.
+ } while (!done.HasBeenNotified());
+
+ exit.Notify();
+ t.Join();
+}
+
+TEST(MsgqueueTest, InterruptSend) {
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
+ msgmax buf{1, ""};
+ // Number of messages that can be sent without blocking.
+ const size_t msgCount = msgMnb / msgMax;
+
+ // Fill the queue.
+ for (size_t i = 0; i < msgCount; i++) {
+ ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallSucceeds());
}
+
+ absl::Notification done, exit;
+
+ // Thread calling msgsnd on a full queue. It would block forever, but we'll
+ // interrupt with a signal below.
+ ScopedThread t([&] {
+ struct sigaction sa = {};
+ sa.sa_sigaction = empty_sighandler;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ auto cleanup_sigaction =
+ ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(kInterruptSignal, sa));
+ auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(
+ ScopedSignalMask(SIG_UNBLOCK, kInterruptSignal));
+
+ EXPECT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallFailsWithErrno(EINTR));
+
+ done.Notify();
+ exit.WaitForNotification();
+ });
+
+ const DisableSave ds; // Too many syscalls.
+
+ // We want the signal to arrive while msgsnd is blocking, but not after the
+ // thread has exited. Signals that arrive before msgsnd are no-ops.
+ do {
+ EXPECT_THAT(kill(getpid(), kInterruptSignal), SyscallSucceeds());
+ absl::SleepFor(absl::Milliseconds(100)); // Rate limit.
+ } while (!done.HasBeenNotified());
+
+ exit.Notify();
+ t.Join();
}
// Test msgctl with IPC_STAT option.
@@ -833,3 +868,16 @@ TEST(MsgqueueTest, MsgCtlMsgInfo) {
} // namespace
} // namespace testing
} // namespace gvisor
+
+int main(int argc, char** argv) {
+ // Some tests depend on delivering a signal to the main thread. Block the
+ // target signal so that any other threads created by TestInit will also have
+ // the signal blocked.
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, gvisor::testing::kInterruptSignal);
+ TEST_PCHECK(sigprocmask(SIG_BLOCK, &set, nullptr) == 0);
+
+ gvisor::testing::TestInit(&argc, &argv);
+ return gvisor::testing::RunAllTests();
+}
diff --git a/test/syscalls/linux/packet_socket.cc b/test/syscalls/linux/packet_socket.cc
index 98339277b..ca4ab0aad 100644
--- a/test/syscalls/linux/packet_socket.cc
+++ b/test/syscalls/linux/packet_socket.cc
@@ -14,13 +14,13 @@
#include <arpa/inet.h>
#include <ifaddrs.h>
-#include <linux/capability.h>
-#include <linux/if_arp.h>
-#include <linux/if_packet.h>
#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
+#include <netpacket/packet.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -31,6 +31,7 @@
#include "absl/base/internal/endian.h"
#include "test/syscalls/linux/unix_domain_socket_test_util.h"
#include "test/util/capability_util.h"
+#include "test/util/cleanup.h"
#include "test/util/file_descriptor.h"
#include "test/util/socket_util.h"
#include "test/util/test_util.h"
@@ -85,7 +86,7 @@ void SendUDPMessage(int sock) {
// Send an IP packet and make sure ETH_P_<something else> doesn't pick it up.
TEST(BasicCookedPacketTest, WrongType) {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
ASSERT_THAT(socket(AF_PACKET, SOCK_DGRAM, ETH_P_PUP),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -123,7 +124,7 @@ class CookedPacketTest : public ::testing::TestWithParam<int> {
};
void CookedPacketTest::SetUp() {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
ASSERT_THAT(socket(AF_PACKET, SOCK_DGRAM, htons(GetParam())),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -149,7 +150,7 @@ void CookedPacketTest::SetUp() {
void CookedPacketTest::TearDown() {
// TearDown will be run even if we skip the test.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
EXPECT_THAT(close(socket_), SyscallSucceeds());
}
}
diff --git a/test/syscalls/linux/packet_socket_raw.cc b/test/syscalls/linux/packet_socket_raw.cc
index 07beb8ba0..61714d1da 100644
--- a/test/syscalls/linux/packet_socket_raw.cc
+++ b/test/syscalls/linux/packet_socket_raw.cc
@@ -13,14 +13,13 @@
// limitations under the License.
#include <arpa/inet.h>
-#include <linux/capability.h>
-#include <linux/filter.h>
-#include <linux/if_arp.h>
-#include <linux/if_packet.h>
#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
+#include <netpacket/packet.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -32,6 +31,7 @@
#include "absl/base/internal/endian.h"
#include "test/syscalls/linux/unix_domain_socket_test_util.h"
#include "test/util/capability_util.h"
+#include "test/util/cleanup.h"
#include "test/util/file_descriptor.h"
#include "test/util/socket_util.h"
#include "test/util/test_util.h"
@@ -100,7 +100,7 @@ class RawPacketTest : public ::testing::TestWithParam<int> {
};
void RawPacketTest::SetUp() {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
ASSERT_THAT(socket(AF_PACKET, SOCK_RAW, htons(GetParam())),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -150,7 +150,7 @@ void RawPacketTest::SetUp() {
void RawPacketTest::TearDown() {
// TearDown will be run even if we skip the test.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
EXPECT_THAT(close(s_), SyscallSucceeds());
}
}
@@ -340,7 +340,7 @@ TEST_P(RawPacketTest, Send) {
// Check that setting SO_RCVBUF below min is clamped to the minimum
// receive buffer size.
TEST_P(RawPacketTest, SetSocketRecvBufBelowMin) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
// Discover minimum receive buf size by trying to set it to zero.
// See:
@@ -373,7 +373,7 @@ TEST_P(RawPacketTest, SetSocketRecvBufBelowMin) {
// Check that setting SO_RCVBUF above max is clamped to the maximum
// receive buffer size.
TEST_P(RawPacketTest, SetSocketRecvBufAboveMax) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
// Discover max buf size by trying to set the largest possible buffer size.
constexpr int kRcvBufSz = 0xffffffff;
@@ -400,7 +400,7 @@ TEST_P(RawPacketTest, SetSocketRecvBufAboveMax) {
// Check that setting SO_RCVBUF min <= kRcvBufSz <= max is honored.
TEST_P(RawPacketTest, SetSocketRecvBuf) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int max = 0;
int min = 0;
@@ -449,7 +449,7 @@ TEST_P(RawPacketTest, SetSocketRecvBuf) {
// Check that setting SO_SNDBUF below min is clamped to the minimum
// receive buffer size.
TEST_P(RawPacketTest, SetSocketSendBufBelowMin) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
// Discover minimum buffer size by trying to set it to zero.
constexpr int kSndBufSz = 0;
@@ -480,7 +480,7 @@ TEST_P(RawPacketTest, SetSocketSendBufBelowMin) {
// Check that setting SO_SNDBUF above max is clamped to the maximum
// send buffer size.
TEST_P(RawPacketTest, SetSocketSendBufAboveMax) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
// Discover maximum buffer size by trying to set it to a large value.
constexpr int kSndBufSz = 0xffffffff;
@@ -507,7 +507,7 @@ TEST_P(RawPacketTest, SetSocketSendBufAboveMax) {
// Check that setting SO_SNDBUF min <= kSndBufSz <= max is honored.
TEST_P(RawPacketTest, SetSocketSendBuf) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int max = 0;
int min = 0;
@@ -551,7 +551,7 @@ TEST_P(RawPacketTest, SetSocketSendBuf) {
}
TEST_P(RawPacketTest, GetSocketError) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int val = 0;
socklen_t val_len = sizeof(val);
@@ -561,7 +561,7 @@ TEST_P(RawPacketTest, GetSocketError) {
}
TEST_P(RawPacketTest, GetSocketErrorBind) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
{
// Bind to the loopback device.
@@ -627,7 +627,7 @@ TEST_P(RawPacketTest, SetSocketDetachFilterNoInstalledFilter) {
}
TEST_P(RawPacketTest, GetSocketDetachFilter) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int val = 0;
socklen_t val_len = sizeof(val);
@@ -636,7 +636,7 @@ TEST_P(RawPacketTest, GetSocketDetachFilter) {
}
TEST_P(RawPacketTest, SetAndGetSocketLinger) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int level = SOL_SOCKET;
int type = SO_LINGER;
@@ -657,7 +657,7 @@ TEST_P(RawPacketTest, SetAndGetSocketLinger) {
}
TEST_P(RawPacketTest, GetSocketAcceptConn) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
int got = -1;
socklen_t length = sizeof(got);
@@ -673,7 +673,7 @@ INSTANTIATE_TEST_SUITE_P(AllInetTests, RawPacketTest,
class RawPacketMsgSizeTest : public ::testing::TestWithParam<TestAddress> {};
TEST_P(RawPacketMsgSizeTest, SendTooLong) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
TestAddress addr = GetParam().WithPort(kPort);
@@ -690,8 +690,11 @@ TEST_P(RawPacketMsgSizeTest, SendTooLong) {
SyscallFailsWithErrno(EMSGSIZE));
}
+// TODO(https://fxbug.dev/76957): Run this test on Fuchsia once splice is
+// available.
+#ifndef __Fuchsia__
TEST_P(RawPacketMsgSizeTest, SpliceTooLong) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability()));
const char buf[65536] = {};
int fds[2];
@@ -718,6 +721,7 @@ TEST_P(RawPacketMsgSizeTest, SpliceTooLong) {
EXPECT_THAT(n, SyscallSucceedsWithValue(sizeof(buf)));
}
}
+#endif // __Fuchsia__
INSTANTIATE_TEST_SUITE_P(AllRawPacketMsgSizeTest, RawPacketMsgSizeTest,
::testing::Values(V4Loopback(), V6Loopback()));
diff --git a/test/syscalls/linux/pipe.cc b/test/syscalls/linux/pipe.cc
index 0bba86846..209801e36 100644
--- a/test/syscalls/linux/pipe.cc
+++ b/test/syscalls/linux/pipe.cc
@@ -13,11 +13,13 @@
// limitations under the License.
#include <fcntl.h> /* Obtain O_* constant definitions */
+#include <linux/futex.h>
#include <linux/magic.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/statfs.h>
#include <sys/uio.h>
+#include <syscall.h>
#include <unistd.h>
#include <vector>
@@ -50,6 +52,9 @@ std::atomic<int> global_num_signals_received = 0;
void SigRecordingHandler(int signum, siginfo_t* siginfo,
void* unused_ucontext) {
global_num_signals_received++;
+ ASSERT_THAT(syscall(SYS_futex, &global_num_signals_received,
+ FUTEX_WAKE | FUTEX_PRIVATE_FLAG, INT_MAX, 0, 0, 0),
+ SyscallSucceeds());
}
PosixErrorOr<Cleanup> RegisterSignalHandler(int signum) {
@@ -61,11 +66,14 @@ PosixErrorOr<Cleanup> RegisterSignalHandler(int signum) {
return ScopedSigaction(signum, handler);
}
-void WaitForSignalDelivery(absl::Duration timeout, int max_expected) {
- absl::Time wait_start = absl::Now();
- while (global_num_signals_received < max_expected &&
- absl::Now() - wait_start < timeout) {
- absl::SleepFor(absl::Milliseconds(10));
+void WaitForSignalDelivery(int expected) {
+ while (1) {
+ int v = global_num_signals_received;
+ if (v >= expected) {
+ break;
+ }
+ RetryEINTR(syscall)(SYS_futex, &global_num_signals_received,
+ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, v, 0, 0, 0);
}
}
@@ -371,7 +379,7 @@ TEST_P(PipeTest, ReaderSideCloses) {
EXPECT_THAT(write(wfd_.get(), &buf, sizeof(buf)),
SyscallFailsWithErrno(EPIPE));
- WaitForSignalDelivery(absl::Seconds(1), 1);
+ WaitForSignalDelivery(1);
ASSERT_EQ(global_num_signals_received, 1);
}
@@ -411,7 +419,7 @@ TEST_P(PipeTest, BlockWriteClosed) {
notify.WaitForNotification();
ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
- WaitForSignalDelivery(absl::Seconds(1), 1);
+ WaitForSignalDelivery(1);
ASSERT_EQ(global_num_signals_received, 1);
t.Join();
@@ -443,7 +451,7 @@ TEST_P(PipeTest, BlockPartialWriteClosed) {
// Unblock the above.
ASSERT_THAT(close(rfd_.release()), SyscallSucceeds());
- WaitForSignalDelivery(absl::Seconds(1), 2);
+ WaitForSignalDelivery(2);
ASSERT_EQ(global_num_signals_received, 2);
t.Join();
diff --git a/test/syscalls/linux/prctl.cc b/test/syscalls/linux/prctl.cc
index 25b0e63d4..286b3d168 100644
--- a/test/syscalls/linux/prctl.cc
+++ b/test/syscalls/linux/prctl.cc
@@ -214,6 +214,12 @@ TEST(PrctlTest, RootDumpability) {
SyscallFailsWithErrno(EINVAL));
}
+TEST(PrctlTest, SetGetSubreaper) {
+ // Setting subreaper on PID 1 works vacuously because PID 1 is always a
+ // subreaper.
+ EXPECT_THAT(prctl(PR_SET_CHILD_SUBREAPER, 1), SyscallSucceeds());
+}
+
} // namespace
} // namespace testing
diff --git a/test/syscalls/linux/proc_net.cc b/test/syscalls/linux/proc_net.cc
index 4cbe30fc1..162c0b665 100644
--- a/test/syscalls/linux/proc_net.cc
+++ b/test/syscalls/linux/proc_net.cc
@@ -152,6 +152,22 @@ TEST(ProcNetDev, Format) {
EXPECT_GT(entries.size(), 0);
}
+// GetMibsAllocationSysctl retuns a value of the net.core.mibs_allocation
+// sysctl./proc/sys/net/core/mibs_allocation
+//
+// When mibs_allocation is unset, a netns creation inherits MIB from init
+// network namespace. Otherwise, MIBS is allocated for each namespace.
+int GetMibsAllocationSysctl() {
+ auto ret = GetContents("/proc/sys/net/core/mibs_allocation");
+ if (!ret.ok()) {
+ // The current kernel doesn't support mibs_allocation.
+ return 1;
+ }
+ int32_t val;
+ EXPECT_TRUE(absl::SimpleAtoi(ret.ValueOrDie(), &val));
+ return val;
+}
+
PosixErrorOr<uint64_t> GetSNMPMetricFromProc(const std::string snmp,
const std::string& type,
const std::string& item) {
@@ -226,12 +242,21 @@ TEST(ProcNetSnmp, TcpReset) {
newAttemptFails = ASSERT_NO_ERRNO_AND_VALUE(
GetSNMPMetricFromProc(snmp, "Tcp", "AttemptFails"));
- EXPECT_EQ(oldActiveOpens, newActiveOpens - 1);
- EXPECT_EQ(oldOutRsts, newOutRsts - 1);
- EXPECT_EQ(oldAttemptFails, newAttemptFails - 1);
+ if (GetMibsAllocationSysctl()) {
+ EXPECT_EQ(oldActiveOpens, newActiveOpens - 1);
+ EXPECT_EQ(oldOutRsts, newOutRsts - 1);
+ EXPECT_EQ(oldAttemptFails, newAttemptFails - 1);
+ } else {
+ // System-wide statistics can have some noise.
+ EXPECT_LE(oldOutRsts, newOutRsts - 1);
+ EXPECT_LE(oldAttemptFails, newAttemptFails - 1);
+ }
}
TEST(ProcNetSnmp, TcpEstab) {
+ // System-wide statistics can have some noise.
+ SKIP_IF(GetMibsAllocationSysctl() == 0);
+
// TODO(gvisor.dev/issue/866): epsocket metrics are not savable.
DisableSave ds;
@@ -355,8 +380,14 @@ TEST(ProcNetSnmp, UdpNoPorts) {
newNoPorts =
ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Udp", "NoPorts"));
- EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1);
- EXPECT_EQ(oldNoPorts, newNoPorts - 1);
+ if (GetMibsAllocationSysctl()) {
+ EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1);
+ EXPECT_EQ(oldNoPorts, newNoPorts - 1);
+ } else {
+ // System-wide statistics can have some noise.
+ EXPECT_LE(oldOutDatagrams, newOutDatagrams - 1);
+ EXPECT_LE(oldNoPorts, newNoPorts - 1);
+ }
}
TEST(ProcNetSnmp, UdpIn) {
@@ -405,8 +436,14 @@ TEST(ProcNetSnmp, UdpIn) {
newInDatagrams = ASSERT_NO_ERRNO_AND_VALUE(
GetSNMPMetricFromProc(snmp, "Udp", "InDatagrams"));
- EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1);
- EXPECT_EQ(oldInDatagrams, newInDatagrams - 1);
+ if (GetMibsAllocationSysctl()) {
+ EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1);
+ EXPECT_EQ(oldInDatagrams, newInDatagrams - 1);
+ } else {
+ // System-wide statistics can have some noise.
+ EXPECT_LE(oldOutDatagrams, newOutDatagrams - 1);
+ EXPECT_LE(oldInDatagrams, newInDatagrams - 1);
+ }
}
TEST(ProcNetSnmp, CheckNetStat) {
diff --git a/test/syscalls/linux/raw_socket.cc b/test/syscalls/linux/raw_socket.cc
index e19fe8f6b..66f0e6ca4 100644
--- a/test/syscalls/linux/raw_socket.cc
+++ b/test/syscalls/linux/raw_socket.cc
@@ -13,8 +13,6 @@
// limitations under the License.
#include <arpa/inet.h>
-#include <linux/capability.h>
-#include <linux/filter.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
@@ -99,7 +97,7 @@ class RawSocketTest : public ::testing::TestWithParam<std::tuple<int, int>> {
};
void RawSocketTest::SetUp() {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
ASSERT_THAT(socket(Family(), SOCK_RAW, Protocol()),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -123,7 +121,7 @@ void RawSocketTest::SetUp() {
void RawSocketTest::TearDown() {
// TearDown will be run even if we skip the test.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
EXPECT_THAT(close(s_), SyscallSucceeds());
}
}
@@ -132,7 +130,7 @@ void RawSocketTest::TearDown() {
// BasicRawSocket::Setup creates the first one, so we only have to create one
// more here.
TEST_P(RawSocketTest, MultipleCreation) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int s2;
ASSERT_THAT(s2 = socket(Family(), SOCK_RAW, Protocol()), SyscallSucceeds());
@@ -142,7 +140,7 @@ TEST_P(RawSocketTest, MultipleCreation) {
// Test that shutting down an unconnected socket fails.
TEST_P(RawSocketTest, FailShutdownWithoutConnect) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(shutdown(s_, SHUT_WR), SyscallFailsWithErrno(ENOTCONN));
ASSERT_THAT(shutdown(s_, SHUT_RD), SyscallFailsWithErrno(ENOTCONN));
@@ -150,7 +148,7 @@ TEST_P(RawSocketTest, FailShutdownWithoutConnect) {
// Shutdown is a no-op for raw sockets (and datagram sockets in general).
TEST_P(RawSocketTest, ShutdownWriteNoop) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
@@ -165,7 +163,7 @@ TEST_P(RawSocketTest, ShutdownWriteNoop) {
// Shutdown is a no-op for raw sockets (and datagram sockets in general).
TEST_P(RawSocketTest, ShutdownReadNoop) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
@@ -182,14 +180,14 @@ TEST_P(RawSocketTest, ShutdownReadNoop) {
// Test that listen() fails.
TEST_P(RawSocketTest, FailListen) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(listen(s_, 1), SyscallFailsWithErrno(ENOTSUP));
}
// Test that accept() fails.
TEST_P(RawSocketTest, FailAccept) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr saddr;
socklen_t addrlen;
@@ -197,7 +195,7 @@ TEST_P(RawSocketTest, FailAccept) {
}
TEST_P(RawSocketTest, BindThenGetSockName) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_);
ASSERT_THAT(bind(s_, addr, AddrLen()), SyscallSucceeds());
@@ -221,7 +219,7 @@ TEST_P(RawSocketTest, BindThenGetSockName) {
}
TEST_P(RawSocketTest, ConnectThenGetSockName) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_);
ASSERT_THAT(connect(s_, addr, AddrLen()), SyscallSucceeds());
@@ -246,7 +244,7 @@ TEST_P(RawSocketTest, ConnectThenGetSockName) {
// Test that getpeername() returns nothing before connect().
TEST_P(RawSocketTest, FailGetPeerNameBeforeConnect) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr saddr;
socklen_t addrlen = sizeof(saddr);
@@ -256,7 +254,7 @@ TEST_P(RawSocketTest, FailGetPeerNameBeforeConnect) {
// Test that getpeername() returns something after connect().
TEST_P(RawSocketTest, GetPeerName) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
@@ -270,7 +268,7 @@ TEST_P(RawSocketTest, GetPeerName) {
// Test that the socket is writable immediately.
TEST_P(RawSocketTest, PollWritableImmediately) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct pollfd pfd = {};
pfd.fd = s_;
@@ -280,7 +278,7 @@ TEST_P(RawSocketTest, PollWritableImmediately) {
// Test that the socket isn't readable before receiving anything.
TEST_P(RawSocketTest, PollNotReadableInitially) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Try to receive data with MSG_DONTWAIT, which returns immediately if there's
// nothing to be read.
@@ -291,7 +289,7 @@ TEST_P(RawSocketTest, PollNotReadableInitially) {
// Test that the socket becomes readable once something is written to it.
TEST_P(RawSocketTest, PollTriggeredOnWrite) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Write something so that there's data to be read.
// Arbitrary.
@@ -306,7 +304,7 @@ TEST_P(RawSocketTest, PollTriggeredOnWrite) {
// Test that we can connect() to a valid IP (loopback).
TEST_P(RawSocketTest, ConnectToLoopback) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
@@ -315,7 +313,7 @@ TEST_P(RawSocketTest, ConnectToLoopback) {
// Test that calling send() without connect() fails.
TEST_P(RawSocketTest, SendWithoutConnectFails) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Arbitrary.
constexpr char kBuf[] = "Endgame was good";
@@ -325,7 +323,7 @@ TEST_P(RawSocketTest, SendWithoutConnectFails) {
// Wildcard Bind.
TEST_P(RawSocketTest, BindToWildcard) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr_storage addr;
addr = {};
@@ -346,16 +344,15 @@ TEST_P(RawSocketTest, BindToWildcard) {
// Bind to localhost.
TEST_P(RawSocketTest, BindToLocalhost) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
- ASSERT_THAT(
- bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
- SyscallSucceeds());
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
}
// Bind to a different address.
TEST_P(RawSocketTest, BindToInvalid) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
struct sockaddr_storage bind_addr = addr_;
if (Family() == AF_INET) {
@@ -367,13 +364,14 @@ TEST_P(RawSocketTest, BindToInvalid) {
memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr));
sin6->sin6_addr.s6_addr[0] = 1; // 1: - An address that we can't bind to.
}
- ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&bind_addr),
- AddrLen()), SyscallFailsWithErrno(EADDRNOTAVAIL));
+ ASSERT_THAT(
+ bind(s_, reinterpret_cast<struct sockaddr*>(&bind_addr), AddrLen()),
+ SyscallFailsWithErrno(EADDRNOTAVAIL));
}
// Send and receive an packet.
TEST_P(RawSocketTest, SendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Arbitrary.
constexpr char kBuf[] = "TB12";
@@ -388,7 +386,7 @@ TEST_P(RawSocketTest, SendAndReceive) {
// We should be able to create multiple raw sockets for the same protocol and
// receive the same packet on both.
TEST_P(RawSocketTest, MultipleSocketReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int s2;
ASSERT_THAT(s2 = socket(Family(), SOCK_RAW, Protocol()), SyscallSucceeds());
@@ -403,11 +401,11 @@ TEST_P(RawSocketTest, MultipleSocketReceive) {
// Receive it on socket 2.
std::vector<char> recv_buf2(sizeof(kBuf) + HdrLen());
- ASSERT_NO_FATAL_FAILURE(ReceiveBufFrom(s2, recv_buf2.data(),
- recv_buf2.size()));
+ ASSERT_NO_FATAL_FAILURE(
+ ReceiveBufFrom(s2, recv_buf2.data(), recv_buf2.size()));
- EXPECT_EQ(memcmp(recv_buf1.data() + HdrLen(),
- recv_buf2.data() + HdrLen(), sizeof(kBuf)),
+ EXPECT_EQ(memcmp(recv_buf1.data() + HdrLen(), recv_buf2.data() + HdrLen(),
+ sizeof(kBuf)),
0);
ASSERT_THAT(close(s2), SyscallSucceeds());
@@ -415,7 +413,7 @@ TEST_P(RawSocketTest, MultipleSocketReceive) {
// Test that connect sends packets to the right place.
TEST_P(RawSocketTest, SendAndReceiveViaConnect) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
@@ -434,11 +432,10 @@ TEST_P(RawSocketTest, SendAndReceiveViaConnect) {
// Bind to localhost, then send and receive packets.
TEST_P(RawSocketTest, BindSendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
- ASSERT_THAT(
- bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
- SyscallSucceeds());
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
// Arbitrary.
constexpr char kBuf[] = "DR16";
@@ -452,11 +449,10 @@ TEST_P(RawSocketTest, BindSendAndReceive) {
// Bind and connect to localhost and send/receive packets.
TEST_P(RawSocketTest, BindConnectSendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
- ASSERT_THAT(
- bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
- SyscallSucceeds());
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
SyscallSucceeds());
@@ -474,7 +470,7 @@ TEST_P(RawSocketTest, BindConnectSendAndReceive) {
// Check that setting SO_RCVBUF below min is clamped to the minimum
// receive buffer size.
TEST_P(RawSocketTest, SetSocketRecvBufBelowMin) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Discover minimum receive buf size by trying to set it to zero.
// See:
@@ -507,7 +503,7 @@ TEST_P(RawSocketTest, SetSocketRecvBufBelowMin) {
// Check that setting SO_RCVBUF above max is clamped to the maximum
// receive buffer size.
TEST_P(RawSocketTest, SetSocketRecvBufAboveMax) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Discover max buf size by trying to set the largest possible buffer size.
constexpr int kRcvBufSz = 0xffffffff;
@@ -534,7 +530,7 @@ TEST_P(RawSocketTest, SetSocketRecvBufAboveMax) {
// Check that setting SO_RCVBUF min <= kRcvBufSz <= max is honored.
TEST_P(RawSocketTest, SetSocketRecvBuf) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int max = 0;
int min = 0;
@@ -584,7 +580,7 @@ TEST_P(RawSocketTest, SetSocketRecvBuf) {
// Check that setting SO_SNDBUF below min is clamped to the minimum
// receive buffer size.
TEST_P(RawSocketTest, SetSocketSendBufBelowMin) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Discover minimum buffer size by trying to set it to zero.
constexpr int kSndBufSz = 0;
@@ -615,7 +611,7 @@ TEST_P(RawSocketTest, SetSocketSendBufBelowMin) {
// Check that setting SO_SNDBUF above max is clamped to the maximum
// send buffer size.
TEST_P(RawSocketTest, SetSocketSendBufAboveMax) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Discover maximum buffer size by trying to set it to a large value.
constexpr int kSndBufSz = 0xffffffff;
@@ -642,7 +638,7 @@ TEST_P(RawSocketTest, SetSocketSendBufAboveMax) {
// Check that setting SO_SNDBUF min <= kSndBufSz <= max is honored.
TEST_P(RawSocketTest, SetSocketSendBuf) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int max = 0;
int min = 0;
@@ -688,11 +684,10 @@ TEST_P(RawSocketTest, SetSocketSendBuf) {
// Test that receive buffer limits are not enforced when the recv buffer is
// empty.
TEST_P(RawSocketTest, RecvBufLimitsEmptyRecvBuffer) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
- ASSERT_THAT(
- bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
- SyscallSucceeds());
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
SyscallSucceeds());
@@ -719,9 +714,7 @@ TEST_P(RawSocketTest, RecvBufLimitsEmptyRecvBuffer) {
// Receive the packet and make sure it's identical.
std::vector<char> recv_buf(buf.size() + HdrLen());
ASSERT_NO_FATAL_FAILURE(ReceiveBuf(recv_buf.data(), recv_buf.size()));
- EXPECT_EQ(
- memcmp(recv_buf.data() + HdrLen(), buf.data(), buf.size()),
- 0);
+ EXPECT_EQ(memcmp(recv_buf.data() + HdrLen(), buf.data(), buf.size()), 0);
}
{
@@ -734,9 +727,7 @@ TEST_P(RawSocketTest, RecvBufLimitsEmptyRecvBuffer) {
// Receive the packet and make sure it's identical.
std::vector<char> recv_buf(buf.size() + HdrLen());
ASSERT_NO_FATAL_FAILURE(ReceiveBuf(recv_buf.data(), recv_buf.size()));
- EXPECT_EQ(
- memcmp(recv_buf.data() + HdrLen(), buf.data(), buf.size()),
- 0);
+ EXPECT_EQ(memcmp(recv_buf.data() + HdrLen(), buf.data(), buf.size()), 0);
}
}
@@ -750,11 +741,10 @@ TEST_P(RawSocketTest, RecvBufLimits) {
if (Protocol() == IPPROTO_TCP) {
return;
}
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
- ASSERT_THAT(
- bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
- SyscallSucceeds());
+ ASSERT_THAT(bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
+ SyscallSucceeds());
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), AddrLen()),
SyscallSucceeds());
@@ -814,9 +804,7 @@ TEST_P(RawSocketTest, RecvBufLimits) {
// Receive the packet and make sure it's identical.
std::vector<char> recv_buf(buf.size() + HdrLen());
ASSERT_NO_FATAL_FAILURE(ReceiveBuf(recv_buf.data(), recv_buf.size()));
- EXPECT_EQ(memcmp(recv_buf.data() + HdrLen(), buf.data(),
- buf.size()),
- 0);
+ EXPECT_EQ(memcmp(recv_buf.data() + HdrLen(), buf.data(), buf.size()), 0);
}
// Assert that the last packet is dropped because the receive buffer should
@@ -885,7 +873,7 @@ TEST_P(RawSocketTest, GetSocketDetachFilter) {
// AF_INET6+SOCK_RAW+IPPROTO_RAW sockets can be created, but not written to.
TEST(RawSocketTest, IPv6ProtoRaw) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int sock;
ASSERT_THAT(sock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW),
@@ -902,7 +890,7 @@ TEST(RawSocketTest, IPv6ProtoRaw) {
}
TEST(RawSocketTest, IPv6SendMsg) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int sock;
ASSERT_THAT(sock = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP),
@@ -930,7 +918,7 @@ TEST(RawSocketTest, IPv6SendMsg) {
}
TEST_P(RawSocketTest, ConnectOnIPv6Socket) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int sock;
ASSERT_THAT(sock = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP),
diff --git a/test/syscalls/linux/raw_socket_hdrincl.cc b/test/syscalls/linux/raw_socket_hdrincl.cc
index f1d8fd295..d45bd07bc 100644
--- a/test/syscalls/linux/raw_socket_hdrincl.cc
+++ b/test/syscalls/linux/raw_socket_hdrincl.cc
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <linux/capability.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
@@ -63,7 +62,7 @@ class RawHDRINCL : public ::testing::Test {
};
void RawHDRINCL::SetUp() {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
ASSERT_THAT(socket(AF_INET, SOCK_RAW, IPPROTO_RAW),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -81,7 +80,7 @@ void RawHDRINCL::SetUp() {
void RawHDRINCL::TearDown() {
// TearDown will be run even if we skip the test.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
EXPECT_THAT(close(socket_), SyscallSucceeds());
}
}
diff --git a/test/syscalls/linux/raw_socket_icmp.cc b/test/syscalls/linux/raw_socket_icmp.cc
index 27d3fffee..3f9717284 100644
--- a/test/syscalls/linux/raw_socket_icmp.cc
+++ b/test/syscalls/linux/raw_socket_icmp.cc
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <linux/capability.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
@@ -77,7 +76,7 @@ class RawSocketICMPTest : public ::testing::Test {
};
void RawSocketICMPTest::SetUp() {
- if (!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
ASSERT_THAT(socket(AF_INET, SOCK_RAW, IPPROTO_ICMP),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP();
@@ -95,7 +94,7 @@ void RawSocketICMPTest::SetUp() {
void RawSocketICMPTest::TearDown() {
// TearDown will be run even if we skip the test.
- if (ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) {
+ if (ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())) {
EXPECT_THAT(close(s_), SyscallSucceeds());
}
}
@@ -103,7 +102,7 @@ void RawSocketICMPTest::TearDown() {
// We'll only read an echo in this case, as the kernel won't respond to the
// malformed ICMP checksum.
TEST_F(RawSocketICMPTest, SendAndReceiveBadChecksum) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Prepare and send an ICMP packet. Use arbitrary junk for checksum, sequence,
// and ID. None of that should matter for raw sockets - the kernel should
@@ -132,7 +131,7 @@ TEST_F(RawSocketICMPTest, SendAndReceiveBadChecksum) {
// Send and receive an ICMP packet.
TEST_F(RawSocketICMPTest, SendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
// Prepare and send an ICMP packet. Use arbitrary junk for sequence and ID.
// None of that should matter for raw sockets - the kernel should still give
@@ -152,7 +151,7 @@ TEST_F(RawSocketICMPTest, SendAndReceive) {
// We should be able to create multiple raw sockets for the same protocol and
// receive the same packet on both.
TEST_F(RawSocketICMPTest, MultipleSocketReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
FileDescriptor s2 =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP));
@@ -215,7 +214,7 @@ TEST_F(RawSocketICMPTest, MultipleSocketReceive) {
// A raw ICMP socket and ping socket should both receive the ICMP packets
// intended for the ping socket.
TEST_F(RawSocketICMPTest, RawAndPingSockets) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
FileDescriptor ping_sock =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP));
@@ -265,7 +264,7 @@ TEST_F(RawSocketICMPTest, RawAndPingSockets) {
// while a ping socket should not. Neither should be able to receieve a short
// malformed packet.
TEST_F(RawSocketICMPTest, ShortEchoRawAndPingSockets) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
FileDescriptor ping_sock =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP));
@@ -306,7 +305,7 @@ TEST_F(RawSocketICMPTest, ShortEchoRawAndPingSockets) {
// while ping socket should not.
// Neither should be able to receieve a short malformed packet.
TEST_F(RawSocketICMPTest, ShortEchoReplyRawAndPingSockets) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
FileDescriptor ping_sock =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP));
@@ -345,7 +344,7 @@ TEST_F(RawSocketICMPTest, ShortEchoReplyRawAndPingSockets) {
// Test that connect() sends packets to the right place.
TEST_F(RawSocketICMPTest, SendAndReceiveViaConnect) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
connect(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
@@ -369,7 +368,7 @@ TEST_F(RawSocketICMPTest, SendAndReceiveViaConnect) {
// Bind to localhost, then send and receive packets.
TEST_F(RawSocketICMPTest, BindSendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
@@ -392,7 +391,7 @@ TEST_F(RawSocketICMPTest, BindSendAndReceive) {
// Bind and connect to localhost and send/receive packets.
TEST_F(RawSocketICMPTest, BindConnectSendAndReceive) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
ASSERT_THAT(
bind(s_, reinterpret_cast<struct sockaddr*>(&addr_), sizeof(addr_)),
@@ -418,7 +417,7 @@ TEST_F(RawSocketICMPTest, BindConnectSendAndReceive) {
// Set and get SO_LINGER.
TEST_F(RawSocketICMPTest, SetAndGetSocketLinger) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int level = SOL_SOCKET;
int type = SO_LINGER;
@@ -440,7 +439,7 @@ TEST_F(RawSocketICMPTest, SetAndGetSocketLinger) {
// Test getsockopt for SO_ACCEPTCONN.
TEST_F(RawSocketICMPTest, GetSocketAcceptConn) {
- SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
+ SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability()));
int got = -1;
socklen_t length = sizeof(got);
diff --git a/test/syscalls/linux/stat.cc b/test/syscalls/linux/stat.cc
index 72f888659..19dc80d0c 100644
--- a/test/syscalls/linux/stat.cc
+++ b/test/syscalls/linux/stat.cc
@@ -765,7 +765,7 @@ TEST_F(StatTest, StatxSymlink) {
SKIP_IF(!IsRunningOnGvisor() && statx(-1, nullptr, 0, 0, nullptr) < 0 &&
errno == ENOSYS);
- std::string parent_dir = "/tmp";
+ std::string parent_dir = GetAbsoluteTestTmpdir();
TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
TempPath::CreateSymlinkTo(parent_dir, test_file_name_));
std::string p = link.path();
diff --git a/test/syscalls/linux/statfs.cc b/test/syscalls/linux/statfs.cc
index d4ea8e026..d057cdc09 100644
--- a/test/syscalls/linux/statfs.cc
+++ b/test/syscalls/linux/statfs.cc
@@ -28,7 +28,7 @@ namespace testing {
namespace {
TEST(StatfsTest, CannotStatBadPath) {
- auto temp_file = NewTempAbsPathInDir("/tmp");
+ auto temp_file = NewTempAbsPath();
struct statfs st;
EXPECT_THAT(statfs(temp_file.c_str(), &st), SyscallFailsWithErrno(ENOENT));
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc
index cb77986c2..3fbbf1423 100644
--- a/test/syscalls/linux/tcp_socket.cc
+++ b/test/syscalls/linux/tcp_socket.cc
@@ -2088,6 +2088,66 @@ TEST_P(SimpleTcpSocketTest, ConnectUnspecifiedAddress) {
}
}
+// Tests that send will return EWOULDBLOCK initially with large buffer and will
+// succeed after the send buffer size is increased.
+TEST_P(TcpSocketTest, SendUnblocksOnSendBufferIncrease) {
+ // Set the FD to O_NONBLOCK.
+ int opts;
+ ASSERT_THAT(opts = fcntl(first_fd, F_GETFL), SyscallSucceeds());
+ opts |= O_NONBLOCK;
+ ASSERT_THAT(fcntl(first_fd, F_SETFL, opts), SyscallSucceeds());
+
+ // Get maximum buffer size by trying to set it to a large value.
+ constexpr int kSndBufSz = 0xffffffff;
+ ASSERT_THAT(setsockopt(first_fd, SOL_SOCKET, SO_SNDBUF, &kSndBufSz,
+ sizeof(kSndBufSz)),
+ SyscallSucceeds());
+
+ int max_buffer_sz = 0;
+ socklen_t max_len = sizeof(max_buffer_sz);
+ ASSERT_THAT(
+ getsockopt(first_fd, SOL_SOCKET, SO_SNDBUF, &max_buffer_sz, &max_len),
+ SyscallSucceeds());
+
+ int buffer_sz = max_buffer_sz >> 2;
+ EXPECT_THAT(setsockopt(first_fd, SOL_SOCKET, SO_SNDBUF, &buffer_sz,
+ sizeof(buffer_sz)),
+ SyscallSucceedsWithValue(0));
+
+ // Create a large buffer that will be used for sending.
+ std::vector<char> buffer(max_buffer_sz);
+
+ // Write until we receive an error.
+ while (RetryEINTR(send)(first_fd, buffer.data(), buffer.size(), 0) != -1) {
+ // Sleep to give linux a chance to move data from the send buffer to the
+ // receive buffer.
+ usleep(10000); // 10ms.
+ }
+
+ // The last error should have been EWOULDBLOCK.
+ ASSERT_EQ(errno, EWOULDBLOCK);
+
+ ScopedThread send_thread([this]() {
+ int flags = 0;
+ ASSERT_THAT(flags = fcntl(first_fd, F_GETFL), SyscallSucceeds());
+ EXPECT_THAT(fcntl(first_fd, F_SETFL, flags & ~O_NONBLOCK),
+ SyscallSucceeds());
+
+ // Expect the send() to succeed.
+ char buffer;
+ ASSERT_THAT(RetryEINTR(send)(first_fd, &buffer, sizeof(buffer), 0),
+ SyscallSucceeds());
+ });
+
+ // Set SO_SNDBUF to maximum buffer size allowed.
+ buffer_sz = max_buffer_sz >> 1;
+ EXPECT_THAT(setsockopt(first_fd, SOL_SOCKET, SO_SNDBUF, &buffer_sz,
+ sizeof(buffer_sz)),
+ SyscallSucceedsWithValue(0));
+
+ send_thread.Join();
+}
+
INSTANTIATE_TEST_SUITE_P(AllInetTests, SimpleTcpSocketTest,
::testing::Values(AF_INET, AF_INET6));