1*ec63e07aSXin Li #include "sandboxed_api/sandbox2/regs.h"
2*ec63e07aSXin Li
3*ec63e07aSXin Li #include <linux/filter.h>
4*ec63e07aSXin Li #include <linux/seccomp.h>
5*ec63e07aSXin Li #include <sys/prctl.h>
6*ec63e07aSXin Li #include <sys/ptrace.h>
7*ec63e07aSXin Li #include <sys/socket.h>
8*ec63e07aSXin Li #include <sys/wait.h>
9*ec63e07aSXin Li #include <syscall.h>
10*ec63e07aSXin Li #include <unistd.h>
11*ec63e07aSXin Li
12*ec63e07aSXin Li #include <cerrno>
13*ec63e07aSXin Li #include <cstdint>
14*ec63e07aSXin Li #include <cstdlib>
15*ec63e07aSXin Li #include <vector>
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include "gmock/gmock.h"
18*ec63e07aSXin Li #include "gtest/gtest.h"
19*ec63e07aSXin Li #include "absl/log/check.h"
20*ec63e07aSXin Li #include "sandboxed_api/config.h"
21*ec63e07aSXin Li #include "sandboxed_api/sandbox2/sanitizer.h"
22*ec63e07aSXin Li #include "sandboxed_api/sandbox2/syscall.h"
23*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
24*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
25*ec63e07aSXin Li #include "sandboxed_api/util/status_matchers.h"
26*ec63e07aSXin Li
27*ec63e07aSXin Li namespace sandbox2 {
28*ec63e07aSXin Li namespace {
29*ec63e07aSXin Li
30*ec63e07aSXin Li using ::sapi::IsOk;
31*ec63e07aSXin Li
32*ec63e07aSXin Li #define __WPTRACEEVENT(x) ((x & 0xff0000) >> 16)
33*ec63e07aSXin Li
TEST(RegsTest,SkipSyscallWorks)34*ec63e07aSXin Li TEST(RegsTest, SkipSyscallWorks) {
35*ec63e07aSXin Li std::vector<sock_filter> policy = {
36*ec63e07aSXin Li LOAD_SYSCALL_NR,
37*ec63e07aSXin Li JEQ32(__NR_getpid, TRACE(0)),
38*ec63e07aSXin Li ALLOW,
39*ec63e07aSXin Li };
40*ec63e07aSXin Li sock_fprog prog = {
41*ec63e07aSXin Li .len = static_cast<uint8_t>(policy.size()),
42*ec63e07aSXin Li .filter = policy.data(),
43*ec63e07aSXin Li };
44*ec63e07aSXin Li // Create socketpair for synchronization
45*ec63e07aSXin Li int sv[2];
46*ec63e07aSXin Li ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
47*ec63e07aSXin Li // Fork a child process to run the syscalls in.
48*ec63e07aSXin Li pid_t ppid = util::Syscall(__NR_gettid);
49*ec63e07aSXin Li pid_t pid = fork();
50*ec63e07aSXin Li ASSERT_NE(pid, -1);
51*ec63e07aSXin Li char c = 'C';
52*ec63e07aSXin Li if (pid == 0) {
53*ec63e07aSXin Li // Get ready for being ptraced.
54*ec63e07aSXin Li sanitizer::WaitForSanitizer();
55*ec63e07aSXin Li CHECK_EQ(prctl(PR_SET_DUMPABLE, 1), 0);
56*ec63e07aSXin Li prctl(PR_SET_PTRACER, ppid);
57*ec63e07aSXin Li CHECK_EQ(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), 0);
58*ec63e07aSXin Li CHECK_EQ(prctl(PR_SET_KEEPCAPS, 0), 0);
59*ec63e07aSXin Li // Notify parent that we're ready for ptrace.
60*ec63e07aSXin Li CHECK_EQ(write(sv[0], &c, 1), 1);
61*ec63e07aSXin Li // Apply seccomp policy
62*ec63e07aSXin Li CHECK_EQ(util::Syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 0,
63*ec63e07aSXin Li reinterpret_cast<uintptr_t>(&prog)),
64*ec63e07aSXin Li 0);
65*ec63e07aSXin Li // Wait for tracer to be attached.
66*ec63e07aSXin Li CHECK_EQ(read(sv[0], &c, 1), 1);
67*ec63e07aSXin Li // Run the test syscall
68*ec63e07aSXin Li errno = 0;
69*ec63e07aSXin Li util::Syscall(__NR_getpid, 123, reinterpret_cast<uintptr_t>(&c), 1);
70*ec63e07aSXin Li _Exit(errno == ENOENT ? 0 : 1);
71*ec63e07aSXin Li }
72*ec63e07aSXin Li // Wait for child to be ready for ptrace
73*ec63e07aSXin Li ASSERT_EQ(read(sv[1], &c, 1), 1);
74*ec63e07aSXin Li ASSERT_EQ(ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACESECCOMP), 0);
75*ec63e07aSXin Li // Notify child it has been ptraced.
76*ec63e07aSXin Li ASSERT_EQ(write(sv[1], &c, 1), 1);
77*ec63e07aSXin Li // Wait for seccomp TRACE stop
78*ec63e07aSXin Li int status;
79*ec63e07aSXin Li ASSERT_EQ(waitpid(pid, &status, __WNOTHREAD | __WALL | WUNTRACED), pid);
80*ec63e07aSXin Li ASSERT_TRUE(WIFSTOPPED(status));
81*ec63e07aSXin Li ASSERT_EQ(__WPTRACEEVENT(status), PTRACE_EVENT_SECCOMP);
82*ec63e07aSXin Li // Fetch the registers
83*ec63e07aSXin Li Regs regs(pid);
84*ec63e07aSXin Li ASSERT_THAT(regs.Fetch(), IsOk());
85*ec63e07aSXin Li // Check syscall arguments
86*ec63e07aSXin Li Syscall syscall = regs.ToSyscall(sapi::host_cpu::Architecture());
87*ec63e07aSXin Li EXPECT_EQ(syscall.nr(), __NR_getpid);
88*ec63e07aSXin Li EXPECT_EQ(syscall.args()[0], 123);
89*ec63e07aSXin Li EXPECT_EQ(syscall.args()[1], reinterpret_cast<uintptr_t>(&c));
90*ec63e07aSXin Li EXPECT_EQ(syscall.args()[2], 1);
91*ec63e07aSXin Li // Skip syscall
92*ec63e07aSXin Li ASSERT_THAT(regs.SkipSyscallReturnValue(-ENOENT), IsOk());
93*ec63e07aSXin Li // Continue&detach the child process
94*ec63e07aSXin Li ASSERT_EQ(ptrace(PTRACE_DETACH, pid, 0, 0), 0);
95*ec63e07aSXin Li // Wait for the child to exit
96*ec63e07aSXin Li ASSERT_EQ(waitpid(pid, &status, __WNOTHREAD | __WALL | WUNTRACED), pid);
97*ec63e07aSXin Li ASSERT_TRUE(WIFEXITED(status));
98*ec63e07aSXin Li EXPECT_EQ(WEXITSTATUS(status), 0);
99*ec63e07aSXin Li }
100*ec63e07aSXin Li
101*ec63e07aSXin Li } // namespace
102*ec63e07aSXin Li } // namespace sandbox2
103