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_SANDBOX_BPF_H__ | 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ | 6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <sys/types.h> | 9 #include <sys/types.h> |
10 #include <sys/wait.h> | 10 #include <sys/wait.h> |
11 | 11 |
12 #include <algorithm> | 12 #include <algorithm> |
13 #include <limits> | 13 #include <limits> |
14 #include <map> | 14 #include <map> |
15 #include <set> | 15 #include <set> |
16 #include <utility> | 16 #include <utility> |
17 #include <vector> | 17 #include <vector> |
18 | 18 |
19 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
20 #include "sandbox/linux/seccomp-bpf/die.h" | 20 #include "sandbox/linux/seccomp-bpf/die.h" |
21 #include "sandbox/linux/seccomp-bpf/errorcode.h" | 21 #include "sandbox/linux/seccomp-bpf/errorcode.h" |
22 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" | 22 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
23 #include "sandbox/linux/seccomp-bpf/port.h" | 23 #include "sandbox/linux/seccomp-bpf/port.h" |
24 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy_forward.h" | 24 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy_forward.h" |
25 | 25 |
26 namespace playground2 { | 26 namespace playground2 { |
27 | 27 |
28 struct arch_seccomp_data { | 28 struct arch_seccomp_data { |
29 int nr; | 29 int nr; |
30 uint32_t arch; | 30 uint32_t arch; |
31 uint64_t instruction_pointer; | 31 uint64_t instruction_pointer; |
32 uint64_t args[6]; | 32 uint64_t args[6]; |
33 }; | 33 }; |
34 | 34 |
35 struct arch_sigsys { | 35 struct arch_sigsys { |
36 void *ip; | 36 void* ip; |
37 int nr; | 37 int nr; |
38 unsigned int arch; | 38 unsigned int arch; |
39 }; | 39 }; |
40 | 40 |
41 class CodeGen; | 41 class CodeGen; |
42 class SandboxUnittestHelper; | 42 class SandboxUnittestHelper; |
43 class SandboxBpfPolicy; | 43 class SandboxBpfPolicy; |
44 struct Instruction; | 44 struct Instruction; |
45 | 45 |
46 class Sandbox { | 46 class Sandbox { |
47 public: | 47 public: |
48 enum SandboxStatus { | 48 enum SandboxStatus { |
49 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() | 49 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() |
50 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing | 50 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing |
51 STATUS_UNAVAILABLE, // Currently unavailable but might work again later | 51 STATUS_UNAVAILABLE, // Currently unavailable but might work again later |
52 STATUS_AVAILABLE, // Sandboxing is available but not currently active | 52 STATUS_AVAILABLE, // Sandboxing is available but not currently active |
53 STATUS_ENABLED // The sandbox is now active | 53 STATUS_ENABLED // The sandbox is now active |
54 }; | 54 }; |
55 | 55 |
56 // BpfSandboxPolicy is the following type: | 56 // BpfSandboxPolicy is the following type: |
57 // ErrorCode (Sandbox *sb, int sysnum, void *aux); | 57 // ErrorCode (Sandbox *sb, int sysnum, void *aux); |
58 // When calling setSandboxPolicy(), the caller can provide an arbitrary | 58 // When calling setSandboxPolicy(), the caller can provide an arbitrary |
59 // pointer in |aux|. This pointer will then be forwarded to the sandbox | 59 // pointer in |aux|. This pointer will then be forwarded to the sandbox |
60 // policy each time a call is made through an EvaluateSyscall function | 60 // policy each time a call is made through an EvaluateSyscall function |
61 // pointer. One common use case would be to pass the "aux" pointer as an | 61 // pointer. One common use case would be to pass the "aux" pointer as an |
62 // argument to Trap() functions. | 62 // argument to Trap() functions. |
63 typedef BpfSandboxPolicy* EvaluateSyscall; | 63 typedef BpfSandboxPolicy* EvaluateSyscall; |
64 typedef std::vector<std::pair<EvaluateSyscall, void *> >Evaluators; | 64 typedef std::vector<std::pair<EvaluateSyscall, void*> > Evaluators; |
65 | 65 |
66 // A vector of BPF instructions that need to be installed as a filter | 66 // A vector of BPF instructions that need to be installed as a filter |
67 // program in the kernel. | 67 // program in the kernel. |
68 typedef std::vector<struct sock_filter> Program; | 68 typedef std::vector<struct sock_filter> Program; |
69 | 69 |
70 // Constructors and destructors. | 70 // Constructors and destructors. |
71 // NOTE: Setting a policy and starting the sandbox is a one-way operation. | 71 // NOTE: Setting a policy and starting the sandbox is a one-way operation. |
72 // The kernel does not provide any option for unloading a loaded | 72 // The kernel does not provide any option for unloading a loaded |
73 // sandbox. Strictly speaking, that means we should disallow calling | 73 // sandbox. Strictly speaking, that means we should disallow calling |
74 // the destructor, if StartSandbox() has ever been called. In practice, | 74 // the destructor, if StartSandbox() has ever been called. In practice, |
(...skipping 29 matching lines...) Expand all Loading... |
104 // by returning ERR_ALLOWED; it can deny the system call unconditionally by | 104 // by returning ERR_ALLOWED; it can deny the system call unconditionally by |
105 // returning an appropriate "errno" value; or it can request inspection | 105 // returning an appropriate "errno" value; or it can request inspection |
106 // of system call argument(s) by returning a suitable ErrorCode. | 106 // of system call argument(s) by returning a suitable ErrorCode. |
107 // The "aux" parameter can be used to pass optional data to the system call | 107 // The "aux" parameter can be used to pass optional data to the system call |
108 // evaluator. There are different possible uses for this data, but one of the | 108 // evaluator. There are different possible uses for this data, but one of the |
109 // use cases would be for the policy to then forward this pointer to a Trap() | 109 // use cases would be for the policy to then forward this pointer to a Trap() |
110 // handler. In this case, of course, the data that is pointed to must remain | 110 // handler. In this case, of course, the data that is pointed to must remain |
111 // valid for the entire time that Trap() handlers can be called; typically, | 111 // valid for the entire time that Trap() handlers can be called; typically, |
112 // this would be the lifetime of the program. | 112 // this would be the lifetime of the program. |
113 // DEPRECATED: use the policy interface below. | 113 // DEPRECATED: use the policy interface below. |
114 void SetSandboxPolicyDeprecated(EvaluateSyscall syscallEvaluator, void *aux); | 114 void SetSandboxPolicyDeprecated(EvaluateSyscall syscallEvaluator, void* aux); |
115 | 115 |
116 // Set the BPF policy as |policy|. Ownership of |policy| is transfered here | 116 // Set the BPF policy as |policy|. Ownership of |policy| is transfered here |
117 // to the sandbox object. | 117 // to the sandbox object. |
118 void SetSandboxPolicy(SandboxBpfPolicy* policy); | 118 void SetSandboxPolicy(SandboxBpfPolicy* policy); |
119 | 119 |
120 // We can use ErrorCode to request calling of a trap handler. This method | 120 // We can use ErrorCode to request calling of a trap handler. This method |
121 // performs the required wrapping of the callback function into an | 121 // performs the required wrapping of the callback function into an |
122 // ErrorCode object. | 122 // ErrorCode object. |
123 // The "aux" field can carry a pointer to arbitrary data. See EvaluateSyscall | 123 // The "aux" field can carry a pointer to arbitrary data. See EvaluateSyscall |
124 // for a description of how to pass data from SetSandboxPolicy() to a Trap() | 124 // for a description of how to pass data from SetSandboxPolicy() to a Trap() |
125 // handler. | 125 // handler. |
126 ErrorCode Trap(Trap::TrapFnc fnc, const void *aux); | 126 ErrorCode Trap(Trap::TrapFnc fnc, const void* aux); |
127 | 127 |
128 // Calls a user-space trap handler and disables all sandboxing for system | 128 // Calls a user-space trap handler and disables all sandboxing for system |
129 // calls made from this trap handler. | 129 // calls made from this trap handler. |
130 // This feature is available only if explicitly enabled by the user having | 130 // This feature is available only if explicitly enabled by the user having |
131 // set the CHROME_SANDBOX_DEBUGGING environment variable. | 131 // set the CHROME_SANDBOX_DEBUGGING environment variable. |
132 // Returns an ET_INVALID ErrorCode, if called when not enabled. | 132 // Returns an ET_INVALID ErrorCode, if called when not enabled. |
133 // NOTE: This feature, by definition, disables all security features of | 133 // NOTE: This feature, by definition, disables all security features of |
134 // the sandbox. It should never be used in production, but it can be | 134 // the sandbox. It should never be used in production, but it can be |
135 // very useful to diagnose code that is incompatible with the sandbox. | 135 // very useful to diagnose code that is incompatible with the sandbox. |
136 // If even a single system call returns "UnsafeTrap", the security of | 136 // If even a single system call returns "UnsafeTrap", the security of |
137 // entire sandbox should be considered compromised. | 137 // entire sandbox should be considered compromised. |
138 ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void *aux); | 138 ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void* aux); |
139 | 139 |
140 // From within an UnsafeTrap() it is often useful to be able to execute | 140 // From within an UnsafeTrap() it is often useful to be able to execute |
141 // the system call that triggered the trap. The ForwardSyscall() method | 141 // the system call that triggered the trap. The ForwardSyscall() method |
142 // makes this easy. It is more efficient than calling glibc's syscall() | 142 // makes this easy. It is more efficient than calling glibc's syscall() |
143 // function, as it avoid the extra round-trip to the signal handler. And | 143 // function, as it avoid the extra round-trip to the signal handler. And |
144 // it automatically does the correct thing to report kernel-style error | 144 // it automatically does the correct thing to report kernel-style error |
145 // conditions, rather than setting errno. See the comments for TrapFnc for | 145 // conditions, rather than setting errno. See the comments for TrapFnc for |
146 // details. In other words, the return value from ForwardSyscall() is | 146 // details. In other words, the return value from ForwardSyscall() is |
147 // directly suitable as a return value for a trap handler. | 147 // directly suitable as a return value for a trap handler. |
148 static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); | 148 static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); |
149 | 149 |
150 // We can also use ErrorCode to request evaluation of a conditional | 150 // We can also use ErrorCode to request evaluation of a conditional |
151 // statement based on inspection of system call parameters. | 151 // statement based on inspection of system call parameters. |
152 // This method wrap an ErrorCode object around the conditional statement. | 152 // This method wrap an ErrorCode object around the conditional statement. |
153 // Argument "argno" (1..6) will be compared to "value" using comparator | 153 // Argument "argno" (1..6) will be compared to "value" using comparator |
154 // "op". If the condition is true "passed" will be returned, otherwise | 154 // "op". If the condition is true "passed" will be returned, otherwise |
155 // "failed". | 155 // "failed". |
156 // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1) | 156 // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1) |
157 // If it is outside this range, the sandbox treats the system call just | 157 // If it is outside this range, the sandbox treats the system call just |
158 // the same as any other ABI violation (i.e. it aborts with an error | 158 // the same as any other ABI violation (i.e. it aborts with an error |
159 // message). | 159 // message). |
160 ErrorCode Cond(int argno, ErrorCode::ArgType is_32bit, | 160 ErrorCode Cond(int argno, |
| 161 ErrorCode::ArgType is_32bit, |
161 ErrorCode::Operation op, | 162 ErrorCode::Operation op, |
162 uint64_t value, const ErrorCode& passed, | 163 uint64_t value, |
| 164 const ErrorCode& passed, |
163 const ErrorCode& failed); | 165 const ErrorCode& failed); |
164 | 166 |
165 // Kill the program and print an error message. | 167 // Kill the program and print an error message. |
166 ErrorCode Kill(const char *msg); | 168 ErrorCode Kill(const char* msg); |
167 | 169 |
168 // This is the main public entry point. It finds all system calls that | 170 // This is the main public entry point. It finds all system calls that |
169 // need rewriting, sets up the resources needed by the sandbox, and | 171 // need rewriting, sets up the resources needed by the sandbox, and |
170 // enters Seccomp mode. | 172 // enters Seccomp mode. |
171 // It is possible to stack multiple sandboxes by creating separate "Sandbox" | 173 // It is possible to stack multiple sandboxes by creating separate "Sandbox" |
172 // objects and calling "StartSandbox()" on each of them. Please note, that | 174 // objects and calling "StartSandbox()" on each of them. Please note, that |
173 // this requires special care, though, as newly stacked sandboxes can never | 175 // this requires special care, though, as newly stacked sandboxes can never |
174 // relax restrictions imposed by earlier sandboxes. Furthermore, installing | 176 // relax restrictions imposed by earlier sandboxes. Furthermore, installing |
175 // a new policy requires making system calls, that might already be | 177 // a new policy requires making system calls, that might already be |
176 // disallowed. | 178 // disallowed. |
177 // Finally, stacking does add more kernel overhead than having a single | 179 // Finally, stacking does add more kernel overhead than having a single |
178 // combined policy. So, it should only be used if there are no alternatives. | 180 // combined policy. So, it should only be used if there are no alternatives. |
179 void StartSandbox(); | 181 void StartSandbox(); |
180 | 182 |
181 // Assembles a BPF filter program from the current policy. After calling this | 183 // Assembles a BPF filter program from the current policy. After calling this |
182 // function, you must not call any other sandboxing function. | 184 // function, you must not call any other sandboxing function. |
183 // Typically, AssembleFilter() is only used by unit tests and by sandbox | 185 // Typically, AssembleFilter() is only used by unit tests and by sandbox |
184 // internals. It should not be used by production code. | 186 // internals. It should not be used by production code. |
185 // For performance reasons, we normally only run the assembled BPF program | 187 // For performance reasons, we normally only run the assembled BPF program |
186 // through the verifier, iff the program was built in debug mode. | 188 // through the verifier, iff the program was built in debug mode. |
187 // But by setting "force_verification", the caller can request that the | 189 // But by setting "force_verification", the caller can request that the |
188 // verifier is run unconditionally. This is useful for unittests. | 190 // verifier is run unconditionally. This is useful for unittests. |
189 Program *AssembleFilter(bool force_verification); | 191 Program* AssembleFilter(bool force_verification); |
190 | 192 |
191 // Returns the fatal ErrorCode that is used to indicate that somebody | 193 // Returns the fatal ErrorCode that is used to indicate that somebody |
192 // attempted to pass a 64bit value in a 32bit system call argument. | 194 // attempted to pass a 64bit value in a 32bit system call argument. |
193 // This method is primarily needed for testing purposes. | 195 // This method is primarily needed for testing purposes. |
194 ErrorCode Unexpected64bitArgument(); | 196 ErrorCode Unexpected64bitArgument(); |
195 | 197 |
196 private: | 198 private: |
197 friend class CodeGen; | 199 friend class CodeGen; |
198 friend class SandboxUnittestHelper; | 200 friend class SandboxUnittestHelper; |
199 friend class ErrorCode; | 201 friend class ErrorCode; |
200 | 202 |
201 struct Range { | 203 struct Range { |
202 Range(uint32_t f, uint32_t t, const ErrorCode& e) | 204 Range(uint32_t f, uint32_t t, const ErrorCode& e) |
203 : from(f), | 205 : from(f), to(t), err(e) {} |
204 to(t), | 206 uint32_t from, to; |
205 err(e) { | |
206 } | |
207 uint32_t from, to; | |
208 ErrorCode err; | 207 ErrorCode err; |
209 }; | 208 }; |
210 typedef std::vector<Range> Ranges; | 209 typedef std::vector<Range> Ranges; |
211 typedef std::map<uint32_t, ErrorCode> ErrMap; | 210 typedef std::map<uint32_t, ErrorCode> ErrMap; |
212 typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds; | 211 typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds; |
213 | 212 |
214 // Get a file descriptor pointing to "/proc", if currently available. | 213 // Get a file descriptor pointing to "/proc", if currently available. |
215 int proc_fd() { return proc_fd_; } | 214 int proc_fd() { return proc_fd_; } |
216 | 215 |
217 // Creates a subprocess and runs "code_in_sandbox" inside of the specified | 216 // Creates a subprocess and runs "code_in_sandbox" inside of the specified |
218 // policy. The caller has to make sure that "this" has not yet been | 217 // policy. The caller has to make sure that "this" has not yet been |
219 // initialized with any other policies. | 218 // initialized with any other policies. |
220 bool RunFunctionInPolicy(void (*code_in_sandbox)(), | 219 bool RunFunctionInPolicy(void (*code_in_sandbox)(), |
221 EvaluateSyscall syscall_evaluator, void *aux); | 220 EvaluateSyscall syscall_evaluator, |
| 221 void* aux); |
222 | 222 |
223 // Performs a couple of sanity checks to verify that the kernel supports the | 223 // Performs a couple of sanity checks to verify that the kernel supports the |
224 // features that we need for successful sandboxing. | 224 // features that we need for successful sandboxing. |
225 // The caller has to make sure that "this" has not yet been initialized with | 225 // The caller has to make sure that "this" has not yet been initialized with |
226 // any other policies. | 226 // any other policies. |
227 bool KernelSupportSeccompBPF(); | 227 bool KernelSupportSeccompBPF(); |
228 | 228 |
229 // Verify that the current policy passes some basic sanity checks. | 229 // Verify that the current policy passes some basic sanity checks. |
230 void PolicySanityChecks(SandboxBpfPolicy* policy); | 230 void PolicySanityChecks(SandboxBpfPolicy* policy); |
231 | 231 |
232 // Assembles and installs a filter based on the policy that has previously | 232 // Assembles and installs a filter based on the policy that has previously |
233 // been configured with SetSandboxPolicy(). | 233 // been configured with SetSandboxPolicy(). |
234 void InstallFilter(); | 234 void InstallFilter(); |
235 | 235 |
236 // Verify the correctness of a compiled program by comparing it against the | 236 // Verify the correctness of a compiled program by comparing it against the |
237 // current policy. This function should only ever be called by unit tests and | 237 // current policy. This function should only ever be called by unit tests and |
238 // by the sandbox internals. It should not be used by production code. | 238 // by the sandbox internals. It should not be used by production code. |
239 void VerifyProgram(const Program& program, bool has_unsafe_traps); | 239 void VerifyProgram(const Program& program, bool has_unsafe_traps); |
240 | 240 |
241 // Finds all the ranges of system calls that need to be handled. Ranges are | 241 // Finds all the ranges of system calls that need to be handled. Ranges are |
242 // sorted in ascending order of system call numbers. There are no gaps in the | 242 // sorted in ascending order of system call numbers. There are no gaps in the |
243 // ranges. System calls with identical ErrorCodes are coalesced into a single | 243 // ranges. System calls with identical ErrorCodes are coalesced into a single |
244 // range. | 244 // range. |
245 void FindRanges(Ranges *ranges); | 245 void FindRanges(Ranges* ranges); |
246 | 246 |
247 // Returns a BPF program snippet that implements a jump table for the | 247 // Returns a BPF program snippet that implements a jump table for the |
248 // given range of system call numbers. This function runs recursively. | 248 // given range of system call numbers. This function runs recursively. |
249 Instruction *AssembleJumpTable(CodeGen *gen, | 249 Instruction* AssembleJumpTable(CodeGen* gen, |
250 Ranges::const_iterator start, | 250 Ranges::const_iterator start, |
251 Ranges::const_iterator stop); | 251 Ranges::const_iterator stop); |
252 | 252 |
253 // Returns a BPF program snippet that makes the BPF filter program exit | 253 // Returns a BPF program snippet that makes the BPF filter program exit |
254 // with the given ErrorCode "err". N.B. the ErrorCode may very well be a | 254 // with the given ErrorCode "err". N.B. the ErrorCode may very well be a |
255 // conditional expression; if so, this function will recursively call | 255 // conditional expression; if so, this function will recursively call |
256 // CondExpression() and possibly RetExpression() to build a complex set of | 256 // CondExpression() and possibly RetExpression() to build a complex set of |
257 // instructions. | 257 // instructions. |
258 Instruction *RetExpression(CodeGen *gen, const ErrorCode& err); | 258 Instruction* RetExpression(CodeGen* gen, const ErrorCode& err); |
259 | 259 |
260 // Returns a BPF program that evaluates the conditional expression in | 260 // Returns a BPF program that evaluates the conditional expression in |
261 // "cond" and returns the appropriate value from the BPF filter program. | 261 // "cond" and returns the appropriate value from the BPF filter program. |
262 // This function recursively calls RetExpression(); it should only ever be | 262 // This function recursively calls RetExpression(); it should only ever be |
263 // called from RetExpression(). | 263 // called from RetExpression(). |
264 Instruction *CondExpression(CodeGen *gen, const ErrorCode& cond); | 264 Instruction* CondExpression(CodeGen* gen, const ErrorCode& cond); |
265 | 265 |
266 static SandboxStatus status_; | 266 static SandboxStatus status_; |
267 | 267 |
268 bool quiet_; | 268 bool quiet_; |
269 int proc_fd_; | 269 int proc_fd_; |
270 scoped_ptr<const SandboxBpfPolicy> policy_; | 270 scoped_ptr<const SandboxBpfPolicy> policy_; |
271 Conds* conds_; | 271 Conds* conds_; |
272 bool sandbox_has_started_; | 272 bool sandbox_has_started_; |
273 | 273 |
274 DISALLOW_COPY_AND_ASSIGN(Sandbox); | 274 DISALLOW_COPY_AND_ASSIGN(Sandbox); |
275 }; | 275 }; |
276 | 276 |
277 } // namespace | 277 } // namespace |
278 | 278 |
279 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ | 279 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
OLD | NEW |