summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/BUILD4
-rw-r--r--test/syscalls/linux/cgroup.cc17
-rw-r--r--test/syscalls/linux/link.cc3
-rw-r--r--test/syscalls/linux/mmap.cc2
-rw-r--r--test/syscalls/linux/msgqueue.cc291
-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/proc_net.cc78
-rw-r--r--test/syscalls/linux/raw_socket.cc122
-rw-r--r--test/syscalls/linux/raw_socket_hdrincl.cc4
-rw-r--r--test/syscalls/linux/raw_socket_icmp.cc26
-rw-r--r--test/syscalls/linux/tcp_socket.cc60
13 files changed, 494 insertions, 192 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 960421466..01ee432cb 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -7,6 +7,8 @@ package(
exports_files(
[
+ "packet_socket.cc",
+ "packet_socket_raw.cc",
"raw_socket.cc",
"raw_socket_hdrincl.cc",
"raw_socket_icmp.cc",
@@ -1446,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",
@@ -1464,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",
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/mmap.cc b/test/syscalls/linux/mmap.cc
index caad575cf..fda176261 100644
--- a/test/syscalls/linux/mmap.cc
+++ b/test/syscalls/linux/mmap.cc
@@ -795,7 +795,7 @@ class MMapFileTest : public MMapTest {
bool FSSupportsMap() const {
bool supported = true;
- void* ret = mmap(nullptr, 1, PROT_NONE, 0, fd_.get(), 0);
+ void* ret = mmap(nullptr, 1, PROT_NONE, MAP_PRIVATE, fd_.get(), 0);
if (ret == MAP_FAILED && errno != ENODEV) {
supported = false;
}
diff --git a/test/syscalls/linux/msgqueue.cc b/test/syscalls/linux/msgqueue.cc
index 8994b739a..c4761eba8 100644
--- a/test/syscalls/linux/msgqueue.cc
+++ b/test/syscalls/linux/msgqueue.cc
@@ -30,9 +30,15 @@ namespace gvisor {
namespace testing {
namespace {
-constexpr int msgMax = 8192; // Max size for message in bytes.
+// Source: include/uapi/linux/msg.h
+constexpr int msgMnb = 16384; // Maximum number of bytes in a queue.
constexpr int msgMni = 32000; // Max number of identifiers.
-constexpr int msgMnb = 16384; // Default max size of message queue in bytes.
+constexpr int msgPool =
+ (msgMni * msgMnb / 1024); // Size of buffer pool used to hold message data.
+constexpr int msgMap = msgMnb; // Maximum number of entries in message map.
+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;
@@ -40,6 +46,10 @@ constexpr int kInterruptSignal = SIGALRM;
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;
@@ -90,8 +108,7 @@ TEST(MsgqueueTest, MsgGet) {
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()));
}
@@ -103,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;
@@ -138,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;
@@ -151,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;
@@ -166,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, ""};
@@ -184,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),
@@ -195,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),
@@ -208,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),
@@ -221,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.
@@ -248,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."}},
@@ -274,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.
@@ -298,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, ""};
@@ -311,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."};
@@ -340,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);
@@ -354,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."},
@@ -390,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));
@@ -406,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));
@@ -419,9 +415,7 @@ 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."};
ScopedThread t([&] {
@@ -441,9 +435,7 @@ TEST(MsgqueueTest, MsgRcvBlocking) {
// 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."},
@@ -471,9 +463,7 @@ TEST(MsgqueueTest, MsgRcvTypeBlocking) {
// Test msgsnd (most probably) blocking on a full queue.
TEST(MsgqueueTest, MsgSndBlocking) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
- ASSERT_THAT(queue.get(), SyscallSucceeds());
-
+ 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
@@ -512,8 +502,7 @@ TEST(MsgqueueTest, MsgSndBlocking) {
// 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));
// Number of messages that can be sent without blocking.
const size_t msgCount = msgMnb / msgMax;
@@ -549,8 +538,7 @@ TEST(MsgqueueTest, MsgSndRmWhileBlocking) {
// 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));
ScopedThread t([&] {
// Because we're repeating on EINTR, msgsnd may race with msgctl(IPC_RMID)
@@ -568,8 +556,7 @@ TEST(MsgqueueTest, MsgRcvRmWhileBlocking) {
// 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,
@@ -625,7 +612,7 @@ TEST(MsgqueueTest, MsgOpGeneral) {
void empty_sighandler(int sig, siginfo_t* info, void* context) {}
TEST(MsgqueueTest, InterruptRecv) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
+ Queue queue = ASSERT_NO_ERRNO_AND_VALUE(Msgget(IPC_PRIVATE, 0600));
char buf[64];
absl::Notification done, exit;
@@ -663,7 +650,7 @@ TEST(MsgqueueTest, InterruptRecv) {
}
TEST(MsgqueueTest, InterruptSend) {
- Queue queue(msgget(IPC_PRIVATE, 0600));
+ 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;
@@ -708,6 +695,178 @@ TEST(MsgqueueTest, InterruptSend) {
t.Join();
}
+// Test msgctl with IPC_STAT option.
+TEST(MsgqueueTest, MsgCtlIpcStat) {
+ auto start = absl::Now();
+
+ Queue queue(msgget(IPC_PRIVATE, 0600));
+ ASSERT_THAT(queue.get(), SyscallSucceeds());
+
+ const uid_t uid = getuid();
+ const gid_t gid = getgid();
+ const pid_t pid = getpid();
+
+ struct msqid_ds ds;
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+
+ EXPECT_EQ(ds.msg_perm.__key, IPC_PRIVATE);
+ EXPECT_EQ(ds.msg_perm.uid, uid);
+ EXPECT_EQ(ds.msg_perm.gid, gid);
+ EXPECT_EQ(ds.msg_perm.cuid, uid);
+ EXPECT_EQ(ds.msg_perm.cgid, gid);
+ EXPECT_EQ(ds.msg_perm.mode, 0600);
+
+ EXPECT_EQ(ds.msg_stime, 0);
+ EXPECT_EQ(ds.msg_rtime, 0);
+ EXPECT_GE(ds.msg_ctime, absl::ToTimeT(start));
+
+ EXPECT_EQ(ds.msg_cbytes, 0);
+ EXPECT_EQ(ds.msg_qnum, 0);
+ EXPECT_EQ(ds.msg_qbytes, msgMnb);
+ EXPECT_EQ(ds.msg_lspid, 0);
+ EXPECT_EQ(ds.msg_lrpid, 0);
+
+ // The timestamps only have a resolution of seconds; slow down so we actually
+ // see the timestamps change.
+ absl::SleepFor(absl::Seconds(1));
+ auto pre_send = absl::Now();
+
+ msgbuf buf{1, "A message."};
+ ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallSucceeds());
+
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+
+ EXPECT_GE(ds.msg_stime, absl::ToTimeT(pre_send));
+ EXPECT_EQ(ds.msg_rtime, 0);
+ EXPECT_GE(ds.msg_ctime, absl::ToTimeT(start));
+
+ EXPECT_EQ(ds.msg_cbytes, msgSize);
+ EXPECT_EQ(ds.msg_qnum, 1);
+ EXPECT_EQ(ds.msg_qbytes, msgMnb);
+ EXPECT_EQ(ds.msg_lspid, pid);
+ EXPECT_EQ(ds.msg_lrpid, 0);
+
+ absl::SleepFor(absl::Seconds(1));
+ auto pre_receive = absl::Now();
+
+ ASSERT_THAT(msgrcv(queue.get(), &buf, sizeof(buf.mtext), 0, 0),
+ SyscallSucceedsWithValue(msgSize));
+
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+
+ EXPECT_GE(ds.msg_stime, absl::ToTimeT(pre_send));
+ EXPECT_GE(ds.msg_rtime, absl::ToTimeT(pre_receive));
+ EXPECT_GE(ds.msg_ctime, absl::ToTimeT(start));
+
+ EXPECT_EQ(ds.msg_cbytes, 0);
+ EXPECT_EQ(ds.msg_qnum, 0);
+ EXPECT_EQ(ds.msg_qbytes, msgMnb);
+ EXPECT_EQ(ds.msg_lspid, pid);
+ EXPECT_EQ(ds.msg_lrpid, pid);
+}
+
+// Test msgctl with IPC_STAT option on a write-only queue.
+TEST(MsgqueueTest, MsgCtlIpcStatWriteOnly) {
+ // Drop CAP_IPC_OWNER which allows us to bypass permissions.
+ AutoCapability cap(CAP_IPC_OWNER, false);
+
+ Queue queue(msgget(IPC_PRIVATE, 0200));
+ ASSERT_THAT(queue.get(), SyscallSucceeds());
+
+ struct msqid_ds ds;
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds),
+ SyscallFailsWithErrno(EACCES));
+}
+
+// Test msgctl with IPC_SET option.
+TEST(MsgqueueTest, MsgCtlIpcSet) {
+ Queue queue(msgget(IPC_PRIVATE, 0600));
+ ASSERT_THAT(queue.get(), SyscallSucceeds());
+
+ struct msqid_ds ds;
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+ EXPECT_EQ(ds.msg_perm.mode, 0600);
+
+ ds.msg_perm.mode = 0777;
+ ASSERT_THAT(msgctl(queue.get(), IPC_SET, &ds), SyscallSucceeds());
+
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+ EXPECT_EQ(ds.msg_perm.mode, 0777);
+}
+
+// Test increasing msg_qbytes beyond limit with IPC_SET.
+TEST(MsgqueueTest, MsgCtlIpcSetMaxBytes) {
+ // Drop CAP_SYS_RESOURCE which allows us to increase msg_qbytes beyond the
+ // system parameter MSGMNB.
+ AutoCapability cap(CAP_SYS_RESOURCE, false);
+
+ Queue queue(msgget(IPC_PRIVATE, 0600));
+ ASSERT_THAT(queue.get(), SyscallSucceeds());
+
+ struct msqid_ds ds;
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+ EXPECT_EQ(ds.msg_qbytes, msgMnb);
+
+ ds.msg_qbytes = msgMnb - 10;
+ ASSERT_THAT(msgctl(queue.get(), IPC_SET, &ds), SyscallSucceeds());
+
+ ASSERT_THAT(msgctl(queue.get(), IPC_STAT, &ds), SyscallSucceeds());
+ EXPECT_EQ(ds.msg_qbytes, msgMnb - 10);
+
+ ds.msg_qbytes = msgMnb + 10;
+ EXPECT_THAT(msgctl(queue.get(), IPC_SET, &ds), SyscallFailsWithErrno(EPERM));
+}
+
+// Test msgctl with IPC_INFO option.
+TEST(MsgqueueTest, MsgCtlIpcInfo) {
+ struct msginfo info;
+ ASSERT_THAT(msgctl(0, IPC_INFO, reinterpret_cast<struct msqid_ds*>(&info)),
+ SyscallSucceeds());
+
+ EXPECT_GT(info.msgmax, 0);
+ EXPECT_GT(info.msgmni, 0);
+ EXPECT_GT(info.msgmnb, 0);
+ EXPECT_EQ(info.msgpool, msgPool);
+ EXPECT_EQ(info.msgmap, msgMap);
+ EXPECT_EQ(info.msgssz, msgSsz);
+ EXPECT_EQ(info.msgtql, msgTql);
+}
+
+// Test msgctl with MSG_INFO option.
+TEST(MsgqueueTest, MsgCtlMsgInfo) {
+ struct msginfo info;
+ ASSERT_THAT(msgctl(0, MSG_INFO, reinterpret_cast<struct msqid_ds*>(&info)),
+ SyscallSucceeds());
+
+ EXPECT_GT(info.msgmax, 0);
+ EXPECT_GT(info.msgmni, 0);
+ EXPECT_GT(info.msgmnb, 0);
+ EXPECT_EQ(info.msgpool, 0); // Number of queues in the system.
+ EXPECT_EQ(info.msgmap, 0); // Total number of messages in all queues.
+ EXPECT_EQ(info.msgtql, 0); // Total number of bytes in all messages.
+ EXPECT_EQ(info.msgssz, msgSsz);
+
+ // Add a queue and a message.
+ Queue queue(msgget(IPC_PRIVATE, 0600));
+ ASSERT_THAT(queue.get(), SyscallSucceeds());
+
+ msgbuf buf{1, "A message."};
+ ASSERT_THAT(msgsnd(queue.get(), &buf, sizeof(buf.mtext), 0),
+ SyscallSucceeds());
+
+ ASSERT_THAT(msgctl(0, MSG_INFO, reinterpret_cast<struct msqid_ds*>(&info)),
+ SyscallSucceeds());
+
+ EXPECT_GT(info.msgmax, 0);
+ EXPECT_GT(info.msgmni, 0);
+ EXPECT_GT(info.msgmnb, 0);
+ EXPECT_EQ(info.msgpool, 1); // Number of queues in the system.
+ EXPECT_EQ(info.msgmap, 1); // Total number of messages in all queues.
+ EXPECT_EQ(info.msgtql, msgSize); // Total number of bytes in all messages.
+ EXPECT_EQ(info.msgssz, msgSsz);
+}
+
} // namespace
} // namespace testing
} // namespace gvisor
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/proc_net.cc b/test/syscalls/linux/proc_net.cc
index 4cbe30fc1..672f2dd42 100644
--- a/test/syscalls/linux/proc_net.cc
+++ b/test/syscalls/linux/proc_net.cc
@@ -152,6 +152,37 @@ 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;
+}
+
+// GetSNMPMetricFromProc retrieves the metric named `item` of `type` from the
+// `snmp` string which represents the file contents of /proc/net/snmp.
+//
+// Note to test writers: If you are writing tests to check the change in value
+// of SNMP metrics, note that if GetMibsAllocationSysctl() == 0
+// (net.core.mibs_allocation isn't set), MIB is from the init network namespace
+// and hence these metrics can have system-wide noise.
+//
+// A feasible way of testing is the following:
+// * Consult RFC 1213 to learn the "SYNTAX" of the metric.
+// * If net.core.mibs_allocation is set:
+// - Can test any metric while checking for hard equality.
+// * If net.core.mibs_allocation is NOT set (system-wide noise is present):
+// - Only test "SYNTAX Counter" metrics.
+// - Counter metrics are increasing in nature, so use LE/GE equality checks.
PosixErrorOr<uint64_t> GetSNMPMetricFromProc(const std::string snmp,
const std::string& type,
const std::string& item) {
@@ -226,12 +257,25 @@ 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 + 1, newActiveOpens);
+ EXPECT_EQ(oldOutRsts + 1, newOutRsts);
+ EXPECT_EQ(oldAttemptFails + 1, newAttemptFails);
+ } else {
+ // System-wide statistics can have some noise. These metrics should have
+ // increased by at least 1.
+ EXPECT_LE(oldActiveOpens + 1, newActiveOpens);
+ EXPECT_LE(oldOutRsts + 1, newOutRsts);
+ EXPECT_LE(oldAttemptFails + 1, newAttemptFails);
+ }
}
TEST(ProcNetSnmp, TcpEstab) {
+ // This test aims to test the tcpCurrEstab metric which has "SYNTAX Gauge" as
+ // per RFC 1213. Hence, it becomes infeasible to test this when system-wide
+ // statistics have noise.
+ SKIP_IF(GetMibsAllocationSysctl() == 0);
+
// TODO(gvisor.dev/issue/866): epsocket metrics are not savable.
DisableSave ds;
@@ -286,9 +330,9 @@ TEST(ProcNetSnmp, TcpEstab) {
newCurrEstab = ASSERT_NO_ERRNO_AND_VALUE(
GetSNMPMetricFromProc(snmp, "Tcp", "CurrEstab"));
- EXPECT_EQ(oldActiveOpens, newActiveOpens - 1);
- EXPECT_EQ(oldPassiveOpens, newPassiveOpens - 1);
- EXPECT_EQ(oldCurrEstab, newCurrEstab - 2);
+ EXPECT_EQ(oldActiveOpens + 1, newActiveOpens);
+ EXPECT_EQ(oldPassiveOpens + 1, newPassiveOpens);
+ EXPECT_EQ(oldCurrEstab + 2, newCurrEstab);
// Send 1 byte from client to server.
ASSERT_THAT(send(s_connect.get(), "a", 1, 0), SyscallSucceedsWithValue(1));
@@ -355,8 +399,15 @@ 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 + 1, newOutDatagrams);
+ EXPECT_EQ(oldNoPorts + 1, newNoPorts);
+ } else {
+ // System-wide statistics can have some noise. These metrics should have
+ // increased by at least 1.
+ EXPECT_LE(oldOutDatagrams + 1, newOutDatagrams);
+ EXPECT_LE(oldNoPorts + 1, newNoPorts);
+ }
}
TEST(ProcNetSnmp, UdpIn) {
@@ -405,8 +456,15 @@ 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 + 1, newOutDatagrams);
+ EXPECT_EQ(oldInDatagrams + 1, newInDatagrams);
+ } else {
+ // System-wide statistics can have some noise. These metrics should have
+ // increased by at least 1.
+ EXPECT_LE(oldOutDatagrams + 1, newOutDatagrams);
+ EXPECT_LE(oldInDatagrams + 1, newInDatagrams);
+ }
}
TEST(ProcNetSnmp, CheckNetStat) {
diff --git a/test/syscalls/linux/raw_socket.cc b/test/syscalls/linux/raw_socket.cc
index 4e69e389b..66f0e6ca4 100644
--- a/test/syscalls/linux/raw_socket.cc
+++ b/test/syscalls/linux/raw_socket.cc
@@ -97,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();
@@ -121,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());
}
}
@@ -130,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());
@@ -140,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));
@@ -148,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()),
@@ -163,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()),
@@ -180,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;
@@ -195,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());
@@ -219,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());
@@ -244,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);
@@ -254,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()),
@@ -268,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_;
@@ -278,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.
@@ -289,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.
@@ -304,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()),
@@ -313,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";
@@ -323,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 = {};
@@ -344,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) {
@@ -365,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";
@@ -386,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());
@@ -401,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());
@@ -413,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()),
@@ -432,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";
@@ -450,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());
@@ -472,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:
@@ -505,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;
@@ -532,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;
@@ -582,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;
@@ -613,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;
@@ -640,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;
@@ -686,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());
@@ -717,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);
}
{
@@ -732,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);
}
}
@@ -748,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());
@@ -812,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
@@ -883,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),
@@ -900,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),
@@ -928,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 e54d781c9..d45bd07bc 100644
--- a/test/syscalls/linux/raw_socket_hdrincl.cc
+++ b/test/syscalls/linux/raw_socket_hdrincl.cc
@@ -62,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();
@@ -80,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 80a524273..3f9717284 100644
--- a/test/syscalls/linux/raw_socket_icmp.cc
+++ b/test/syscalls/linux/raw_socket_icmp.cc
@@ -76,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();
@@ -94,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());
}
}
@@ -102,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
@@ -131,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
@@ -151,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));
@@ -214,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));
@@ -264,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));
@@ -305,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));
@@ -344,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_)),
@@ -368,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_)),
@@ -391,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_)),
@@ -417,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;
@@ -439,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/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));