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 <stdint.h> 9 10 namespace sandbox { 11 12 // We have to make sure that we have a single "magic" return address for 13 // our system calls, which we can check from within a BPF filter. This 14 // works by writing a little bit of asm() code that a) enters the kernel, and 15 // that also b) can be invoked in a way that computes this return address. 16 // Passing "nr" as "-1" computes the "magic" return address. Passing any 17 // other value invokes the appropriate system call. 18 intptr_t SandboxSyscall(int nr, 19 intptr_t p0, 20 intptr_t p1, 21 intptr_t p2, 22 intptr_t p3, 23 intptr_t p4, 24 intptr_t p5); 25 26 // System calls can take up to six parameters. Traditionally, glibc 27 // implements this property by using variadic argument lists. This works, but 28 // confuses modern tools such as valgrind, because we are nominally passing 29 // uninitialized data whenever we call through this function and pass less 30 // than the full six arguments. 31 // So, instead, we use C++'s template system to achieve a very similar 32 // effect. C++ automatically sets the unused parameters to zero for us, and 33 // it also does the correct type expansion (e.g. from 32bit to 64bit) where 34 // necessary. 35 // We have to use C-style cast operators as we want to be able to accept both 36 // integer and pointer types. 37 // We explicitly mark all functions as inline. This is not necessary in 38 // optimized builds, where the compiler automatically figures out that it 39 // can inline everything. But it makes stack traces of unoptimized builds 40 // easier to read as it hides implementation details. 41 #if __cplusplus >= 201103 // C++11 42 43 template <class T0 = intptr_t, 44 class T1 = intptr_t, 45 class T2 = intptr_t, 46 class T3 = intptr_t, 47 class T4 = intptr_t, 48 class T5 = intptr_t> 49 inline intptr_t SandboxSyscall(int nr, 50 T0 p0 = 0, 51 T1 p1 = 0, 52 T2 p2 = 0, 53 T3 p3 = 0, 54 T4 p4 = 0, 55 T5 p5 = 0) __attribute__((always_inline)); 56 57 template <class T0, class T1, class T2, class T3, class T4, class T5> 58 inline intptr_t 59 SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { 60 return SandboxSyscall(nr, 61 (intptr_t)p0, 62 (intptr_t)p1, 63 (intptr_t)p2, 64 (intptr_t)p3, 65 (intptr_t)p4, 66 (intptr_t)p5); 67 } 68 69 #else // Pre-C++11 70 71 // TODO(markus): C++11 has a much more concise and readable solution for 72 // expressing what we are doing here. Delete the fall-back code for older 73 // compilers as soon as we have fully switched to C++11 74 75 template <class T0, class T1, class T2, class T3, class T4, class T5> 76 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) 77 __attribute__((always_inline)); 78 template <class T0, class T1, class T2, class T3, class T4, class T5> 79 inline intptr_t 80 SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) { 81 return SandboxSyscall(nr, 82 (intptr_t)p0, 83 (intptr_t)p1, 84 (intptr_t)p2, 85 (intptr_t)p3, 86 (intptr_t)p4, 87 (intptr_t)p5); 88 } 89 90 template <class T0, class T1, class T2, class T3, class T4> 91 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) 92 __attribute__((always_inline)); 93 template <class T0, class T1, class T2, class T3, class T4> 94 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) { 95 return SandboxSyscall(nr, p0, p1, p2, p3, p4, 0); 96 } 97 98 template <class T0, class T1, class T2, class T3> 99 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3) 100 __attribute__((always_inline)); 101 template <class T0, class T1, class T2, class T3> 102 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3) { 103 return SandboxSyscall(nr, p0, p1, p2, p3, 0, 0); 104 } 105 106 template <class T0, class T1, class T2> 107 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2) 108 __attribute__((always_inline)); 109 template <class T0, class T1, class T2> 110 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2) { 111 return SandboxSyscall(nr, p0, p1, p2, 0, 0, 0); 112 } 113 114 template <class T0, class T1> 115 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1) 116 __attribute__((always_inline)); 117 template <class T0, class T1> 118 inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1) { 119 return SandboxSyscall(nr, p0, p1, 0, 0, 0, 0); 120 } 121 122 template <class T0> 123 inline intptr_t SandboxSyscall(int nr, T0 p0) __attribute__((always_inline)); 124 template <class T0> 125 inline intptr_t SandboxSyscall(int nr, T0 p0) { 126 return SandboxSyscall(nr, p0, 0, 0, 0, 0, 0); 127 } 128 129 inline intptr_t SandboxSyscall(int nr) __attribute__((always_inline)); 130 inline intptr_t SandboxSyscall(int nr) { 131 return SandboxSyscall(nr, 0, 0, 0, 0, 0, 0); 132 } 133 134 #endif // Pre-C++11 135 136 } // namespace sandbox 137 138 #endif // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__ 139