Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf.cc

Issue 11300014: Seccomp-BPF: relax failure in probe process setup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add vertical space. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/codegen.h" 5 #include "sandbox/linux/seccomp-bpf/codegen.h"
6 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 6 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
7 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 7 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
8 #include "sandbox/linux/seccomp-bpf/verifier.h" 8 #include "sandbox/linux/seccomp-bpf/verifier.h"
9 9
10 namespace {
11
12 void WriteFailedStderrSetupMessage(int out_fd) {
13 const char* error_string = strerror(errno);
14 static const char msg[] = "Failed to set up stderr: ";
15 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg)-1)) > 0 && error_string &&
16 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 &&
17 HANDLE_EINTR(write(out_fd, "\n", 1))) {
18 }
19 }
20
21 } // namespace
22
10 // The kernel gives us a sandbox, we turn it into a playground :-) 23 // The kernel gives us a sandbox, we turn it into a playground :-)
11 // This is version 2 of the playground; version 1 was built on top of 24 // This is version 2 of the playground; version 1 was built on top of
12 // pre-BPF seccomp mode. 25 // pre-BPF seccomp mode.
13 namespace playground2 { 26 namespace playground2 {
14 27
28 const int kExpectedExitCode = 100;
29
15 // We define a really simple sandbox policy. It is just good enough for us 30 // We define a really simple sandbox policy. It is just good enough for us
16 // to tell that the sandbox has actually been activated. 31 // to tell that the sandbox has actually been activated.
17 ErrorCode Sandbox::probeEvaluator(int signo) { 32 ErrorCode Sandbox::probeEvaluator(int signo) {
18 switch (signo) { 33 switch (signo) {
19 case __NR_getpid: 34 case __NR_getpid:
20 // Return EPERM so that we can check that the filter actually ran. 35 // Return EPERM so that we can check that the filter actually ran.
21 return ErrorCode(EPERM); 36 return ErrorCode(EPERM);
22 case __NR_exit_group: 37 case __NR_exit_group:
23 // Allow exit() with a non-default return code. 38 // Allow exit() with a non-default return code.
24 return ErrorCode(ErrorCode::ERR_ALLOWED); 39 return ErrorCode(ErrorCode::ERR_ALLOWED);
25 default: 40 default:
26 // Make everything else fail in an easily recognizable way. 41 // Make everything else fail in an easily recognizable way.
27 return ErrorCode(EINVAL); 42 return ErrorCode(EINVAL);
28 } 43 }
29 } 44 }
30 45
31 void Sandbox::probeProcess(void) { 46 void Sandbox::probeProcess(void) {
32 if (syscall(__NR_getpid) < 0 && errno == EPERM) { 47 if (syscall(__NR_getpid) < 0 && errno == EPERM) {
33 syscall(__NR_exit_group, (intptr_t)100); 48 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
34 } 49 }
35 } 50 }
36 51
37 bool Sandbox::isValidSyscallNumber(int sysnum) { 52 bool Sandbox::isValidSyscallNumber(int sysnum) {
38 return SyscallIterator::IsValid(sysnum); 53 return SyscallIterator::IsValid(sysnum);
39 } 54 }
40 55
41 ErrorCode Sandbox::allowAllEvaluator(int sysnum) { 56 ErrorCode Sandbox::allowAllEvaluator(int sysnum) {
42 if (!isValidSyscallNumber(sysnum)) { 57 if (!isValidSyscallNumber(sysnum)) {
43 return ErrorCode(ENOSYS); 58 return ErrorCode(ENOSYS);
44 } 59 }
45 return ErrorCode(ErrorCode::ERR_ALLOWED); 60 return ErrorCode(ErrorCode::ERR_ALLOWED);
46 } 61 }
47 62
48 void Sandbox::tryVsyscallProcess(void) { 63 void Sandbox::tryVsyscallProcess(void) {
49 time_t current_time; 64 time_t current_time;
50 // time() is implemented as a vsyscall. With an older glibc, with 65 // time() is implemented as a vsyscall. With an older glibc, with
51 // vsyscall=emulate and some versions of the seccomp BPF patch 66 // vsyscall=emulate and some versions of the seccomp BPF patch
52 // we may get SIGKILL-ed. Detect this! 67 // we may get SIGKILL-ed. Detect this!
53 if (time(&current_time) != static_cast<time_t>(-1)) { 68 if (time(&current_time) != static_cast<time_t>(-1)) {
54 syscall(__NR_exit_group, (intptr_t)100); 69 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
55 } 70 }
56 } 71 }
57 72
58 bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), 73 bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(),
59 EvaluateSyscall syscallEvaluator, 74 EvaluateSyscall syscallEvaluator,
60 int proc_fd) { 75 int proc_fd) {
61 // Block all signals before forking a child process. This prevents an 76 // Block all signals before forking a child process. This prevents an
62 // attacker from manipulating our test by sending us an unexpected signal. 77 // attacker from manipulating our test by sending us an unexpected signal.
63 sigset_t oldMask, newMask; 78 sigset_t oldMask, newMask;
64 if (sigfillset(&newMask) || 79 if (sigfillset(&newMask) ||
65 sigprocmask(SIG_BLOCK, &newMask, &oldMask)) { 80 sigprocmask(SIG_BLOCK, &newMask, &oldMask)) {
66 SANDBOX_DIE("sigprocmask() failed"); 81 SANDBOX_DIE("sigprocmask() failed");
67 } 82 }
68 int fds[2]; 83 int fds[2];
69 if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) { 84 if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) {
70 SANDBOX_DIE("pipe() failed"); 85 SANDBOX_DIE("pipe() failed");
71 } 86 }
72 87
88 if (fds[0] <= 2 || fds[1] <= 2) {
89 SANDBOX_DIE("Process started without standard file descriptors");
90 }
91
73 pid_t pid = fork(); 92 pid_t pid = fork();
74 if (pid < 0) { 93 if (pid < 0) {
75 // Die if we cannot fork(). We would probably fail a little later 94 // Die if we cannot fork(). We would probably fail a little later
76 // anyway, as the machine is likely very close to running out of 95 // anyway, as the machine is likely very close to running out of
77 // memory. 96 // memory.
78 // But what we don't want to do is return "false", as a crafty 97 // But what we don't want to do is return "false", as a crafty
79 // attacker might cause fork() to fail at will and could trick us 98 // attacker might cause fork() to fail at will and could trick us
80 // into running without a sandbox. 99 // into running without a sandbox.
81 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails 100 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails
82 SANDBOX_DIE("fork() failed unexpectedly"); 101 SANDBOX_DIE("fork() failed unexpectedly");
83 } 102 }
84 103
85 // In the child process 104 // In the child process
86 if (!pid) { 105 if (!pid) {
87 // Test a very simple sandbox policy to verify that we can 106 // Test a very simple sandbox policy to verify that we can
88 // successfully turn on sandboxing. 107 // successfully turn on sandboxing.
89 Die::EnableSimpleExit(); 108 Die::EnableSimpleExit();
90 errno = 0;
91 if (HANDLE_EINTR(close(fds[0])) ||
92 HANDLE_EINTR(dup2(fds[1], 2)) != 2 ||
93 HANDLE_EINTR(close(fds[1]))) {
94 const char* error_string = strerror(errno);
95 static const char msg[] = "Failed to set up stderr: ";
96 if (HANDLE_EINTR(write(fds[1], msg, sizeof(msg)-1)) > 0 && error_string &&
97 HANDLE_EINTR(write(fds[1], error_string, strlen(error_string))) > 0 &&
98 HANDLE_EINTR(write(fds[1], "\n", 1))) {
99 }
100 } else {
101 evaluators_.clear();
102 setSandboxPolicy(syscallEvaluator, NULL);
103 setProcFd(proc_fd);
104 109
105 // By passing "quiet=true" to "startSandboxInternal()" we suppress 110 if (HANDLE_EINTR(close(fds[0]))) {
106 // messages for expected and benign failures (e.g. if the current 111 WriteFailedStderrSetupMessage(fds[1]);
107 // kernel lacks support for BPF filters). 112 SANDBOX_DIE(NULL);
108 startSandboxInternal(true); 113 }
114 if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) {
115 // Stderr could very well be a file descriptor to .xsession-errors, or
116 // another file, which could be backed by a file system that could cause
117 // dup2 to fail while trying to close stderr. It's important that we do
118 // not fail on trying to close stderr.
119 // If dup2 fails here, we will continue normally, this means that our
120 // parent won't cause a fatal failure if something writes to stderr in
121 // this child.
122 }
123 if (HANDLE_EINTR(close(fds[1]))) {
124 WriteFailedStderrSetupMessage(fds[1]);
125 SANDBOX_DIE(NULL);
126 }
109 127
110 // Run our code in the sandbox 128 evaluators_.clear();
111 CodeInSandbox(); 129 setSandboxPolicy(syscallEvaluator, NULL);
112 } 130 setProcFd(proc_fd);
131
132 // By passing "quiet=true" to "startSandboxInternal()" we suppress
133 // messages for expected and benign failures (e.g. if the current
134 // kernel lacks support for BPF filters).
135 startSandboxInternal(true);
136
137 // Run our code in the sandbox.
138 CodeInSandbox();
139
140 // CodeInSandbox() is not supposed to return here.
113 SANDBOX_DIE(NULL); 141 SANDBOX_DIE(NULL);
114 } 142 }
115 143
116 // In the parent process. 144 // In the parent process.
117 if (HANDLE_EINTR(close(fds[1]))) { 145 if (HANDLE_EINTR(close(fds[1]))) {
118 SANDBOX_DIE("close() failed"); 146 SANDBOX_DIE("close() failed");
119 } 147 }
120 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { 148 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) {
121 SANDBOX_DIE("sigprocmask() failed"); 149 SANDBOX_DIE("sigprocmask() failed");
122 } 150 }
123 int status; 151 int status;
124 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { 152 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) {
125 SANDBOX_DIE("waitpid() failed unexpectedly"); 153 SANDBOX_DIE("waitpid() failed unexpectedly");
126 } 154 }
127 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == 100; 155 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode;
128 156
129 // If we fail to support sandboxing, there might be an additional 157 // If we fail to support sandboxing, there might be an additional
130 // error message. If so, this was an entirely unexpected and fatal 158 // error message. If so, this was an entirely unexpected and fatal
131 // failure. We should report the failure and somebody must fix 159 // failure. We should report the failure and somebody must fix
132 // things. This is probably a security-critical bug in the sandboxing 160 // things. This is probably a security-critical bug in the sandboxing
133 // code. 161 // code.
134 if (!rc) { 162 if (!rc) {
135 char buf[4096]; 163 char buf[4096];
136 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); 164 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1));
137 if (len > 0) { 165 if (len > 0) {
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; 644 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN;
617 int Sandbox::proc_fd_ = -1; 645 int Sandbox::proc_fd_ = -1;
618 Sandbox::Evaluators Sandbox::evaluators_; 646 Sandbox::Evaluators Sandbox::evaluators_;
619 Sandbox::ErrMap Sandbox::errMap_; 647 Sandbox::ErrMap Sandbox::errMap_;
620 Sandbox::Traps *Sandbox::traps_ = NULL; 648 Sandbox::Traps *Sandbox::traps_ = NULL;
621 Sandbox::TrapIds Sandbox::trapIds_; 649 Sandbox::TrapIds Sandbox::trapIds_;
622 ErrorCode *Sandbox::trapArray_ = NULL; 650 ErrorCode *Sandbox::trapArray_ = NULL;
623 size_t Sandbox::trapArraySize_ = 0; 651 size_t Sandbox::trapArraySize_ = 0;
624 652
625 } // namespace 653 } // namespace
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698