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

Side by Side Diff: content/common/sandbox_init_linux.cc

Issue 10051022: Add an initial Linux GPU sandbox using the seccomp filter framework. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months 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 | content/content_common.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/public/common/sandbox_init.h"
6
7 #if defined(OS_LINUX) && defined(__x86_64__)
8
9 #include <asm/unistd.h>
10 #include <errno.h>
11 #include <linux/audit.h>
12 #include <linux/filter.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <sys/prctl.h>
16 #include <ucontext.h>
17 #include <unistd.h>
18
19 #include <vector>
20
21 #include "base/command_line.h"
22 #include "base/file_util.h"
23 #include "base/logging.h"
24 #include "base/time.h"
25 #include "content/public/common/content_switches.h"
26
27 #ifndef PR_SET_NO_NEW_PRIVS
28 #define PR_SET_NO_NEW_PRIVS 38
29 #endif
30
31 #ifndef SYS_SECCOMP
32 #define SYS_SECCOMP 1
33 #endif
34
35 #ifndef __NR_eventfd2
36 #define __NR_eventfd2 290
37 #endif
38
39 // Constants from very new header files that we can't yet include.
40 #ifndef SECCOMP_MODE_FILTER
41 #define SECCOMP_MODE_FILTER 2
42 #define SECCOMP_RET_KILL 0x00000000U
43 #define SECCOMP_RET_TRAP 0x00030000U
44 #define SECCOMP_RET_ERRNO 0x00050000U
45 #define SECCOMP_RET_ALLOW 0x7fff0000U
46 #endif
47
48
49 namespace {
50
51 static void CheckSingleThreaded() {
52 int num_threads = file_util::CountFilesCreatedAfter(
53 FilePath("/proc/self/task"), base::Time::UnixEpoch());
54 // Possibly racy, but it's ok because this is more of a debug check to catch
55 // new threaded situations arising during development.
56 CHECK_EQ(num_threads, 1);
57 }
58
59 static void SIGSYS_Handler(int signal, siginfo_t* info, void* void_context) {
60 if (signal != SIGSYS)
61 return;
62 if (info->si_code != SYS_SECCOMP)
63 return;
64 if (!void_context)
65 return;
66 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
67 unsigned int syscall = context->uc_mcontext.gregs[REG_RAX];
68 if (syscall >= 1024)
69 syscall = 0;
70 // Purposefully dereference the syscall as an address so it'll show up very
71 // clearly and easily in crash dumps.
72 volatile char* addr = reinterpret_cast<volatile char*>(syscall);
73 *addr = '\0';
74 _exit(1);
75 }
76
77 static void InstallSIGSYSHandler() {
78 struct sigaction sa;
79 memset(&sa, 0, sizeof(sa));
80 sa.sa_flags = SA_SIGINFO;
81 sa.sa_sigaction = SIGSYS_Handler;
82 int ret = sigaction(SIGSYS, &sa, NULL);
83 PLOG_IF(FATAL, ret != 0) << "Failed to install SIGSYS handler.";
84 }
85
86 static void EmitPreamble(std::vector<struct sock_filter>* program) {
87 struct sock_filter filter;
88 // First, check syscall arch.
89 filter.code = BPF_LD+BPF_W+BPF_ABS;
90 filter.jt = 0;
91 filter.jf = 0;
92 // Offset 4 for syscall arch.
93 filter.k = 4;
Markus (顧孟勤) 2012/04/12 22:22:33 Instead of hardcoding the offset, you might want t
94 program->push_back(filter);
95
96 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
97 filter.jt = 1;
98 filter.jf = 0;
99 filter.k = AUDIT_ARCH_X86_64;
100 program->push_back(filter);
101
102 filter.code = BPF_RET+BPF_K;
103 filter.jt = 0;
104 filter.jf = 0;
105 filter.k = SECCOMP_RET_KILL;
106 program->push_back(filter);
107
108 filter.code = BPF_LD+BPF_W+BPF_ABS;
109 filter.jt = 0;
110 filter.jf = 0;
111 // Offset 0 for syscall number.
112 filter.k = 0;
Markus (顧孟勤) 2012/04/12 22:22:33 Same here
113 program->push_back(filter);
114 }
115
116 static void EmitAllowSyscall(int nr, std::vector<struct sock_filter>* program) {
117 struct sock_filter filter;
118 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
119 filter.jt = 0;
120 filter.jf = 1;
121 filter.k = nr;
122 program->push_back(filter);
123
124 filter.code = BPF_RET+BPF_K;
125 filter.jt = 0;
126 filter.jf = 0;
127 filter.k = SECCOMP_RET_ALLOW;
Markus (顧孟勤) 2012/04/12 22:22:33 This generates twice as many instructions as neces
128 program->push_back(filter);
129 }
130
131 static void EmitFailSyscall(int nr, int err,
132 std::vector<struct sock_filter>* program) {
Markus (顧孟勤) 2012/04/12 22:22:33 EmitAllowSyscall() is really the same as EmitFailS
133 struct sock_filter filter;
134 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
135 filter.jt = 0;
136 filter.jf = 1;
137 filter.k = nr;
138 program->push_back(filter);
139
140 filter.code = BPF_RET+BPF_K;
141 filter.jt = 0;
142 filter.jf = 0;
143 filter.k = SECCOMP_RET_ERRNO | err;
144 program->push_back(filter);
145 }
146
147 static void EmitTrap(std::vector<struct sock_filter>* program) {
148 struct sock_filter filter;
149 filter.code = BPF_RET+BPF_K;
150 filter.jt = 0;
151 filter.jf = 0;
152 filter.k = SECCOMP_RET_TRAP;
153 program->push_back(filter);
154 }
155
156 static void ApplyGPUPolicy(std::vector<struct sock_filter>* program) {
157 // "Hot" syscalls go first.
158 EmitAllowSyscall(__NR_read, program);
159 EmitAllowSyscall(__NR_ioctl, program);
Markus (顧孟勤) 2012/04/12 22:22:33 That sound dangerous. There are way too many thing
160 EmitAllowSyscall(__NR_poll, program);
161 EmitAllowSyscall(__NR_epoll_wait, program);
162 EmitAllowSyscall(__NR_recvfrom, program);
163 EmitAllowSyscall(__NR_write, program);
164 EmitAllowSyscall(__NR_writev, program);
165 EmitAllowSyscall(__NR_gettid, program);
166
167 // Less hot syscalls.
168 EmitAllowSyscall(__NR_futex, program);
169 EmitAllowSyscall(__NR_madvise, program);
Markus (顧孟勤) 2012/04/12 22:22:33 The memory functions (madvise, mmap, munmap, mprot
170 EmitAllowSyscall(__NR_sendmsg, program);
Markus (顧孟勤) 2012/04/12 22:22:33 sendmsg() is potentially dangerous. At the very le
171 EmitAllowSyscall(__NR_recvmsg, program);
172 EmitAllowSyscall(__NR_eventfd2, program);
173 EmitAllowSyscall(__NR_pipe, program);
174 EmitAllowSyscall(__NR_mmap, program);
175 EmitAllowSyscall(__NR_mprotect, program);
176 EmitAllowSyscall(__NR_clone, program);
Markus (顧孟勤) 2012/04/12 22:22:33 clone() can have surprising semantics. I'd suggest
177 EmitAllowSyscall(__NR_set_robust_list, program);
178 EmitAllowSyscall(__NR_getuid, program);
179 EmitAllowSyscall(__NR_geteuid, program);
180 EmitAllowSyscall(__NR_getgid, program);
181 EmitAllowSyscall(__NR_getegid, program);
182 EmitAllowSyscall(__NR_epoll_create, program);
183 EmitAllowSyscall(__NR_fcntl, program);
184 EmitAllowSyscall(__NR_socketpair, program);
185 EmitAllowSyscall(__NR_epoll_ctl, program);
186 EmitAllowSyscall(__NR_prctl, program);
Markus (顧孟勤) 2012/04/12 22:22:33 I would strongly encourage you to limit prctl() to
187 EmitAllowSyscall(__NR_fstat, program);
188 EmitAllowSyscall(__NR_close, program);
189 EmitAllowSyscall(__NR_restart_syscall, program);
Markus (顧孟勤) 2012/04/12 22:22:33 Is this actually visible to seccomp/BPF? I thought
jln (very slow on Chromium) 2012/04/12 22:36:47 Yes, the kernel puts them on the user stack when i
190 EmitAllowSyscall(__NR_rt_sigreturn, program);
191 EmitAllowSyscall(__NR_brk, program);
192 EmitAllowSyscall(__NR_rt_sigprocmask, program);
193 EmitAllowSyscall(__NR_munmap, program);
194 EmitAllowSyscall(__NR_dup, program);
195 EmitAllowSyscall(__NR_mlock, program);
196 EmitAllowSyscall(__NR_munlock, program);
197 EmitAllowSyscall(__NR_exit, program);
198 EmitAllowSyscall(__NR_exit_group, program);
199
200 EmitFailSyscall(__NR_open, ENOENT, program);
201 EmitFailSyscall(__NR_access, ENOENT, program);
202 }
203
204 static bool CanUseSeccompFilters() {
205 int ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0, 0, 0);
206 if (ret != 0 && errno == EFAULT)
207 return true;
208 return false;
209 }
210
211 static void InstallFilter(const std::vector<struct sock_filter>& program) {
212 int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
213 PLOG_IF(FATAL, ret != 0) << "prctl(PR_SET_NO_NEW_PRIVS) failed";
214
215 struct sock_fprog fprog;
216 fprog.len = program.size();
217 fprog.filter = const_cast<struct sock_filter*>(&program[0]);
218
219 ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &fprog, 0, 0);
220 PLOG_IF(FATAL, ret != 0) << "Failed to install filter.";
221 }
222
223 } // anonymous namespace
224
225 namespace content {
226
227 void InitializeSandbox() {
228 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
229 if (command_line.HasSwitch(switches::kNoSandbox))
230 return;
231
232 std::string process_type =
233 command_line.GetSwitchValueASCII(switches::kProcessType);
234 if (process_type == switches::kGpuProcess &&
235 command_line.HasSwitch(switches::kDisableGpuSandbox))
236 return;
237
238 CheckSingleThreaded();
239
240 if (!CanUseSeccompFilters())
241 return;
242
243 std::vector<struct sock_filter> program;
244 EmitPreamble(&program);
245
246 if (process_type == switches::kGpuProcess) {
247 ApplyGPUPolicy(&program);
248 } else {
249 NOTREACHED();
250 }
251
252 EmitTrap(&program);
253
254 InstallSIGSYSHandler();
255 InstallFilter(program);
256 }
257
258 } // namespace content
259
260 #else
261
262 namespace content {
263
264 void InitializeSandbox() {
265 }
266
267 } // namespace content
268
269 #endif
270
OLDNEW
« no previous file with comments | « no previous file | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698