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