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

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

Issue 11369167: Merge 164850 - Seccomp-BPF: relax failure in probe process setup (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1271/src/
Patch Set: 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 <time.h> 5 #include <time.h>
6 6
7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.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 ErrorCode Sandbox::allowAllEvaluator(int signo) { 52 ErrorCode Sandbox::allowAllEvaluator(int signo) {
38 if (signo < static_cast<int>(MIN_SYSCALL) || 53 if (signo < static_cast<int>(MIN_SYSCALL) ||
39 signo > static_cast<int>(MAX_SYSCALL)) { 54 signo > static_cast<int>(MAX_SYSCALL)) {
40 return ErrorCode(ENOSYS); 55 return ErrorCode(ENOSYS);
41 } 56 }
42 return ErrorCode(ErrorCode::ERR_ALLOWED); 57 return ErrorCode(ErrorCode::ERR_ALLOWED);
43 } 58 }
44 59
45 void Sandbox::tryVsyscallProcess(void) { 60 void Sandbox::tryVsyscallProcess(void) {
46 time_t current_time; 61 time_t current_time;
47 // time() is implemented as a vsyscall. With an older glibc, with 62 // time() is implemented as a vsyscall. With an older glibc, with
48 // vsyscall=emulate and some versions of the seccomp BPF patch 63 // vsyscall=emulate and some versions of the seccomp BPF patch
49 // we may get SIGKILL-ed. Detect this! 64 // we may get SIGKILL-ed. Detect this!
50 if (time(&current_time) != static_cast<time_t>(-1)) { 65 if (time(&current_time) != static_cast<time_t>(-1)) {
51 syscall(__NR_exit_group, (intptr_t)100); 66 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
52 } 67 }
53 } 68 }
54 69
55 bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), 70 bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(),
56 EvaluateSyscall syscallEvaluator, 71 EvaluateSyscall syscallEvaluator,
57 int proc_fd) { 72 int proc_fd) {
58 // Block all signals before forking a child process. This prevents an 73 // Block all signals before forking a child process. This prevents an
59 // attacker from manipulating our test by sending us an unexpected signal. 74 // attacker from manipulating our test by sending us an unexpected signal.
60 sigset_t oldMask, newMask; 75 sigset_t oldMask, newMask;
61 if (sigfillset(&newMask) || 76 if (sigfillset(&newMask) ||
62 sigprocmask(SIG_BLOCK, &newMask, &oldMask)) { 77 sigprocmask(SIG_BLOCK, &newMask, &oldMask)) {
63 SANDBOX_DIE("sigprocmask() failed"); 78 SANDBOX_DIE("sigprocmask() failed");
64 } 79 }
65 int fds[2]; 80 int fds[2];
66 if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) { 81 if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) {
67 SANDBOX_DIE("pipe() failed"); 82 SANDBOX_DIE("pipe() failed");
68 } 83 }
69 84
85 if (fds[0] <= 2 || fds[1] <= 2) {
86 SANDBOX_DIE("Process started without standard file descriptors");
87 }
88
70 pid_t pid = fork(); 89 pid_t pid = fork();
71 if (pid < 0) { 90 if (pid < 0) {
72 // Die if we cannot fork(). We would probably fail a little later 91 // Die if we cannot fork(). We would probably fail a little later
73 // anyway, as the machine is likely very close to running out of 92 // anyway, as the machine is likely very close to running out of
74 // memory. 93 // memory.
75 // But what we don't want to do is return "false", as a crafty 94 // But what we don't want to do is return "false", as a crafty
76 // attacker might cause fork() to fail at will and could trick us 95 // attacker might cause fork() to fail at will and could trick us
77 // into running without a sandbox. 96 // into running without a sandbox.
78 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails 97 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails
79 SANDBOX_DIE("fork() failed unexpectedly"); 98 SANDBOX_DIE("fork() failed unexpectedly");
80 } 99 }
81 100
82 // In the child process 101 // In the child process
83 if (!pid) { 102 if (!pid) {
84 // Test a very simple sandbox policy to verify that we can 103 // Test a very simple sandbox policy to verify that we can
85 // successfully turn on sandboxing. 104 // successfully turn on sandboxing.
86 Die::EnableSimpleExit(); 105 Die::EnableSimpleExit();
87 errno = 0;
88 if (HANDLE_EINTR(close(fds[0])) ||
89 HANDLE_EINTR(dup2(fds[1], 2)) != 2 ||
90 HANDLE_EINTR(close(fds[1]))) {
91 const char* error_string = strerror(errno);
92 static const char msg[] = "Failed to set up stderr: ";
93 if (HANDLE_EINTR(write(fds[1], msg, sizeof(msg)-1)) > 0 && error_string &&
94 HANDLE_EINTR(write(fds[1], error_string, strlen(error_string))) > 0 &&
95 HANDLE_EINTR(write(fds[1], "\n", 1))) {
96 }
97 } else {
98 evaluators_.clear();
99 setSandboxPolicy(syscallEvaluator, NULL);
100 setProcFd(proc_fd);
101 106
102 // By passing "quiet=true" to "startSandboxInternal()" we suppress 107 if (HANDLE_EINTR(close(fds[0]))) {
103 // messages for expected and benign failures (e.g. if the current 108 WriteFailedStderrSetupMessage(fds[1]);
104 // kernel lacks support for BPF filters). 109 SANDBOX_DIE(NULL);
105 startSandboxInternal(true); 110 }
111 if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) {
112 // Stderr could very well be a file descriptor to .xsession-errors, or
113 // another file, which could be backed by a file system that could cause
114 // dup2 to fail while trying to close stderr. It's important that we do
115 // not fail on trying to close stderr.
116 // If dup2 fails here, we will continue normally, this means that our
117 // parent won't cause a fatal failure if something writes to stderr in
118 // this child.
119 }
120 if (HANDLE_EINTR(close(fds[1]))) {
121 WriteFailedStderrSetupMessage(fds[1]);
122 SANDBOX_DIE(NULL);
123 }
106 124
107 // Run our code in the sandbox 125 evaluators_.clear();
108 CodeInSandbox(); 126 setSandboxPolicy(syscallEvaluator, NULL);
109 } 127 setProcFd(proc_fd);
128
129 // By passing "quiet=true" to "startSandboxInternal()" we suppress
130 // messages for expected and benign failures (e.g. if the current
131 // kernel lacks support for BPF filters).
132 startSandboxInternal(true);
133
134 // Run our code in the sandbox.
135 CodeInSandbox();
136
137 // CodeInSandbox() is not supposed to return here.
110 SANDBOX_DIE(NULL); 138 SANDBOX_DIE(NULL);
111 } 139 }
112 140
113 // In the parent process. 141 // In the parent process.
114 if (HANDLE_EINTR(close(fds[1]))) { 142 if (HANDLE_EINTR(close(fds[1]))) {
115 SANDBOX_DIE("close() failed"); 143 SANDBOX_DIE("close() failed");
116 } 144 }
117 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { 145 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) {
118 SANDBOX_DIE("sigprocmask() failed"); 146 SANDBOX_DIE("sigprocmask() failed");
119 } 147 }
120 int status; 148 int status;
121 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { 149 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) {
122 SANDBOX_DIE("waitpid() failed unexpectedly"); 150 SANDBOX_DIE("waitpid() failed unexpectedly");
123 } 151 }
124 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == 100; 152 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode;
125 153
126 // If we fail to support sandboxing, there might be an additional 154 // If we fail to support sandboxing, there might be an additional
127 // error message. If so, this was an entirely unexpected and fatal 155 // error message. If so, this was an entirely unexpected and fatal
128 // failure. We should report the failure and somebody must fix 156 // failure. We should report the failure and somebody must fix
129 // things. This is probably a security-critical bug in the sandboxing 157 // things. This is probably a security-critical bug in the sandboxing
130 // code. 158 // code.
131 if (!rc) { 159 if (!rc) {
132 char buf[4096]; 160 char buf[4096];
133 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); 161 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1));
134 if (len > 0) { 162 if (len > 0) {
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; 749 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN;
722 int Sandbox::proc_fd_ = -1; 750 int Sandbox::proc_fd_ = -1;
723 Sandbox::Evaluators Sandbox::evaluators_; 751 Sandbox::Evaluators Sandbox::evaluators_;
724 Sandbox::ErrMap Sandbox::errMap_; 752 Sandbox::ErrMap Sandbox::errMap_;
725 Sandbox::Traps *Sandbox::traps_ = NULL; 753 Sandbox::Traps *Sandbox::traps_ = NULL;
726 Sandbox::TrapIds Sandbox::trapIds_; 754 Sandbox::TrapIds Sandbox::trapIds_;
727 ErrorCode *Sandbox::trapArray_ = NULL; 755 ErrorCode *Sandbox::trapArray_ = NULL;
728 size_t Sandbox::trapArraySize_ = 0; 756 size_t Sandbox::trapArraySize_ = 0;
729 757
730 } // namespace 758 } // 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