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 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
6 | 6 |
7 // The kernel gives us a sandbox, we turn it into a playground :-) | 7 // The kernel gives us a sandbox, we turn it into a playground :-) |
8 // This is version 2 of the playground; version 1 was built on top of | 8 // This is version 2 of the playground; version 1 was built on top of |
9 // pre-BPF seccomp mode. | 9 // pre-BPF seccomp mode. |
10 namespace playground2 { | 10 namespace playground2 { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
204 sigprocmask(SIG_UNBLOCK, &mask, NULL)) { | 204 sigprocmask(SIG_UNBLOCK, &mask, NULL)) { |
205 goto filter_failed; | 205 goto filter_failed; |
206 } | 206 } |
207 | 207 |
208 // We can't handle stacked evaluators, yet. We'll get there eventually | 208 // We can't handle stacked evaluators, yet. We'll get there eventually |
209 // though. Hang tight. | 209 // though. Hang tight. |
210 if (evaluators_.size() != 1) { | 210 if (evaluators_.size() != 1) { |
211 die("Not implemented"); | 211 die("Not implemented"); |
212 } | 212 } |
213 | 213 |
214 // Assemble the BPF filter program. | |
215 Program *program = new Program(); | |
216 if (!program) { | |
Chris Evans
2012/06/12 20:26:26
Nit: not sure you need this, the standard c++ runt
| |
217 die("Out of memory"); | |
218 } | |
219 | |
214 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 220 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
215 // system call. | 221 // system call. |
216 std::vector<struct sock_filter> program; | 222 program->push_back((struct sock_filter) |
217 program.push_back((struct sock_filter) | |
218 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); | 223 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); |
219 program.push_back((struct sock_filter) | 224 program->push_back((struct sock_filter) |
220 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); | 225 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); |
221 | 226 |
222 // TODO: Instead of killing outright, we should raise a SIGSYS and | 227 // TODO: Instead of killing outright, we should raise a SIGSYS and |
223 // report a useful error message. SIGKILL cannot be trapped by the | 228 // report a useful error message. SIGKILL cannot be trapped by the |
224 // debugger and essentially makes the program fail in a way that is | 229 // debugger and essentially makes the program fail in a way that is |
225 // almost impossible to debug. | 230 // almost impossible to debug. |
226 program.push_back((struct sock_filter) | 231 program->push_back((struct sock_filter) |
227 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 232 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); |
228 | 233 |
229 // Grab the system call number, so that we can implement jump tables. | 234 // Grab the system call number, so that we can implement jump tables. |
230 program.push_back((struct sock_filter) | 235 program->push_back((struct sock_filter) |
231 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); | 236 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); |
232 | 237 |
233 // On Intel architectures, verify that system call numbers are in the | 238 // On Intel architectures, verify that system call numbers are in the |
234 // expected number range. The older i386 and x86-64 APIs clear bit 30 | 239 // expected number range. The older i386 and x86-64 APIs clear bit 30 |
235 // on all system calls. The newer x86-32 API always sets bit 30. | 240 // on all system calls. The newer x86-32 API always sets bit 30. |
236 #if defined(__i386__) || defined(__x86_64__) | 241 #if defined(__i386__) || defined(__x86_64__) |
237 #if defined(__x86_64__) && defined(__ILP32__) | 242 #if defined(__x86_64__) && defined(__ILP32__) |
238 program.push_back((struct sock_filter) | 243 program->push_back((struct sock_filter) |
239 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); | 244 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); |
240 #else | 245 #else |
241 program.push_back((struct sock_filter) | 246 program->push_back((struct sock_filter) |
242 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); | 247 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); |
243 #endif | 248 #endif |
244 // TODO: raise a suitable SIGSYS signal | 249 // TODO: raise a suitable SIGSYS signal |
245 program.push_back((struct sock_filter) | 250 program->push_back((struct sock_filter) |
246 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 251 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); |
247 #endif | 252 #endif |
248 | 253 |
249 // Evaluate all possible system calls and depending on their | 254 // Evaluate all possible system calls and depending on their |
250 // exit codes generate a BPF filter. | 255 // exit codes generate a BPF filter. |
251 // This is very inefficient right now. We need to be much smarter | 256 // This is very inefficient right now. We need to be much smarter |
252 // eventually. | 257 // eventually. |
253 // We currently incur a O(N) overhead on each system call, with N | 258 // We currently incur a O(N) overhead on each system call, with N |
254 // being the number of system calls. It is easy to get this down to | 259 // being the number of system calls. It is easy to get this down to |
255 // O(log_2(M)) with M being the number of system calls that need special | 260 // O(log_2(M)) with M being the number of system calls that need special |
(...skipping 15 matching lines...) Expand all Loading... | |
271 if (err >= static_cast<ErrorCode>(1) && | 276 if (err >= static_cast<ErrorCode>(1) && |
272 err <= static_cast<ErrorCode>(4096)) { | 277 err <= static_cast<ErrorCode>(4096)) { |
273 // We limit errno values to a reasonable range. In fact, the Linux ABI | 278 // We limit errno values to a reasonable range. In fact, the Linux ABI |
274 // doesn't support errno values outside of this range. | 279 // doesn't support errno values outside of this range. |
275 ret = SECCOMP_RET_ERRNO + err; | 280 ret = SECCOMP_RET_ERRNO + err; |
276 } else { | 281 } else { |
277 die("Invalid ErrorCode reported by sandbox system call evaluator"); | 282 die("Invalid ErrorCode reported by sandbox system call evaluator"); |
278 } | 283 } |
279 break; | 284 break; |
280 } | 285 } |
281 program.push_back((struct sock_filter) | 286 program->push_back((struct sock_filter) |
282 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); | 287 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); |
283 program.push_back((struct sock_filter) | 288 program->push_back((struct sock_filter) |
284 BPF_STMT(BPF_RET+BPF_K, ret)); | 289 BPF_STMT(BPF_RET+BPF_K, ret)); |
285 } | 290 } |
286 | 291 |
287 // Everything that isn't allowed is forbidden. Eventually, we would | 292 // Everything that isn't allowed is forbidden. Eventually, we would |
288 // like to have a way to log forbidden calls, when in debug mode. | 293 // like to have a way to log forbidden calls, when in debug mode. |
289 // TODO: raise a suitable SIGSYS signal | 294 // TODO: raise a suitable SIGSYS signal |
290 program.push_back((struct sock_filter) | 295 program->push_back((struct sock_filter) |
291 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 296 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); |
292 | 297 |
298 // We want to be very careful in not imposing any requirements on the | |
299 // policies that are set with setSandboxPolicy(). This means, as soon as | |
300 // the sandbox is active, we shouldn't be relying on libraries that could | |
301 // be making system calls. This, for example, means we should avoid | |
302 // using the heap and we should avoid using STL functions. | |
303 // Temporarily copy the contents of the "program" vector into a | |
304 // stack-allocated array; and then explicitly destroy that object. | |
305 // This makes sure we don't ex- or implicitly call new/delete after we | |
306 // installed the BPF filter program in the kernel. Depending on the | |
307 // system memory allocator that is in effect, these operators can result | |
308 // in system calls to things like munmap() or brk(). | |
309 struct sock_filter bpf[program->size()]; | |
310 const struct sock_fprog prog = { program->size(), bpf }; | |
311 memcpy(bpf, &(*program)[0], sizeof(bpf)); | |
312 delete program; | |
313 | |
293 // Install BPF filter program | 314 // Install BPF filter program |
294 const struct sock_fprog prog = { program.size(), &program[0] }; | |
295 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || | 315 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || |
296 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 316 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
297 goto filter_failed; | 317 goto filter_failed; |
298 } | 318 } |
299 | 319 |
300 return; | 320 return; |
301 } | 321 } |
302 | 322 |
303 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { | 323 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { |
304 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context) { | 324 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context) { |
(...skipping 26 matching lines...) Expand all Loading... | |
331 } | 351 } |
332 | 352 |
333 | 353 |
334 bool Sandbox::suppressLogging_ = false; | 354 bool Sandbox::suppressLogging_ = false; |
335 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 355 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
336 int Sandbox::proc_fd_ = -1; | 356 int Sandbox::proc_fd_ = -1; |
337 std::vector<std::pair<Sandbox::EvaluateSyscall, | 357 std::vector<std::pair<Sandbox::EvaluateSyscall, |
338 Sandbox::EvaluateArguments> > Sandbox::evaluators_; | 358 Sandbox::EvaluateArguments> > Sandbox::evaluators_; |
339 | 359 |
340 } // namespace | 360 } // namespace |
OLD | NEW |