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 |