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

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

Issue 12223109: SECCOMP-BPF: Refactor the BPF sandbox API to use fewer "static" fields and methods. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 9 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 | « sandbox/linux/seccomp-bpf/codegen.cc ('k') | sandbox/linux/seccomp-bpf/die.h » ('j') | 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 <errno.h> 5 #include <errno.h>
6 #include <fcntl.h> 6 #include <fcntl.h>
7 #include <linux/unistd.h> 7 #include <linux/unistd.h>
8 #include <netinet/in.h> 8 #include <netinet/in.h>
9 #include <netinet/tcp.h> 9 #include <netinet/tcp.h>
10 #include <netinet/udp.h> 10 #include <netinet/udp.h>
11 #include <pthread.h> 11 #include <pthread.h>
12 #include <signal.h> 12 #include <signal.h>
13 #include <stdarg.h>
13 #include <stdio.h> 14 #include <stdio.h>
14 #include <stdlib.h> 15 #include <stdlib.h>
15 #include <string.h> 16 #include <string.h>
16 #include <sys/ioctl.h> 17 #include <sys/ioctl.h>
17 #include <sys/ipc.h> 18 #include <sys/ipc.h>
18 #include <sys/mman.h> 19 #include <sys/mman.h>
19 #include <sys/prctl.h> 20 #include <sys/prctl.h>
20 #include <sys/resource.h> 21 #include <sys/resource.h>
21 #include <sys/shm.h> 22 #include <sys/shm.h>
22 #include <sys/socket.h> 23 #include <sys/socket.h>
23 #include <sys/time.h> 24 #include <sys/time.h>
24 #include <sys/types.h> 25 #include <sys/types.h>
25 #include <time.h> 26 #include <time.h>
26 #include <unistd.h> 27 #include <unistd.h>
27 28
28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
29 #include "sandbox/linux/seccomp-bpf/util.h"
30 30
31 using playground2::arch_seccomp_data; 31 using playground2::arch_seccomp_data;
32 using playground2::ErrorCode; 32 using playground2::ErrorCode;
33 using playground2::Sandbox; 33 using playground2::Sandbox;
34 using playground2::Util;
35 34
36 #define ERR EPERM 35 #define ERR EPERM
37 36
38 // We don't expect our sandbox to do anything useful yet. So, we will fail 37 // We don't expect our sandbox to do anything useful yet. So, we will fail
39 // almost immediately. For now, force the code to continue running. The 38 // almost immediately. For now, force the code to continue running. The
40 // following line should be removed as soon as the sandbox is starting to 39 // following line should be removed as soon as the sandbox is starting to
41 // actually enforce restrictions in a meaningful way: 40 // actually enforce restrictions in a meaningful way:
42 #define _exit(x) do { } while (0) 41 #define _exit(x) do { } while (0)
43 42
43 namespace {
44
45 bool SendFds(int transport, const void *buf, size_t len, ...) {
46 int count = 0;
47 va_list ap;
48 va_start(ap, len);
49 while (va_arg(ap, int) >= 0) {
50 ++count;
51 }
52 va_end(ap);
53 if (!count) {
54 return false;
55 }
56 char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
57 memset(cmsg_buf, 0, sizeof(cmsg_buf));
58 struct iovec iov[2] = { { 0 } };
59 struct msghdr msg = { 0 };
60 int dummy = 0;
61 iov[0].iov_base = &dummy;
62 iov[0].iov_len = sizeof(dummy);
63 if (buf && len > 0) {
64 iov[1].iov_base = const_cast<void *>(buf);
65 iov[1].iov_len = len;
66 }
67 msg.msg_iov = iov;
68 msg.msg_iovlen = (buf && len > 0) ? 2 : 1;
69 msg.msg_control = cmsg_buf;
70 msg.msg_controllen = CMSG_LEN(count*sizeof(int));
71 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
72 cmsg->cmsg_level = SOL_SOCKET;
73 cmsg->cmsg_type = SCM_RIGHTS;
74 cmsg->cmsg_len = CMSG_LEN(count*sizeof(int));
75 va_start(ap, len);
76 for (int i = 0, fd; (fd = va_arg(ap, int)) >= 0; ++i) {
77 (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i] = fd;
78 }
79 return sendmsg(transport, &msg, 0) ==
80 static_cast<ssize_t>(sizeof(dummy) + ((buf && len > 0) ? len : 0));
81 }
82
83 bool GetFds(int transport, void *buf, size_t *len, ...) {
84 int count = 0;
85 va_list ap;
86 va_start(ap, len);
87 for (int *fd; (fd = va_arg(ap, int *)) != NULL; ++count) {
88 *fd = -1;
89 }
90 va_end(ap);
91 if (!count) {
92 return false;
93 }
94 char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
95 memset(cmsg_buf, 0, sizeof(cmsg_buf));
96 struct iovec iov[2] = { { 0 } };
97 struct msghdr msg = { 0 };
98 int err;
99 iov[0].iov_base = &err;
100 iov[0].iov_len = sizeof(int);
101 if (buf && len && *len > 0) {
102 iov[1].iov_base = buf;
103 iov[1].iov_len = *len;
104 }
105 msg.msg_iov = iov;
106 msg.msg_iovlen = (buf && len && *len > 0) ? 2 : 1;
107 msg.msg_control = cmsg_buf;
108 msg.msg_controllen = CMSG_LEN(count*sizeof(int));
109 ssize_t bytes = recvmsg(transport, &msg, 0);
110 if (len) {
111 *len = bytes > static_cast<int>(sizeof(int)) ? bytes - sizeof(int) : 0;
112 }
113 if (bytes != static_cast<ssize_t>(sizeof(int) + iov[1].iov_len)) {
114 if (bytes >= 0) {
115 errno = 0;
116 }
117 return false;
118 }
119 if (err) {
120 // "err" is the first four bytes of the payload. If these are non-zero,
121 // the sender on the other side of the socketpair sent us an errno value.
122 // We don't expect to get any file handles in this case.
123 errno = err;
124 return false;
125 }
126 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
127 if ((msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) ||
128 !cmsg ||
129 cmsg->cmsg_level != SOL_SOCKET ||
130 cmsg->cmsg_type != SCM_RIGHTS ||
131 cmsg->cmsg_len != CMSG_LEN(count*sizeof(int))) {
132 errno = EBADF;
133 return false;
134 }
135 va_start(ap, len);
136 for (int *fd, i = 0; (fd = va_arg(ap, int *)) != NULL; ++i) {
137 *fd = (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i];
138 }
139 va_end(ap);
140 return true;
141 }
142
44 143
45 // POSIX doesn't define any async-signal safe function for converting 144 // POSIX doesn't define any async-signal safe function for converting
46 // an integer to ASCII. We'll have to define our own version. 145 // an integer to ASCII. We'll have to define our own version.
47 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the 146 // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
48 // conversion was successful or NULL otherwise. It never writes more than "sz" 147 // conversion was successful or NULL otherwise. It never writes more than "sz"
49 // bytes. Output will be truncated as needed, and a NUL character is always 148 // bytes. Output will be truncated as needed, and a NUL character is always
50 // appended. 149 // appended.
51 static char *itoa_r(int i, char *buf, size_t sz) { 150 char *itoa_r(int i, char *buf, size_t sz) {
52 // Make sure we can write at least one NUL byte. 151 // Make sure we can write at least one NUL byte.
53 size_t n = 1; 152 size_t n = 1;
54 if (n > sz) { 153 if (n > sz) {
55 return NULL; 154 return NULL;
56 } 155 }
57 156
58 // Handle negative numbers. 157 // Handle negative numbers.
59 char *start = buf; 158 char *start = buf;
60 int minint = 0; 159 int minint = 0;
61 if (i < 0) { 160 if (i < 0) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 } 208 }
110 return buf; 209 return buf;
111 } 210 }
112 211
113 // This handler gets called, whenever we encounter a system call that we 212 // This handler gets called, whenever we encounter a system call that we
114 // don't recognize explicitly. For the purposes of this program, we just 213 // don't recognize explicitly. For the purposes of this program, we just
115 // log the system call and then deny it. More elaborate sandbox policies 214 // log the system call and then deny it. More elaborate sandbox policies
116 // might try to evaluate the system call in user-space, instead. 215 // might try to evaluate the system call in user-space, instead.
117 // The only notable complication is that this function must be async-signal 216 // The only notable complication is that this function must be async-signal
118 // safe. This restricts the libary functions that we can call. 217 // safe. This restricts the libary functions that we can call.
119 static intptr_t defaultHandler(const struct arch_seccomp_data& data, 218 intptr_t DefaultHandler(const struct arch_seccomp_data& data, void *) {
120 void *) {
121 static const char msg0[] = "Disallowed system call #"; 219 static const char msg0[] = "Disallowed system call #";
122 static const char msg1[] = "\n"; 220 static const char msg1[] = "\n";
123 char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)]; 221 char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)];
124 222
125 *buf = '\000'; 223 *buf = '\000';
126 strncat(buf, msg0, sizeof(buf)); 224 strncat(buf, msg0, sizeof(buf));
127 225
128 char *ptr = strrchr(buf, '\000'); 226 char *ptr = strrchr(buf, '\000');
129 itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf)); 227 itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf));
130 228
131 ptr = strrchr(ptr, '\000'); 229 ptr = strrchr(ptr, '\000');
132 strncat(ptr, msg1, sizeof(buf) - (ptr - buf)); 230 strncat(ptr, msg1, sizeof(buf) - (ptr - buf));
133 231
134 ptr = strrchr(ptr, '\000'); 232 ptr = strrchr(ptr, '\000');
135 if (HANDLE_EINTR(write(2, buf, ptr - buf))) { } 233 if (HANDLE_EINTR(write(2, buf, ptr - buf))) { }
136 234
137 return -ERR; 235 return -ERR;
138 } 236 }
139 237
140 static ErrorCode evaluator(int sysno, void *) { 238 ErrorCode Evaluator(Sandbox *sandbox, int sysno, void *) {
141 switch (sysno) { 239 switch (sysno) {
142 #if defined(__NR_accept) 240 #if defined(__NR_accept)
143 case __NR_accept: case __NR_accept4: 241 case __NR_accept: case __NR_accept4:
144 #endif 242 #endif
145 case __NR_alarm: 243 case __NR_alarm:
146 case __NR_brk: 244 case __NR_brk:
147 case __NR_clock_gettime: 245 case __NR_clock_gettime:
148 case __NR_close: 246 case __NR_close:
149 case __NR_dup: case __NR_dup2: 247 case __NR_dup: case __NR_dup2:
150 case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait: 248 case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait:
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 #if defined(__NR_socketpair) 317 #if defined(__NR_socketpair)
220 case __NR_socketpair: 318 case __NR_socketpair:
221 #endif 319 #endif
222 case __NR_time: 320 case __NR_time:
223 case __NR_uname: 321 case __NR_uname:
224 case __NR_write: case __NR_writev: 322 case __NR_write: case __NR_writev:
225 return ErrorCode(ErrorCode::ERR_ALLOWED); 323 return ErrorCode(ErrorCode::ERR_ALLOWED);
226 324
227 case __NR_prctl: 325 case __NR_prctl:
228 // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else. 326 // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else.
229 return Sandbox::Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 327 return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
230 PR_SET_DUMPABLE, 328 PR_SET_DUMPABLE,
231 ErrorCode(ErrorCode::ERR_ALLOWED), 329 ErrorCode(ErrorCode::ERR_ALLOWED),
232 Sandbox::Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 330 sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
233 PR_GET_DUMPABLE, 331 PR_GET_DUMPABLE,
234 ErrorCode(ErrorCode::ERR_ALLOWED), 332 ErrorCode(ErrorCode::ERR_ALLOWED),
235 Sandbox::Trap(defaultHandler, NULL))); 333 sandbox->Trap(DefaultHandler, NULL)));
236 334
237 // The following system calls are temporarily permitted. This must be 335 // The following system calls are temporarily permitted. This must be
238 // tightened later. But we currently don't implement enough of the sandboxing 336 // tightened later. But we currently don't implement enough of the sandboxing
239 // API to do so. 337 // API to do so.
240 // As is, this sandbox isn't exactly safe :-/ 338 // As is, this sandbox isn't exactly safe :-/
241 #if defined(__NR_sendmsg) 339 #if defined(__NR_sendmsg)
242 case __NR_sendmsg: case __NR_sendto: 340 case __NR_sendmsg: case __NR_sendto:
243 case __NR_recvmsg: case __NR_recvfrom: 341 case __NR_recvmsg: case __NR_recvfrom:
244 case __NR_getsockopt: case __NR_setsockopt: 342 case __NR_getsockopt: case __NR_setsockopt:
245 #elif defined(__NR_socketcall) 343 #elif defined(__NR_socketcall)
(...skipping 14 matching lines...) Expand all
260 #endif 358 #endif
261 case __NR_getrlimit: 359 case __NR_getrlimit:
262 case __NR_ioctl: 360 case __NR_ioctl:
263 case __NR_clone: 361 case __NR_clone:
264 case __NR_munmap: case __NR_mprotect: case __NR_madvise: 362 case __NR_munmap: case __NR_mprotect: case __NR_madvise:
265 case __NR_remap_file_pages: 363 case __NR_remap_file_pages:
266 return ErrorCode(ErrorCode::ERR_ALLOWED); 364 return ErrorCode(ErrorCode::ERR_ALLOWED);
267 365
268 // Everything that isn't explicitly allowed is denied. 366 // Everything that isn't explicitly allowed is denied.
269 default: 367 default:
270 return Sandbox::Trap(defaultHandler, NULL); 368 return sandbox->Trap(DefaultHandler, NULL);
271 } 369 }
272 } 370 }
273 371
274 static void *threadFnc(void *arg) { 372 void *ThreadFnc(void *arg) {
275 return arg; 373 return arg;
276 } 374 }
277 375
278 static void *sendmsgStressThreadFnc(void *arg) { 376 void *SendmsgStressThreadFnc(void *arg) {
279 if (arg) { } 377 if (arg) { }
280 static const int repetitions = 100; 378 static const int repetitions = 100;
281 static const int kNumFds = 3; 379 static const int kNumFds = 3;
282 for (int rep = 0; rep < repetitions; ++rep) { 380 for (int rep = 0; rep < repetitions; ++rep) {
283 int fds[2 + kNumFds]; 381 int fds[2 + kNumFds];
284 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { 382 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
285 perror("socketpair()"); 383 perror("socketpair()");
286 _exit(1); 384 _exit(1);
287 } 385 }
288 size_t len = 4; 386 size_t len = 4;
289 char buf[4]; 387 char buf[4];
290 if (!Util::SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) || 388 if (!SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) ||
291 !Util::GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) || 389 !GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) ||
292 len != 4 || 390 len != 4 ||
293 memcmp(buf, "test", len) || 391 memcmp(buf, "test", len) ||
294 write(fds[2], "demo", 4) != 4 || 392 write(fds[2], "demo", 4) != 4 ||
295 read(fds[0], buf, 4) != 4 || 393 read(fds[0], buf, 4) != 4 ||
296 memcmp(buf, "demo", 4)) { 394 memcmp(buf, "demo", 4)) {
297 perror("sending/receiving of fds"); 395 perror("sending/receiving of fds");
298 _exit(1); 396 _exit(1);
299 } 397 }
300 for (int i = 0; i < 2+kNumFds; ++i) { 398 for (int i = 0; i < 2+kNumFds; ++i) {
301 if (close(fds[i])) { 399 if (close(fds[i])) {
302 perror("close"); 400 perror("close");
303 _exit(1); 401 _exit(1);
304 } 402 }
305 } 403 }
306 } 404 }
307 return NULL; 405 return NULL;
308 } 406 }
309 407
408 } // namespace
409
310 int main(int argc, char *argv[]) { 410 int main(int argc, char *argv[]) {
311 if (argc) { } 411 if (argc) { }
312 if (argv) { } 412 if (argv) { }
313 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY); 413 int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY);
314 if (Sandbox::SupportsSeccompSandbox(proc_fd) != 414 if (Sandbox::SupportsSeccompSandbox(proc_fd) !=
315 Sandbox::STATUS_AVAILABLE) { 415 Sandbox::STATUS_AVAILABLE) {
316 perror("sandbox"); 416 perror("sandbox");
317 _exit(1); 417 _exit(1);
318 } 418 }
319 Sandbox::set_proc_fd(proc_fd); 419 Sandbox sandbox;
320 Sandbox::SetSandboxPolicy(evaluator, NULL); 420 sandbox.set_proc_fd(proc_fd);
321 Sandbox::StartSandbox(); 421 sandbox.SetSandboxPolicy(Evaluator, NULL);
422 sandbox.StartSandbox();
322 423
323 // Check that we can create threads 424 // Check that we can create threads
324 pthread_t thr; 425 pthread_t thr;
325 if (!pthread_create(&thr, NULL, threadFnc, 426 if (!pthread_create(&thr, NULL, ThreadFnc,
326 reinterpret_cast<void *>(0x1234))) { 427 reinterpret_cast<void *>(0x1234))) {
327 void *ret; 428 void *ret;
328 pthread_join(thr, &ret); 429 pthread_join(thr, &ret);
329 if (ret != reinterpret_cast<void *>(0x1234)) { 430 if (ret != reinterpret_cast<void *>(0x1234)) {
330 perror("clone() failed"); 431 perror("clone() failed");
331 _exit(1); 432 _exit(1);
332 } 433 }
333 } else { 434 } else {
334 perror("clone() failed"); 435 perror("clone() failed");
335 _exit(1); 436 _exit(1);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 } 470 }
370 471
371 // Check that we can send and receive file handles. 472 // Check that we can send and receive file handles.
372 int fds[3]; 473 int fds[3];
373 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { 474 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
374 perror("socketpair()"); 475 perror("socketpair()");
375 _exit(1); 476 _exit(1);
376 } 477 }
377 size_t len = 4; 478 size_t len = 4;
378 char buf[4]; 479 char buf[4];
379 if (!Util::SendFds(fds[0], "test", 4, fds[1], -1) || 480 if (!SendFds(fds[0], "test", 4, fds[1], -1) ||
380 !Util::GetFds(fds[1], buf, &len, fds+2, NULL) || 481 !GetFds(fds[1], buf, &len, fds+2, NULL) ||
381 len != 4 || 482 len != 4 ||
382 memcmp(buf, "test", len) || 483 memcmp(buf, "test", len) ||
383 write(fds[2], "demo", 4) != 4 || 484 write(fds[2], "demo", 4) != 4 ||
384 read(fds[0], buf, 4) != 4 || 485 read(fds[0], buf, 4) != 4 ||
385 memcmp(buf, "demo", 4) || 486 memcmp(buf, "demo", 4) ||
386 close(fds[0]) || 487 close(fds[0]) ||
387 close(fds[1]) || 488 close(fds[1]) ||
388 close(fds[2])) { 489 close(fds[2])) {
389 perror("sending/receiving of fds"); 490 perror("sending/receiving of fds");
390 _exit(1); 491 _exit(1);
(...skipping 12 matching lines...) Expand all
403 504
404 // Print a message so that the user can see the sandbox is activated. 505 // Print a message so that the user can see the sandbox is activated.
405 time_t tm = time(NULL); 506 time_t tm = time(NULL);
406 printf("Sandbox has been started at %s", ctime(&tm)); 507 printf("Sandbox has been started at %s", ctime(&tm));
407 508
408 // Stress-test the sendmsg() code 509 // Stress-test the sendmsg() code
409 static const int kSendmsgStressNumThreads = 10; 510 static const int kSendmsgStressNumThreads = 10;
410 pthread_t sendmsgStressThreads[kSendmsgStressNumThreads]; 511 pthread_t sendmsgStressThreads[kSendmsgStressNumThreads];
411 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { 512 for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
412 if (pthread_create(sendmsgStressThreads + i, NULL, 513 if (pthread_create(sendmsgStressThreads + i, NULL,
413 sendmsgStressThreadFnc, NULL)) { 514 SendmsgStressThreadFnc, NULL)) {
414 perror("pthread_create"); 515 perror("pthread_create");
415 _exit(1); 516 _exit(1);
416 } 517 }
417 } 518 }
418 for (int i = 0; i < kSendmsgStressNumThreads; ++i) { 519 for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
419 pthread_join(sendmsgStressThreads[i], NULL); 520 pthread_join(sendmsgStressThreads[i], NULL);
420 } 521 }
421 522
422 return 0; 523 return 0;
423 } 524 }
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/codegen.cc ('k') | sandbox/linux/seccomp-bpf/die.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698