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/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))) { | |
Markus (顧孟勤)
2012/10/26 23:14:11
After this change, do we still expect to see these
jln (very slow on Chromium)
2012/10/29 21:15:37
That makes sense. But let's land a simple, easy to
| |
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(¤t_time) != static_cast<time_t>(-1)) { | 68 if (time(¤t_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) { | |
Markus (顧孟勤)
2012/10/26 23:14:11
Try calling HANDLE_EINTR(close(2)) first and ignor
| |
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. | |
Markus (顧孟勤)
2012/10/26 23:14:11
Do you still want this to be fatal in debug builds
jln (very slow on Chromium)
2012/10/29 21:15:37
Yeah, the first iteration of this patch, as you ca
| |
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(); | |
Markus (顧孟勤)
2012/10/26 23:14:11
I'd prefer a blank line before the comment, as I f
jln (very slow on Chromium)
2012/10/29 21:15:37
Done.
| |
139 // CodeInSandbox() is not supposed to return here. | |
113 SANDBOX_DIE(NULL); | 140 SANDBOX_DIE(NULL); |
114 } | 141 } |
115 | 142 |
116 // In the parent process. | 143 // In the parent process. |
117 if (HANDLE_EINTR(close(fds[1]))) { | 144 if (HANDLE_EINTR(close(fds[1]))) { |
118 SANDBOX_DIE("close() failed"); | 145 SANDBOX_DIE("close() failed"); |
119 } | 146 } |
120 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { | 147 if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { |
121 SANDBOX_DIE("sigprocmask() failed"); | 148 SANDBOX_DIE("sigprocmask() failed"); |
122 } | 149 } |
123 int status; | 150 int status; |
124 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { | 151 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { |
125 SANDBOX_DIE("waitpid() failed unexpectedly"); | 152 SANDBOX_DIE("waitpid() failed unexpectedly"); |
126 } | 153 } |
127 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == 100; | 154 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode; |
128 | 155 |
129 // If we fail to support sandboxing, there might be an additional | 156 // If we fail to support sandboxing, there might be an additional |
130 // error message. If so, this was an entirely unexpected and fatal | 157 // error message. If so, this was an entirely unexpected and fatal |
131 // failure. We should report the failure and somebody must fix | 158 // failure. We should report the failure and somebody must fix |
132 // things. This is probably a security-critical bug in the sandboxing | 159 // things. This is probably a security-critical bug in the sandboxing |
133 // code. | 160 // code. |
134 if (!rc) { | 161 if (!rc) { |
135 char buf[4096]; | 162 char buf[4096]; |
136 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); | 163 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); |
137 if (len > 0) { | 164 if (len > 0) { |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 643 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
617 int Sandbox::proc_fd_ = -1; | 644 int Sandbox::proc_fd_ = -1; |
618 Sandbox::Evaluators Sandbox::evaluators_; | 645 Sandbox::Evaluators Sandbox::evaluators_; |
619 Sandbox::ErrMap Sandbox::errMap_; | 646 Sandbox::ErrMap Sandbox::errMap_; |
620 Sandbox::Traps *Sandbox::traps_ = NULL; | 647 Sandbox::Traps *Sandbox::traps_ = NULL; |
621 Sandbox::TrapIds Sandbox::trapIds_; | 648 Sandbox::TrapIds Sandbox::trapIds_; |
622 ErrorCode *Sandbox::trapArray_ = NULL; | 649 ErrorCode *Sandbox::trapArray_ = NULL; |
623 size_t Sandbox::trapArraySize_ = 0; | 650 size_t Sandbox::trapArraySize_ = 0; |
624 | 651 |
625 } // namespace | 652 } // namespace |
OLD | NEW |