diff options
Diffstat (limited to 'test/syscalls/linux/rseq/rseq.cc')
-rw-r--r-- | test/syscalls/linux/rseq/rseq.cc | 377 |
1 files changed, 0 insertions, 377 deletions
diff --git a/test/syscalls/linux/rseq/rseq.cc b/test/syscalls/linux/rseq/rseq.cc deleted file mode 100644 index 6f5d38bba..000000000 --- a/test/syscalls/linux/rseq/rseq.cc +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "test/syscalls/linux/rseq/critical.h" -#include "test/syscalls/linux/rseq/syscalls.h" -#include "test/syscalls/linux/rseq/test.h" -#include "test/syscalls/linux/rseq/types.h" -#include "test/syscalls/linux/rseq/uapi.h" - -namespace gvisor { -namespace testing { - -extern "C" int main(int argc, char** argv, char** envp); - -// Standalone initialization before calling main(). -extern "C" void __init(uintptr_t* sp) { - int argc = sp[0]; - char** argv = reinterpret_cast<char**>(&sp[1]); - char** envp = &argv[argc + 1]; - - // Call main() and exit. - sys_exit_group(main(argc, argv, envp)); - - // sys_exit_group does not return -} - -int strcmp(const char* s1, const char* s2) { - const unsigned char* p1 = reinterpret_cast<const unsigned char*>(s1); - const unsigned char* p2 = reinterpret_cast<const unsigned char*>(s2); - - while (*p1 == *p2) { - if (!*p1) { - return 0; - } - ++p1; - ++p2; - } - return static_cast<int>(*p1) - static_cast<int>(*p2); -} - -int sys_rseq(struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) { - return raw_syscall(kRseqSyscall, rseq, rseq_len, flags, sig); -} - -// Test that rseq must be aligned. -int TestUnaligned() { - constexpr uintptr_t kRequiredAlignment = alignof(rseq); - - char buf[2 * kRequiredAlignment] = {}; - uintptr_t ptr = reinterpret_cast<uintptr_t>(&buf[0]); - if ((ptr & (kRequiredAlignment - 1)) == 0) { - // buf is already aligned. Misalign it. - ptr++; - } - - int ret = sys_rseq(reinterpret_cast<rseq*>(ptr), sizeof(rseq), 0, 0); - if (sys_errno(ret) != EINVAL) { - return 1; - } - return 0; -} - -// Sanity test that registration works. -int TestRegister() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - return 0; -} - -// Registration can't be done twice. -int TestDoubleRegister() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != EBUSY) { - return 1; - } - - return 0; -} - -// Registration can be done again after unregister. -int TestRegisterUnregister() { - struct rseq r = {}; - - int ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - ret = sys_rseq(&r, sizeof(r), kRseqFlagUnregister, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - return 0; -} - -// The pointer to rseq must match on register/unregister. -int TestUnregisterDifferentPtr() { - struct rseq r = {}; - - int ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq r2 = {}; - - ret = sys_rseq(&r2, sizeof(r2), kRseqFlagUnregister, 0); - if (sys_errno(ret) != EINVAL) { - return 1; - } - - return 0; -} - -// The signature must match on register/unregister. -int TestUnregisterDifferentSignature() { - constexpr int kSignature = 0; - - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kSignature); - if (sys_errno(ret) != 0) { - return 1; - } - - ret = sys_rseq(&r, sizeof(r), kRseqFlagUnregister, kSignature + 1); - if (sys_errno(ret) != EPERM) { - return 1; - } - - return 0; -} - -// The CPU ID is initialized. -int TestCPU() { - struct rseq r = {}; - r.cpu_id = kRseqCPUIDUninitialized; - - int ret = sys_rseq(&r, sizeof(r), 0, 0); - if (sys_errno(ret) != 0) { - return 1; - } - - if (__atomic_load_n(&r.cpu_id, __ATOMIC_RELAXED) < 0) { - return 1; - } - if (__atomic_load_n(&r.cpu_id_start, __ATOMIC_RELAXED) < 0) { - return 1; - } - - return 0; -} - -// Critical section is eventually aborted. -int TestAbort() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_abort); - - // Loops until abort. If this returns then abort occurred. - rseq_loop(&r, &cs); - - return 0; -} - -// Abort may be before the critical section. -int TestAbortBefore() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_early_abort); - - // Loops until abort. If this returns then abort occurred. - rseq_loop(&r, &cs); - - return 0; -} - -// Signature must match. -int TestAbortSignature() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature + 1); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_abort); - - // Loops until abort. This should SIGSEGV on abort. - rseq_loop(&r, &cs); - - return 1; -} - -// Abort must not be in the critical section. -int TestAbortPreCommit() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature + 1); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_pre_commit); - - // Loops until abort. This should SIGSEGV on abort. - rseq_loop(&r, &cs); - - return 1; -} - -// rseq.rseq_cs is cleared on abort. -int TestAbortClearsCS() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_abort); - - // Loops until abort. If this returns then abort occurred. - rseq_loop(&r, &cs); - - if (__atomic_load_n(&r.rseq_cs, __ATOMIC_RELAXED)) { - return 1; - } - - return 0; -} - -// rseq.rseq_cs is cleared on abort outside of critical section. -int TestInvalidAbortClearsCS() { - struct rseq r = {}; - int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature); - if (sys_errno(ret) != 0) { - return 1; - } - - struct rseq_cs cs = {}; - cs.version = 0; - cs.flags = 0; - cs.start_ip = reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.post_commit_offset = reinterpret_cast<uint64_t>(&rseq_loop_post_commit) - - reinterpret_cast<uint64_t>(&rseq_loop_start); - cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_abort); - - __atomic_store_n(&r.rseq_cs, &cs, __ATOMIC_RELAXED); - - // When the next abort condition occurs, the kernel will clear cs once it - // determines we aren't in the critical section. - while (1) { - if (!__atomic_load_n(&r.rseq_cs, __ATOMIC_RELAXED)) { - break; - } - } - - return 0; -} - -// Exit codes: -// 0 - Pass -// 1 - Fail -// 2 - Missing argument -// 3 - Unknown test case -extern "C" int main(int argc, char** argv, char** envp) { - if (argc != 2) { - // Usage: rseq <test case> - return 2; - } - - if (strcmp(argv[1], kRseqTestUnaligned) == 0) { - return TestUnaligned(); - } - if (strcmp(argv[1], kRseqTestRegister) == 0) { - return TestRegister(); - } - if (strcmp(argv[1], kRseqTestDoubleRegister) == 0) { - return TestDoubleRegister(); - } - if (strcmp(argv[1], kRseqTestRegisterUnregister) == 0) { - return TestRegisterUnregister(); - } - if (strcmp(argv[1], kRseqTestUnregisterDifferentPtr) == 0) { - return TestUnregisterDifferentPtr(); - } - if (strcmp(argv[1], kRseqTestUnregisterDifferentSignature) == 0) { - return TestUnregisterDifferentSignature(); - } - if (strcmp(argv[1], kRseqTestCPU) == 0) { - return TestCPU(); - } - if (strcmp(argv[1], kRseqTestAbort) == 0) { - return TestAbort(); - } - if (strcmp(argv[1], kRseqTestAbortBefore) == 0) { - return TestAbortBefore(); - } - if (strcmp(argv[1], kRseqTestAbortSignature) == 0) { - return TestAbortSignature(); - } - if (strcmp(argv[1], kRseqTestAbortPreCommit) == 0) { - return TestAbortPreCommit(); - } - if (strcmp(argv[1], kRseqTestAbortClearsCS) == 0) { - return TestAbortClearsCS(); - } - if (strcmp(argv[1], kRseqTestInvalidAbortClearsCS) == 0) { - return TestInvalidAbortClearsCS(); - } - - return 3; -} - -} // namespace testing -} // namespace gvisor |