1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sandbox/linux/seccomp-bpf/syscall.h"
6
7 #include <asm/unistd.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sys/mman.h>
13 #include <sys/syscall.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <vector>
18
19 #include "base/macros.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "build/build_config.h"
22 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
23 #include "sandbox/linux/bpf_dsl/policy.h"
24 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
25 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
26 #include "sandbox/linux/tests/unit_tests.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using sandbox::bpf_dsl::Allow;
30 using sandbox::bpf_dsl::ResultExpr;
31 using sandbox::bpf_dsl::Trap;
32
33 namespace sandbox {
34
35 namespace {
36
37 // Different platforms use different symbols for the six-argument version
38 // of the mmap() system call. Test for the correct symbol at compile time.
39 #ifdef __NR_mmap2
40 const int kMMapNr = __NR_mmap2;
41 #else
42 const int kMMapNr = __NR_mmap;
43 #endif
44
TEST(Syscall,InvalidCallReturnsENOSYS)45 TEST(Syscall, InvalidCallReturnsENOSYS) {
46 EXPECT_EQ(-ENOSYS, Syscall::InvalidCall());
47 }
48
TEST(Syscall,WellKnownEntryPoint)49 TEST(Syscall, WellKnownEntryPoint) {
50 // Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
51 // where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
52 // are still testing ARM code in the next set of tests.
53 #if !defined(__arm__) && !defined(__aarch64__)
54 EXPECT_NE(Syscall::Call(-1), syscall(-1));
55 #endif
56
57 // If possible, test that Syscall::Call(-1) returns the address right
58 // after
59 // a kernel entry point.
60 #if defined(__i386__)
61 EXPECT_EQ(0x80CDu, ((uint16_t*)Syscall::Call(-1))[-1]); // INT 0x80
62 #elif defined(__x86_64__)
63 EXPECT_EQ(0x050Fu, ((uint16_t*)Syscall::Call(-1))[-1]); // SYSCALL
64 #elif defined(__arm__)
65 #if defined(__thumb__)
66 EXPECT_EQ(0xDF00u, ((uint16_t*)Syscall::Call(-1))[-1]); // SWI 0
67 #else
68 EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]); // SVC 0
69 #endif
70 #elif defined(__mips__)
71 // Opcode for MIPS sycall is in the lower 16-bits
72 EXPECT_EQ(0x0cu, (((uint32_t*)Syscall::Call(-1))[-1]) & 0x0000FFFF);
73 #elif defined(__aarch64__)
74 EXPECT_EQ(0xD4000001u, ((uint32_t*)Syscall::Call(-1))[-1]); // SVC 0
75 #else
76 #warning Incomplete test case; need port for target platform
77 #endif
78 }
79
TEST(Syscall,TrivialSyscallNoArgs)80 TEST(Syscall, TrivialSyscallNoArgs) {
81 // Test that we can do basic system calls
82 EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid));
83 }
84
TEST(Syscall,TrivialSyscallOneArg)85 TEST(Syscall, TrivialSyscallOneArg) {
86 int new_fd;
87 // Duplicate standard error and close it.
88 ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0);
89 int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd));
90 ASSERT_EQ(close_return_value, 0);
91 }
92
TEST(Syscall,TrivialFailingSyscall)93 TEST(Syscall, TrivialFailingSyscall) {
94 errno = -42;
95 int ret = Syscall::Call(__NR_dup, -1);
96 ASSERT_EQ(-EBADF, ret);
97 // Verify that Syscall::Call does not touch errno.
98 ASSERT_EQ(-42, errno);
99 }
100
101 // SIGSYS trap handler that will be called on __NR_uname.
CopySyscallArgsToAux(const struct arch_seccomp_data & args,void * aux)102 intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) {
103 // |aux| is our BPF_AUX pointer.
104 std::vector<uint64_t>* const seen_syscall_args =
105 static_cast<std::vector<uint64_t>*>(aux);
106 BPF_ASSERT(arraysize(args.args) == 6);
107 seen_syscall_args->assign(args.args, args.args + arraysize(args.args));
108 return -ENOMEM;
109 }
110
111 class CopyAllArgsOnUnamePolicy : public bpf_dsl::Policy {
112 public:
CopyAllArgsOnUnamePolicy(std::vector<uint64_t> * aux)113 explicit CopyAllArgsOnUnamePolicy(std::vector<uint64_t>* aux) : aux_(aux) {}
~CopyAllArgsOnUnamePolicy()114 ~CopyAllArgsOnUnamePolicy() override {}
115
EvaluateSyscall(int sysno) const116 ResultExpr EvaluateSyscall(int sysno) const override {
117 DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
118 if (sysno == __NR_uname) {
119 return Trap(CopySyscallArgsToAux, aux_);
120 } else {
121 return Allow();
122 }
123 }
124
125 private:
126 std::vector<uint64_t>* aux_;
127
128 DISALLOW_COPY_AND_ASSIGN(CopyAllArgsOnUnamePolicy);
129 };
130
131 // We are testing Syscall::Call() by making use of a BPF filter that
132 // allows us
133 // to inspect the system call arguments that the kernel saw.
BPF_TEST(Syscall,SyntheticSixArgs,CopyAllArgsOnUnamePolicy,std::vector<uint64_t>)134 BPF_TEST(Syscall,
135 SyntheticSixArgs,
136 CopyAllArgsOnUnamePolicy,
137 std::vector<uint64_t> /* (*BPF_AUX) */) {
138 const int kExpectedValue = 42;
139 // In this test we only pass integers to the kernel. We might want to make
140 // additional tests to try other types. What we will see depends on
141 // implementation details of kernel BPF filters and we will need to document
142 // the expected behavior very clearly.
143 int syscall_args[6];
144 for (size_t i = 0; i < arraysize(syscall_args); ++i) {
145 syscall_args[i] = kExpectedValue + i;
146 }
147
148 // We could use pretty much any system call we don't need here. uname() is
149 // nice because it doesn't have any dangerous side effects.
150 BPF_ASSERT(Syscall::Call(__NR_uname,
151 syscall_args[0],
152 syscall_args[1],
153 syscall_args[2],
154 syscall_args[3],
155 syscall_args[4],
156 syscall_args[5]) == -ENOMEM);
157
158 // We expect the trap handler to have copied the 6 arguments.
159 BPF_ASSERT(BPF_AUX->size() == 6);
160
161 // Don't loop here so that we can see which argument does cause the failure
162 // easily from the failing line.
163 // uint64_t is the type passed to our SIGSYS handler.
164 BPF_ASSERT((*BPF_AUX)[0] == static_cast<uint64_t>(syscall_args[0]));
165 BPF_ASSERT((*BPF_AUX)[1] == static_cast<uint64_t>(syscall_args[1]));
166 BPF_ASSERT((*BPF_AUX)[2] == static_cast<uint64_t>(syscall_args[2]));
167 BPF_ASSERT((*BPF_AUX)[3] == static_cast<uint64_t>(syscall_args[3]));
168 BPF_ASSERT((*BPF_AUX)[4] == static_cast<uint64_t>(syscall_args[4]));
169 BPF_ASSERT((*BPF_AUX)[5] == static_cast<uint64_t>(syscall_args[5]));
170 }
171
TEST(Syscall,ComplexSyscallSixArgs)172 TEST(Syscall, ComplexSyscallSixArgs) {
173 int fd;
174 ASSERT_LE(0,
175 fd = Syscall::Call(__NR_openat, AT_FDCWD, "/dev/null", O_RDWR, 0L));
176
177 // Use mmap() to allocate some read-only memory
178 char* addr0;
179 ASSERT_NE(
180 (char*)NULL,
181 addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
182 (void*)NULL,
183 4096,
184 PROT_READ,
185 MAP_PRIVATE | MAP_ANONYMOUS,
186 fd,
187 0L)));
188
189 // Try to replace the existing mapping with a read-write mapping
190 char* addr1;
191 ASSERT_EQ(addr0,
192 addr1 = reinterpret_cast<char*>(
193 Syscall::Call(kMMapNr,
194 addr0,
195 4096L,
196 PROT_READ | PROT_WRITE,
197 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
198 fd,
199 0L)));
200 ++*addr1; // This should not seg fault
201
202 // Clean up
203 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L));
204 EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
205
206 // Check that the offset argument (i.e. the sixth argument) is processed
207 // correctly.
208 ASSERT_GE(
209 fd = Syscall::Call(__NR_openat, AT_FDCWD, "/proc/self/exe", O_RDONLY, 0L),
210 0);
211 char* addr2, *addr3;
212 ASSERT_NE((char*)NULL,
213 addr2 = reinterpret_cast<char*>(Syscall::Call(
214 kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L)));
215 ASSERT_NE((char*)NULL,
216 addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
217 (void*)NULL,
218 4096L,
219 PROT_READ,
220 MAP_PRIVATE,
221 fd,
222 #if defined(__NR_mmap2)
223 1L
224 #else
225 4096L
226 #endif
227 )));
228 EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
229
230 // Just to be absolutely on the safe side, also verify that the file
231 // contents matches what we are getting from a read() operation.
232 char buf[8192];
233 EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L));
234 EXPECT_EQ(0, memcmp(addr2, buf, 8192));
235
236 // Clean up
237 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L));
238 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L));
239 EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
240 }
241
242 } // namespace
243
244 } // namespace sandbox
245