xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/regs_test.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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