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

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') | content/gpu/gpu_main.cc » ('J')
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/filter.h>
12 #include <signal.h>
13 #include <stdio.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 namespace {
36
37 static void CheckSingleThreaded() {
jln (very slow on Chromium) 2012/04/12 17:54:14 This is racy if potentially created threads can cr
38 char proc_name[64];
39 snprintf(proc_name, sizeof(proc_name), "/proc/%d/task", getpid());
40 FilePath path(proc_name);
41 int num_threads = file_util::CountFilesCreatedAfter(
42 path, base::Time::UnixEpoch());
43 CHECK_EQ(num_threads, 1);
44 }
45
46 static void SIGSYS_Handler(int signal, siginfo_t* info, void* void_context) {
47 if (signal != SIGSYS)
48 return;
49 if (info->si_code != SYS_SECCOMP)
50 return;
51 if (!void_context)
52 return;
53 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
54 unsigned int syscall = context->uc_mcontext.gregs[REG_RAX];
Will Drewry 2012/04/12 01:08:56 I guess this is easier than wrangling asm/siginfo?
Chris Evans 2012/04/12 18:42:49 Yeah, and it's also the way the Will / Kees exampl
Kees Cook 2012/04/12 18:56:39 Will found a way to include the kernel's siginfo.h
55 if (syscall >= 1024)
56 syscall = 0;
57 // Purposefully dereference the syscall as an address so it'll show up very
58 // clearly and easily in crash dumps.
59 volatile char* addr = reinterpret_cast<volatile char*>(syscall);
60 *addr = '\0';
61 _exit(1);
62 }
63
64 static void InstallSIGSYSHandler() {
65 struct sigaction sa;
66 memset(&sa, 0, sizeof(sa));
67 sa.sa_flags = SA_SIGINFO;
68 sa.sa_sigaction = SIGSYS_Handler;
69 int ret = sigaction(SIGSYS, &sa, NULL);
70 PLOG_IF(FATAL, ret != 0) << "Failed to install SIGSYS handler.";
71 }
72
73 static void EmitPreamble(std::vector<struct sock_filter>* program) {
74 struct sock_filter filter;
75 // First, check syscall arch.
76 filter.code = BPF_LD+BPF_W+BPF_ABS;
77 filter.jt = 0;
78 filter.jf = 0;
79 // Offset 4 for syscall arch.
80 filter.k = 4;
81 program->push_back(filter);
82 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
83 filter.jt = 1;
84 filter.jf = 0;
85 // AUDIT_ARCH_X86_64
86 filter.k = 0xc000003e;
87 program->push_back(filter);
88 filter.code = BPF_RET+BPF_K;
89 filter.jt = 0;
90 filter.jf = 0;
91 // SECCOMP_RET_KILL
92 filter.k = 0;
Kees Cook 2012/04/12 18:56:39 I would use the actual SECCOMP_* defines here and
93 program->push_back(filter);
94 filter.code = BPF_LD+BPF_W+BPF_ABS;
95 filter.jt = 0;
96 filter.jf = 0;
97 // Offset 0 for syscall number.
98 filter.k = 0;
99 program->push_back(filter);
100 }
101
102 static void EmitAllowSyscall(int nr, std::vector<struct sock_filter>* program) {
103 struct sock_filter filter;
104 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
105 filter.jt = 0;
106 filter.jf = 1;
107 filter.k = nr;
108 program->push_back(filter);
109 filter.code = BPF_RET+BPF_K;
110 filter.jt = 0;
111 filter.jf = 0;
112 // SECCOMP_RET_ALLOW
113 filter.k = 0x7fff0000;
114 program->push_back(filter);
115 }
116
117 static void EmitFailSyscall(int nr, int err,
118 std::vector<struct sock_filter>* program) {
119 struct sock_filter filter;
120 filter.code = BPF_JMP+BPF_JEQ+BPF_K;
121 filter.jt = 0;
122 filter.jf = 1;
123 filter.k = nr;
124 program->push_back(filter);
125 filter.code = BPF_RET+BPF_K;
126 filter.jt = 0;
127 filter.jf = 0;
128 // SECCOMP_RET_ERRNO
129 filter.k = 0x00050000 | err;
130 program->push_back(filter);
131 }
132
133 static void EmitKill(std::vector<struct sock_filter>* program) {
Will Drewry 2012/04/12 01:08:56 nit: Any reason not to call it EmitLoggedKill? Th
Chris Evans 2012/04/12 18:42:49 Ah nice catch, I did previously used SECCOMP_RET_K
134 struct sock_filter filter;
135 filter.code = BPF_RET+BPF_K;
136 filter.jt = 0;
137 filter.jf = 0;
138 // SECCOMP_RET_TRAP
139 filter.k = 0x00030000;
140 program->push_back(filter);
141 }
142
143 static void ApplyGPUPolicy(std::vector<struct sock_filter>* program) {
Will Drewry 2012/04/12 01:08:56 Is the plan to tighten this up further later?
Markus (顧孟勤) 2012/04/12 17:51:24 My ultimate plan for efficient syscall filtering i
Chris Evans 2012/04/12 18:42:49 Definitely. Once we've flushed out all the corner-
144 // "Hot" syscalls go first.
jln (very slow on Chromium) 2012/04/12 17:54:14 Looks like a very good start with a positive secur
145 EmitAllowSyscall(__NR_read, program);
146 EmitAllowSyscall(__NR_ioctl, program);
147 EmitAllowSyscall(__NR_poll, program);
148 EmitAllowSyscall(__NR_epoll_wait, program);
149 EmitAllowSyscall(__NR_recvfrom, program);
150 EmitAllowSyscall(__NR_write, program);
151 EmitAllowSyscall(__NR_writev, program);
152 EmitAllowSyscall(__NR_gettid, program);
153
154 // Less hot syscalls.
155 EmitAllowSyscall(__NR_futex, program);
156 EmitAllowSyscall(__NR_madvise, program);
157 EmitAllowSyscall(__NR_sendmsg, program);
158 EmitAllowSyscall(__NR_recvmsg, program);
159 EmitAllowSyscall(__NR_eventfd2, program);
160 EmitAllowSyscall(__NR_pipe, program);
161 EmitAllowSyscall(__NR_mmap, program);
162 EmitAllowSyscall(__NR_mprotect, program);
163 EmitAllowSyscall(__NR_clone, program);
164 EmitAllowSyscall(__NR_set_robust_list, program);
165 EmitAllowSyscall(__NR_getuid, program);
166 EmitAllowSyscall(__NR_geteuid, program);
167 EmitAllowSyscall(__NR_getgid, program);
168 EmitAllowSyscall(__NR_getegid, program);
169 EmitAllowSyscall(__NR_epoll_create, program);
170 EmitAllowSyscall(__NR_fcntl, program);
171 EmitAllowSyscall(__NR_socketpair, program);
172 EmitAllowSyscall(__NR_epoll_ctl, program);
173 EmitAllowSyscall(__NR_prctl, program);
174 EmitAllowSyscall(__NR_fstat, program);
175 EmitAllowSyscall(__NR_close, program);
176 EmitAllowSyscall(__NR_restart_syscall, program);
177 EmitAllowSyscall(__NR_rt_sigreturn, program);
178 EmitAllowSyscall(__NR_brk, program);
179 EmitAllowSyscall(__NR_rt_sigprocmask, program);
180 EmitAllowSyscall(__NR_munmap, program);
181 EmitAllowSyscall(__NR_dup, program);
182 EmitAllowSyscall(__NR_mlock, program);
183 EmitAllowSyscall(__NR_munlock, program);
184 EmitAllowSyscall(__NR_exit, program);
185 EmitAllowSyscall(__NR_exit_group, program);
186
187 EmitFailSyscall(__NR_open, ENOENT, program);
188 EmitFailSyscall(__NR_access, ENOENT, program);
189 }
190
191 static bool CanUseSeccompFilters() {
192 int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
193 if (ret != 0) {
194 if (errno == EINVAL) {
195 // This is expected: not many kernels support this yet.
196 return false;
197 }
198 PLOG(FATAL) << "prctl(PR_SET_NO_NEW_PRIVS) failed";
199 }
Will Drewry 2012/04/12 01:08:56 An authoritative check would be: ret = prctl(PR_
Markus (顧孟勤) 2012/04/12 17:51:24 If you don't mind the minimal cost of doing an ext
Chris Evans 2012/04/12 18:42:49 Thanks! Much cleaner. I moved PR_SET_NEW_PRIVS to
Kees Cook 2012/04/12 18:56:39 I wonder if the filter should test for failure ins
200 return true;
201 }
202
203 static void InstallFilter(const std::vector<struct sock_filter>& program) {
204 struct sock_fprog fprog;
205 fprog.len = program.size();
206 fprog.filter = const_cast<struct sock_filter*>(&program[0]);
207
208 int ret = prctl(PR_SET_SECCOMP, 2, &fprog, 0, 0);
209 PLOG_IF(FATAL, ret != 0) << "Failed to install filter.";
210 }
211
212 } // anonymous namespace
213
214 namespace content {
215
216 void InitializeSandbox() {
217 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
218 if (command_line.HasSwitch(switches::kNoSandbox))
219 return;
220
221 std::string process_type =
222 command_line.GetSwitchValueASCII(switches::kProcessType);
223 if (process_type == switches::kGpuProcess &&
224 command_line.HasSwitch(switches::kDisableGpuSandbox))
225 return;
226
227 CheckSingleThreaded();
228
229 if (!CanUseSeccompFilters())
230 return;
231
232 std::vector<struct sock_filter> program;
233 EmitPreamble(&program);
234
235 if (process_type == switches::kGpuProcess) {
236 ApplyGPUPolicy(&program);
237 } else {
238 NOTREACHED();
239 }
240
241 EmitKill(&program);
242
243 InstallSIGSYSHandler();
244 InstallFilter(program);
245 }
246
247 } // namespace content
248
249 #else
250
251 namespace content {
252
253 void InitializeSandbox() {
254 }
255
256 } // namespace content
257
258 #endif
259
OLDNEW
« no previous file with comments | « no previous file | content/content_common.gypi » ('j') | content/gpu/gpu_main.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698