summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
authorJing Chen <chjing@google.com>2020-12-15 16:03:41 -0800
committergVisor bot <gvisor-bot@google.com>2020-12-15 16:06:06 -0800
commit1e56a2f9a29ff72eada493bf024a4e3fd5a963b6 (patch)
tree1daeb434caa26aa6abac08d21e583d90d8eb7d48 /test/syscalls
parent7aa674eb68e9b760ea72508dfb79a19dbf5b85ed (diff)
Implement command SEM_INFO and SEM_STAT for semctl.
PiperOrigin-RevId: 347711998
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/semaphore.cc182
1 files changed, 152 insertions, 30 deletions
diff --git a/test/syscalls/linux/semaphore.cc b/test/syscalls/linux/semaphore.cc
index fb4695e72..c2f080917 100644
--- a/test/syscalls/linux/semaphore.cc
+++ b/test/syscalls/linux/semaphore.cc
@@ -20,7 +20,7 @@
#include <atomic>
#include <cerrno>
#include <ctime>
-#include <stack>
+#include <set>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -32,10 +32,23 @@
#include "test/util/test_util.h"
#include "test/util/thread_util.h"
+using ::testing::Contains;
+
namespace gvisor {
namespace testing {
namespace {
+constexpr int kSemMap = 1024000000;
+constexpr int kSemMni = 32000;
+constexpr int kSemMns = 1024000000;
+constexpr int kSemMnu = 1024000000;
+constexpr int kSemMsl = 32000;
+constexpr int kSemOpm = 500;
+constexpr int kSemUme = 500;
+constexpr int kSemUsz = 20;
+constexpr int kSemVmx = 32767;
+constexpr int kSemAem = 32767;
+
class AutoSem {
public:
explicit AutoSem(int id) : id_(id) {}
@@ -775,42 +788,151 @@ TEST(SemaphoreTest, SemopGetncntOnSignal_NoRandomSave) {
}
TEST(SemaphoreTest, IpcInfo) {
- std::stack<int> sem_ids;
- std::stack<int> max_used_indexes;
+ constexpr int kLoops = 5;
+ std::set<int> sem_ids;
struct seminfo info;
- for (int i = 0; i < 3; i++) {
- int sem_id = 0;
- ASSERT_THAT(sem_id = semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT),
- SyscallSucceeds());
- sem_ids.push(sem_id);
- int max_used_index = 0;
- EXPECT_THAT(max_used_index = semctl(0, 0, IPC_INFO, &info),
- SyscallSucceeds());
- if (!max_used_indexes.empty()) {
- EXPECT_GT(max_used_index, max_used_indexes.top());
+ // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
+ ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
+ ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceedsWithValue(0));
+ for (int i = 0; i < kLoops; i++) {
+ AutoSem sem(semget(IPC_PRIVATE, 1, 0600 | IPC_CREAT));
+ ASSERT_THAT(sem.get(), SyscallSucceeds());
+ sem_ids.insert(sem.release());
+ }
+ ASSERT_EQ(sem_ids.size(), kLoops);
+
+ int max_used_index = 0;
+ EXPECT_THAT(max_used_index = semctl(0, 0, IPC_INFO, &info),
+ SyscallSucceeds());
+
+ int index_count = 0;
+ for (int i = 0; i <= max_used_index; i++) {
+ struct semid_ds ds = {};
+ int sem_id = semctl(i, 0, SEM_STAT, &ds);
+ // Only if index i is used within the registry.
+ if (sem_id != -1) {
+ ASSERT_THAT(sem_ids, Contains(sem_id));
+ struct semid_ds ipc_stat_ds;
+ ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds());
+ EXPECT_EQ(ds.sem_perm.__key, ipc_stat_ds.sem_perm.__key);
+ EXPECT_EQ(ds.sem_perm.uid, ipc_stat_ds.sem_perm.uid);
+ EXPECT_EQ(ds.sem_perm.gid, ipc_stat_ds.sem_perm.gid);
+ EXPECT_EQ(ds.sem_perm.cuid, ipc_stat_ds.sem_perm.cuid);
+ EXPECT_EQ(ds.sem_perm.cgid, ipc_stat_ds.sem_perm.cgid);
+ EXPECT_EQ(ds.sem_perm.mode, ipc_stat_ds.sem_perm.mode);
+ EXPECT_EQ(ds.sem_otime, ipc_stat_ds.sem_otime);
+ EXPECT_EQ(ds.sem_ctime, ipc_stat_ds.sem_ctime);
+ EXPECT_EQ(ds.sem_nsems, ipc_stat_ds.sem_nsems);
+
+ // Remove the semaphore set's read permission.
+ struct semid_ds ipc_set_ds;
+ ipc_set_ds.sem_perm.uid = getuid();
+ ipc_set_ds.sem_perm.gid = getgid();
+ // Keep the semaphore set's write permission so that it could be removed.
+ ipc_set_ds.sem_perm.mode = 0200;
+ ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds());
+ ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES));
+
+ index_count += 1;
}
- max_used_indexes.push(max_used_index);
}
- while (!sem_ids.empty()) {
- int sem_id = sem_ids.top();
- sem_ids.pop();
+ EXPECT_EQ(index_count, kLoops);
+ ASSERT_THAT(semctl(0, 0, IPC_INFO, &info),
+ SyscallSucceedsWithValue(max_used_index));
+ for (const int sem_id : sem_ids) {
ASSERT_THAT(semctl(sem_id, 0, IPC_RMID), SyscallSucceeds());
- int max_index = max_used_indexes.top();
- EXPECT_THAT(max_index = semctl(0, 0, IPC_INFO, &info), SyscallSucceeds());
- EXPECT_GE(max_used_indexes.top(), max_index);
- max_used_indexes.pop();
}
+
+ ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceedsWithValue(0));
+ EXPECT_EQ(info.semmap, kSemMap);
+ EXPECT_EQ(info.semmni, kSemMni);
+ EXPECT_EQ(info.semmns, kSemMns);
+ EXPECT_EQ(info.semmnu, kSemMnu);
+ EXPECT_EQ(info.semmsl, kSemMsl);
+ EXPECT_EQ(info.semopm, kSemOpm);
+ EXPECT_EQ(info.semume, kSemUme);
+ EXPECT_EQ(info.semusz, kSemUsz);
+ EXPECT_EQ(info.semvmx, kSemVmx);
+ EXPECT_EQ(info.semaem, kSemAem);
+}
+
+TEST(SemaphoreTest, SemInfo) {
+ constexpr int kLoops = 5;
+ constexpr int kSemSetSize = 3;
+ std::set<int> sem_ids;
+ struct seminfo info;
+ // Drop CAP_IPC_OWNER which allows us to bypass semaphore permissions.
+ ASSERT_NO_ERRNO(SetCapability(CAP_IPC_OWNER, false));
ASSERT_THAT(semctl(0, 0, IPC_INFO, &info), SyscallSucceedsWithValue(0));
+ for (int i = 0; i < kLoops; i++) {
+ AutoSem sem(semget(IPC_PRIVATE, kSemSetSize, 0600 | IPC_CREAT));
+ ASSERT_THAT(sem.get(), SyscallSucceeds());
+ sem_ids.insert(sem.release());
+ }
+ ASSERT_EQ(sem_ids.size(), kLoops);
+ int max_used_index = 0;
+ EXPECT_THAT(max_used_index = semctl(0, 0, SEM_INFO, &info),
+ SyscallSucceeds());
+ EXPECT_EQ(info.semmap, kSemMap);
+ EXPECT_EQ(info.semmni, kSemMni);
+ EXPECT_EQ(info.semmns, kSemMns);
+ EXPECT_EQ(info.semmnu, kSemMnu);
+ EXPECT_EQ(info.semmsl, kSemMsl);
+ EXPECT_EQ(info.semopm, kSemOpm);
+ EXPECT_EQ(info.semume, kSemUme);
+ EXPECT_EQ(info.semusz, sem_ids.size());
+ EXPECT_EQ(info.semvmx, kSemVmx);
+ EXPECT_EQ(info.semaem, sem_ids.size() * kSemSetSize);
+
+ int index_count = 0;
+ for (int i = 0; i <= max_used_index; i++) {
+ struct semid_ds ds = {};
+ int sem_id = semctl(i, 0, SEM_STAT, &ds);
+ // Only if index i is used within the registry.
+ if (sem_id != -1) {
+ ASSERT_THAT(sem_ids, Contains(sem_id));
+ struct semid_ds ipc_stat_ds;
+ ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds());
+ EXPECT_EQ(ds.sem_perm.__key, ipc_stat_ds.sem_perm.__key);
+ EXPECT_EQ(ds.sem_perm.uid, ipc_stat_ds.sem_perm.uid);
+ EXPECT_EQ(ds.sem_perm.gid, ipc_stat_ds.sem_perm.gid);
+ EXPECT_EQ(ds.sem_perm.cuid, ipc_stat_ds.sem_perm.cuid);
+ EXPECT_EQ(ds.sem_perm.cgid, ipc_stat_ds.sem_perm.cgid);
+ EXPECT_EQ(ds.sem_perm.mode, ipc_stat_ds.sem_perm.mode);
+ EXPECT_EQ(ds.sem_otime, ipc_stat_ds.sem_otime);
+ EXPECT_EQ(ds.sem_ctime, ipc_stat_ds.sem_ctime);
+ EXPECT_EQ(ds.sem_nsems, ipc_stat_ds.sem_nsems);
+
+ // Remove the semaphore set's read permission.
+ struct semid_ds ipc_set_ds;
+ ipc_set_ds.sem_perm.uid = getuid();
+ ipc_set_ds.sem_perm.gid = getgid();
+ // Keep the semaphore set's write permission so that it could be removed.
+ ipc_set_ds.sem_perm.mode = 0200;
+ ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds());
+ ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES));
+
+ index_count += 1;
+ }
+ }
+ EXPECT_EQ(index_count, kLoops);
+ ASSERT_THAT(semctl(0, 0, SEM_INFO, &info),
+ SyscallSucceedsWithValue(max_used_index));
+ for (const int sem_id : sem_ids) {
+ ASSERT_THAT(semctl(sem_id, 0, IPC_RMID), SyscallSucceeds());
+ }
- EXPECT_EQ(info.semmap, 1024000000);
- EXPECT_EQ(info.semmni, 32000);
- EXPECT_EQ(info.semmns, 1024000000);
- EXPECT_EQ(info.semmnu, 1024000000);
- EXPECT_EQ(info.semmsl, 32000);
- EXPECT_EQ(info.semopm, 500);
- EXPECT_EQ(info.semume, 500);
- EXPECT_EQ(info.semvmx, 32767);
- EXPECT_EQ(info.semaem, 32767);
+ ASSERT_THAT(semctl(0, 0, SEM_INFO, &info), SyscallSucceedsWithValue(0));
+ EXPECT_EQ(info.semmap, kSemMap);
+ EXPECT_EQ(info.semmni, kSemMni);
+ EXPECT_EQ(info.semmns, kSemMns);
+ EXPECT_EQ(info.semmnu, kSemMnu);
+ EXPECT_EQ(info.semmsl, kSemMsl);
+ EXPECT_EQ(info.semopm, kSemOpm);
+ EXPECT_EQ(info.semume, kSemUme);
+ EXPECT_EQ(info.semusz, 0);
+ EXPECT_EQ(info.semvmx, kSemVmx);
+ EXPECT_EQ(info.semaem, 0);
}
} // namespace