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 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__ 6 #define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__ 7 8 #include <signal.h> 9 #include <stdint.h> 10 11 #include "base/macros.h" 12 #include "sandbox/sandbox_export.h" 13 14 // Android's signal.h doesn't define ucontext etc. 15 #if defined(OS_ANDROID) 16 #include "sandbox/linux/services/android_ucontext.h" 17 #endif 18 19 namespace sandbox { 20 21 // This purely static class can be used to perform system calls with some 22 // low-level control. 23 class SANDBOX_EXPORT Syscall { 24 public: 25 // InvalidCall() invokes Call() with a platform-appropriate syscall 26 // number that is guaranteed to not be implemented (i.e., normally 27 // returns -ENOSYS). 28 // This is primarily meant to be useful for writing sandbox policy 29 // unit tests. 30 static intptr_t InvalidCall(); 31 32 // System calls can take up to six parameters (up to eight on some 33 // architectures). Traditionally, glibc 34 // implements this property by using variadic argument lists. This works, but 35 // confuses modern tools such as valgrind, because we are nominally passing 36 // uninitialized data whenever we call through this function and pass less 37 // than the full six arguments. 38 // So, instead, we use C++'s template system to achieve a very similar 39 // effect. C++ automatically sets the unused parameters to zero for us, and 40 // it also does the correct type expansion (e.g. from 32bit to 64bit) where 41 // necessary. 42 // We have to use C-style cast operators as we want to be able to accept both 43 // integer and pointer types. 44 template <class T0, 45 class T1, 46 class T2, 47 class T3, 48 class T4, 49 class T5, 50 class T6, 51 class T7> 52 static inline intptr_t Call(int nr,T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6,T7 p7)53 Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) { 54 return Call(nr, 55 (intptr_t)p0, 56 (intptr_t)p1, 57 (intptr_t)p2, 58 (intptr_t)p3, 59 (intptr_t)p4, 60 (intptr_t)p5, 61 (intptr_t)p6, 62 (intptr_t)p7); 63 } 64 65 template <class T0, 66 class T1, 67 class T2, 68 class T3, 69 class T4, 70 class T5, 71 class T6> 72 static inline intptr_t Call(int nr,T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5,T6 p6)73 Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) { 74 return Call(nr, 75 (intptr_t)p0, 76 (intptr_t)p1, 77 (intptr_t)p2, 78 (intptr_t)p3, 79 (intptr_t)p4, 80 (intptr_t)p5, 81 (intptr_t)p6, 82 0); 83 } 84 85 template <class T0, class T1, class T2, class T3, class T4, class T5> 86 static inline intptr_t Call(int nr,T0 p0,T1 p1,T2 p2,T3 p3,T4 p4,T5 p5)87 Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { 88 return Call(nr, 89 (intptr_t)p0, 90 (intptr_t)p1, 91 (intptr_t)p2, 92 (intptr_t)p3, 93 (intptr_t)p4, 94 (intptr_t)p5, 95 0, 96 0); 97 } 98 99 template <class T0, class T1, class T2, class T3, class T4> Call(int nr,T0 p0,T1 p1,T2 p2,T3 p3,T4 p4)100 static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) { 101 return Call(nr, p0, p1, p2, p3, p4, 0, 0, 0); 102 } 103 104 template <class T0, class T1, class T2, class T3> Call(int nr,T0 p0,T1 p1,T2 p2,T3 p3)105 static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) { 106 return Call(nr, p0, p1, p2, p3, 0, 0, 0, 0); 107 } 108 109 template <class T0, class T1, class T2> Call(int nr,T0 p0,T1 p1,T2 p2)110 static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) { 111 return Call(nr, p0, p1, p2, 0, 0, 0, 0, 0); 112 } 113 114 template <class T0, class T1> Call(int nr,T0 p0,T1 p1)115 static inline intptr_t Call(int nr, T0 p0, T1 p1) { 116 return Call(nr, p0, p1, 0, 0, 0, 0, 0, 0); 117 } 118 119 template <class T0> Call(int nr,T0 p0)120 static inline intptr_t Call(int nr, T0 p0) { 121 return Call(nr, p0, 0, 0, 0, 0, 0, 0, 0); 122 } 123 Call(int nr)124 static inline intptr_t Call(int nr) { 125 return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0); 126 } 127 128 // Set the registers in |ctx| to match what they would be after a system call 129 // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention 130 // of being -errno on errors. 131 static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx); 132 133 private: 134 // This performs system call |nr| with the arguments p0 to p7 from a constant 135 // userland address, which is for instance observable by seccomp-bpf filters. 136 // The constant userland address from which these system calls are made will 137 // be returned if |nr| is passed as -1. 138 // On error, this function will return a value between -1 and -4095 which 139 // should be interpreted as -errno. 140 static intptr_t Call(int nr, 141 intptr_t p0, 142 intptr_t p1, 143 intptr_t p2, 144 intptr_t p3, 145 intptr_t p4, 146 intptr_t p5, 147 intptr_t p6, 148 intptr_t p7); 149 150 #if defined(__mips__) 151 // This function basically does on MIPS what SandboxSyscall() is doing on 152 // other architectures. However, because of specificity of MIPS regarding 153 // handling syscall errors, SandboxSyscall() is made as a wrapper for this 154 // function in order for SandboxSyscall() to behave more like on other 155 // architectures on places where return value from SandboxSyscall() is used 156 // directly (like in most tests). 157 // The syscall "nr" is called with arguments that are set in an array on which 158 // pointer "args" points to and an information weather there is an error or no 159 // is returned to SandboxSyscall() by err_stat. 160 static intptr_t SandboxSyscallRaw(int nr, 161 const intptr_t* args, 162 intptr_t* err_stat); 163 #endif // defined(__mips__) 164 165 DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall); 166 }; 167 168 } // namespace sandbox 169 170 #endif // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__ 171