syscall_unittest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 24namespace sandbox { 25 26namespace { 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 31const int kMMapNr = __NR_mmap2; 32#else 33const int kMMapNr = __NR_mmap; 34#endif 35 36TEST(Syscall, InvalidCallReturnsENOSYS) { 37 EXPECT_EQ(-ENOSYS, Syscall::InvalidCall()); 38} 39 40TEST(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__) 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#else 65#warning Incomplete test case; need port for target platform 66#endif 67} 68 69TEST(Syscall, TrivialSyscallNoArgs) { 70 // Test that we can do basic system calls 71 EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid)); 72} 73 74TEST(Syscall, TrivialSyscallOneArg) { 75 int new_fd; 76 // Duplicate standard error and close it. 77 ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0); 78 int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd)); 79 ASSERT_EQ(close_return_value, 0); 80} 81 82TEST(Syscall, TrivialFailingSyscall) { 83 errno = -42; 84 int ret = Syscall::Call(__NR_dup, -1); 85 ASSERT_EQ(-EBADF, ret); 86 // Verify that Syscall::Call does not touch errno. 87 ASSERT_EQ(-42, errno); 88} 89 90// SIGSYS trap handler that will be called on __NR_uname. 91intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) { 92 // |aux| is our BPF_AUX pointer. 93 std::vector<uint64_t>* const seen_syscall_args = 94 static_cast<std::vector<uint64_t>*>(aux); 95 BPF_ASSERT(arraysize(args.args) == 6); 96 seen_syscall_args->assign(args.args, args.args + arraysize(args.args)); 97 return -ENOMEM; 98} 99 100ErrorCode CopyAllArgsOnUnamePolicy(SandboxBPF* sandbox, 101 int sysno, 102 std::vector<uint64_t>* aux) { 103 if (!SandboxBPF::IsValidSyscallNumber(sysno)) { 104 return ErrorCode(ENOSYS); 105 } 106 if (sysno == __NR_uname) { 107 return sandbox->Trap(CopySyscallArgsToAux, aux); 108 } else { 109 return ErrorCode(ErrorCode::ERR_ALLOWED); 110 } 111} 112 113// We are testing Syscall::Call() by making use of a BPF filter that 114// allows us 115// to inspect the system call arguments that the kernel saw. 116BPF_TEST(Syscall, 117 SyntheticSixArgs, 118 CopyAllArgsOnUnamePolicy, 119 std::vector<uint64_t> /* (*BPF_AUX) */) { 120 const int kExpectedValue = 42; 121 // In this test we only pass integers to the kernel. We might want to make 122 // additional tests to try other types. What we will see depends on 123 // implementation details of kernel BPF filters and we will need to document 124 // the expected behavior very clearly. 125 int syscall_args[6]; 126 for (size_t i = 0; i < arraysize(syscall_args); ++i) { 127 syscall_args[i] = kExpectedValue + i; 128 } 129 130 // We could use pretty much any system call we don't need here. uname() is 131 // nice because it doesn't have any dangerous side effects. 132 BPF_ASSERT(Syscall::Call(__NR_uname, 133 syscall_args[0], 134 syscall_args[1], 135 syscall_args[2], 136 syscall_args[3], 137 syscall_args[4], 138 syscall_args[5]) == -ENOMEM); 139 140 // We expect the trap handler to have copied the 6 arguments. 141 BPF_ASSERT(BPF_AUX->size() == 6); 142 143 // Don't loop here so that we can see which argument does cause the failure 144 // easily from the failing line. 145 // uint64_t is the type passed to our SIGSYS handler. 146 BPF_ASSERT((*BPF_AUX)[0] == static_cast<uint64_t>(syscall_args[0])); 147 BPF_ASSERT((*BPF_AUX)[1] == static_cast<uint64_t>(syscall_args[1])); 148 BPF_ASSERT((*BPF_AUX)[2] == static_cast<uint64_t>(syscall_args[2])); 149 BPF_ASSERT((*BPF_AUX)[3] == static_cast<uint64_t>(syscall_args[3])); 150 BPF_ASSERT((*BPF_AUX)[4] == static_cast<uint64_t>(syscall_args[4])); 151 BPF_ASSERT((*BPF_AUX)[5] == static_cast<uint64_t>(syscall_args[5])); 152} 153 154TEST(Syscall, ComplexSyscallSixArgs) { 155 int fd; 156 ASSERT_LE(0, fd = Syscall::Call(__NR_open, "/dev/null", O_RDWR, 0L)); 157 158 // Use mmap() to allocate some read-only memory 159 char* addr0; 160 ASSERT_NE( 161 (char*)NULL, 162 addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr, 163 (void*)NULL, 164 4096, 165 PROT_READ, 166 MAP_PRIVATE | MAP_ANONYMOUS, 167 fd, 168 0L))); 169 170 // Try to replace the existing mapping with a read-write mapping 171 char* addr1; 172 ASSERT_EQ(addr0, 173 addr1 = reinterpret_cast<char*>( 174 Syscall::Call(kMMapNr, 175 addr0, 176 4096L, 177 PROT_READ | PROT_WRITE, 178 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 179 fd, 180 0L))); 181 ++*addr1; // This should not seg fault 182 183 // Clean up 184 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L)); 185 EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd))); 186 187 // Check that the offset argument (i.e. the sixth argument) is processed 188 // correctly. 189 ASSERT_GE(fd = Syscall::Call(__NR_open, "/proc/self/exe", O_RDONLY, 0L), 0); 190 char* addr2, *addr3; 191 ASSERT_NE((char*)NULL, 192 addr2 = reinterpret_cast<char*>(Syscall::Call( 193 kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L))); 194 ASSERT_NE((char*)NULL, 195 addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr, 196 (void*)NULL, 197 4096L, 198 PROT_READ, 199 MAP_PRIVATE, 200 fd, 201#if defined(__NR_mmap2) 202 1L 203#else 204 4096L 205#endif 206 ))); 207 EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096)); 208 209 // Just to be absolutely on the safe side, also verify that the file 210 // contents matches what we are getting from a read() operation. 211 char buf[8192]; 212 EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L)); 213 EXPECT_EQ(0, memcmp(addr2, buf, 8192)); 214 215 // Clean up 216 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L)); 217 EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L)); 218 EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd))); 219} 220 221} // namespace 222 223} // namespace sandbox 224