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