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

Side by Side Diff: sandbox/linux/seccomp/tests/test_syscalls.cc

Issue 3225010: Pull seccomp-sandbox in via DEPS rather than using an in-tree copy... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 3 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/tests/list_tests.py ('k') | sandbox/linux/seccomp/timestats.cc » ('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) 2010 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 <assert.h>
6 #include <dirent.h>
7 #include <pthread.h>
8 #include <pty.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11
12 #include "sandbox_impl.h"
13
14 #ifdef DEBUG
15 #define MSG(fmt, ...) printf(fmt, ##__VA_ARGS__)
16 #else
17 #define MSG(fmt, ...) do { } while (0)
18 #endif
19
20 int g_intended_status_fd = -1;
21
22 // Declares the wait() status that the test subprocess intends to exit with.
23 void intend_exit_status(int val, bool is_signal) {
24 if (is_signal) {
25 val = W_EXITCODE(0, val);
26 } else {
27 val = W_EXITCODE(val, 0);
28 }
29 if (g_intended_status_fd != -1) {
30 int sent = write(g_intended_status_fd, &val, sizeof(val));
31 assert(sent == sizeof(val));
32 } else {
33 // This prints in cases where we run one test without forking
34 printf("Intending to exit with status %i...\n", val);
35 }
36 }
37
38
39 // This is basically a marker to grep for.
40 #define TEST(name) void name()
41
42 TEST(test_dup) {
43 StartSeccompSandbox();
44 // Test a simple syscall that is marked as UNRESTRICTED_SYSCALL.
45 int fd = dup(1);
46 assert(fd >= 0);
47 int rc = close(fd);
48 assert(rc == 0);
49 }
50
51 TEST(test_segfault) {
52 StartSeccompSandbox();
53 // Check that the sandbox's SIGSEGV handler does not stop the
54 // process from dying cleanly in the event of a real segfault.
55 intend_exit_status(SIGSEGV, true);
56 asm("hlt");
57 }
58
59 TEST(test_exit) {
60 StartSeccompSandbox();
61 intend_exit_status(123, false);
62 _exit(123);
63 }
64
65 // This has an off-by-three error because it counts ".", "..", and the
66 // FD for the /proc/self/fd directory. This doesn't matter because it
67 // is only used to check for differences in the number of open FDs.
68 static int count_fds() {
69 DIR *dir = opendir("/proc/self/fd");
70 assert(dir != NULL);
71 int count = 0;
72 while (1) {
73 struct dirent *d = readdir(dir);
74 if (d == NULL)
75 break;
76 count++;
77 }
78 int rc = closedir(dir);
79 assert(rc == 0);
80 return count;
81 }
82
83 static void *thread_func(void *x) {
84 int *ptr = (int *) x;
85 *ptr = 123;
86 MSG("In new thread\n");
87 return (void *) 456;
88 }
89
90 TEST(test_thread) {
91 playground::g_policy.allow_file_namespace = true; // To allow count_fds()
92 StartSeccompSandbox();
93 int fd_count1 = count_fds();
94 pthread_t tid;
95 int x = 999;
96 void *result;
97 pthread_create(&tid, NULL, thread_func, &x);
98 MSG("Waiting for thread\n");
99 pthread_join(tid, &result);
100 assert(result == (void *) 456);
101 assert(x == 123);
102 // Check that the process has not leaked FDs.
103 int fd_count2 = count_fds();
104 assert(fd_count2 == fd_count1);
105 }
106
107 static int clone_func(void *x) {
108 int *ptr = (int *) x;
109 *ptr = 124;
110 MSG("In thread\n");
111 // On x86-64, returning from this function calls the __NR_exit_group
112 // syscall instead of __NR_exit.
113 syscall(__NR_exit, 100);
114 // Not reached.
115 return 200;
116 }
117
118 #if defined(__i386__)
119 static int get_gs() {
120 int gs;
121 asm volatile("mov %%gs, %0" : "=r"(gs));
122 return gs;
123 }
124 #endif
125
126 static void *get_tls_base() {
127 void *base;
128 #if defined(__x86_64__)
129 asm volatile("mov %%fs:0, %0" : "=r"(base));
130 #elif defined(__i386__)
131 asm volatile("mov %%gs:0, %0" : "=r"(base));
132 #else
133 #error Unsupported target platform
134 #endif
135 return base;
136 }
137
138 TEST(test_clone) {
139 playground::g_policy.allow_file_namespace = true; // To allow count_fds()
140 StartSeccompSandbox();
141 int fd_count1 = count_fds();
142 int stack_size = 0x1000;
143 char *stack = (char *) malloc(stack_size);
144 assert(stack != NULL);
145 int flags = CLONE_VM | CLONE_FS | CLONE_FILES |
146 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
147 CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
148 int tid = -1;
149 int x = 999;
150
151 // The sandbox requires us to pass CLONE_TLS. Pass settings that
152 // are enough to copy the parent thread's TLS setup. This allows us
153 // to invoke libc in the child thread.
154 #if defined(__x86_64__)
155 void *tls = get_tls_base();
156 #elif defined(__i386__)
157 struct user_desc tls_desc, *tls = &tls_desc;
158 tls_desc.entry_number = get_gs() >> 3;
159 tls_desc.base_addr = (long) get_tls_base();
160 tls_desc.limit = 0xfffff;
161 tls_desc.seg_32bit = 1;
162 tls_desc.contents = 0;
163 tls_desc.read_exec_only = 0;
164 tls_desc.limit_in_pages = 1;
165 tls_desc.seg_not_present = 0;
166 tls_desc.useable = 1;
167 #else
168 #error Unsupported target platform
169 #endif
170
171 int rc = clone(clone_func, (void *) (stack + stack_size), flags, &x,
172 &tid, tls, &tid);
173 assert(rc > 0);
174 while (tid == rc) {
175 syscall(__NR_futex, &tid, FUTEX_WAIT, rc, NULL);
176 }
177 assert(tid == 0);
178 assert(x == 124);
179 // Check that the process has not leaked FDs.
180 int fd_count2 = count_fds();
181 assert(fd_count2 == fd_count1);
182 }
183
184 static int uncalled_clone_func(void *x) {
185 printf("In thread func, which shouldn't happen\n");
186 return 1;
187 }
188
189 TEST(test_clone_disallowed_flags) {
190 StartSeccompSandbox();
191 int stack_size = 4096;
192 char *stack = (char *) malloc(stack_size);
193 assert(stack != NULL);
194 /* We omit the flags CLONE_SETTLS, CLONE_PARENT_SETTID and
195 CLONE_CHILD_CLEARTID, which is disallowed by the sandbox. */
196 int flags = CLONE_VM | CLONE_FS | CLONE_FILES |
197 CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
198 int rc = clone(uncalled_clone_func, (void *) (stack + stack_size),
199 flags, NULL, NULL, NULL, NULL);
200 assert(rc == -1);
201 assert(errno == EPERM);
202 }
203
204 static void *fp_thread(void *x) {
205 int val;
206 asm("movss %%xmm0, %0" : "=m"(val));
207 MSG("val=%i\n", val);
208 return NULL;
209 }
210
211 TEST(test_fp_regs) {
212 StartSeccompSandbox();
213 int val = 1234;
214 asm("movss %0, %%xmm0" : "=m"(val));
215 pthread_t tid;
216 pthread_create(&tid, NULL, fp_thread, NULL);
217 pthread_join(tid, NULL);
218 MSG("thread done OK\n");
219 }
220
221 static long long read_tsc() {
222 long long rc;
223 asm volatile(
224 "rdtsc\n"
225 "mov %%eax, (%0)\n"
226 "mov %%edx, 4(%0)\n"
227 :
228 : "c"(&rc), "a"(-1), "d"(-1));
229 return rc;
230 }
231
232 TEST(test_rdtsc) {
233 StartSeccompSandbox();
234 // Just check that we can do the instruction.
235 read_tsc();
236 }
237
238 TEST(test_getpid) {
239 int pid1 = getpid();
240 StartSeccompSandbox();
241 int pid2 = getpid();
242 assert(pid1 == pid2);
243 // Bypass any caching that glibc's getpid() wrapper might do.
244 int pid3 = syscall(__NR_getpid);
245 assert(pid1 == pid3);
246 }
247
248 TEST(test_gettid) {
249 // glibc doesn't provide a gettid() wrapper.
250 int tid1 = syscall(__NR_gettid);
251 assert(tid1 > 0);
252 StartSeccompSandbox();
253 int tid2 = syscall(__NR_gettid);
254 assert(tid1 == tid2);
255 }
256
257 static void *map_something() {
258 void *addr = mmap(NULL, 0x1000, PROT_READ,
259 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
260 assert(addr != MAP_FAILED);
261 return addr;
262 }
263
264 TEST(test_mmap_disallows_remapping) {
265 void *addr = map_something();
266 StartSeccompSandbox();
267 // Overwriting a mapping that was created before the sandbox was
268 // enabled is not allowed.
269 void *result = mmap(addr, 0x1000, PROT_READ,
270 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
271 assert(result == MAP_FAILED);
272 assert(errno == EINVAL);
273 }
274
275 TEST(test_mmap_disallows_low_address) {
276 StartSeccompSandbox();
277 // Mapping pages at low addresses is not allowed because this helps
278 // with exploiting buggy kernels.
279 void *result = mmap(NULL, 0x1000, PROT_READ,
280 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
281 assert(result == MAP_FAILED);
282 assert(errno == EINVAL);
283 }
284
285 TEST(test_munmap_allowed) {
286 StartSeccompSandbox();
287 void *addr = map_something();
288 int result = munmap(addr, 0x1000);
289 assert(result == 0);
290 }
291
292 TEST(test_munmap_disallowed) {
293 void *addr = map_something();
294 StartSeccompSandbox();
295 int result = munmap(addr, 0x1000);
296 assert(result == -1);
297 assert(errno == EINVAL);
298 }
299
300 TEST(test_mprotect_allowed) {
301 StartSeccompSandbox();
302 void *addr = map_something();
303 int result = mprotect(addr, 0x1000, PROT_READ | PROT_WRITE);
304 assert(result == 0);
305 }
306
307 TEST(test_mprotect_disallowed) {
308 void *addr = map_something();
309 StartSeccompSandbox();
310 int result = mprotect(addr, 0x1000, PROT_READ | PROT_WRITE);
311 assert(result == -1);
312 assert(errno == EINVAL);
313 }
314
315 static int get_tty_fd() {
316 int master_fd, tty_fd;
317 int rc = openpty(&master_fd, &tty_fd, NULL, NULL, NULL);
318 assert(rc == 0);
319 return tty_fd;
320 }
321
322 TEST(test_ioctl_tiocgwinsz_allowed) {
323 int tty_fd = get_tty_fd();
324 StartSeccompSandbox();
325 int size[2];
326 // Get terminal width and height.
327 int result = ioctl(tty_fd, TIOCGWINSZ, size);
328 assert(result == 0);
329 }
330
331 TEST(test_ioctl_disallowed) {
332 int tty_fd = get_tty_fd();
333 StartSeccompSandbox();
334 // This ioctl call inserts a character into the tty's input queue,
335 // which provides a way to send commands to an interactive shell.
336 char c = 'x';
337 int result = ioctl(tty_fd, TIOCSTI, &c);
338 assert(result == -1);
339 assert(errno == EINVAL);
340 }
341
342 TEST(test_socket) {
343 StartSeccompSandbox();
344 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
345 assert(fd == -1);
346 // TODO: Make it consistent between i386 and x86-64.
347 assert(errno == EINVAL || errno == ENOSYS);
348 }
349
350 TEST(test_open_disabled) {
351 StartSeccompSandbox();
352 int fd = open("/dev/null", O_RDONLY);
353 assert(fd == -1);
354 assert(errno == EACCES);
355
356 // Writing to the policy flag does not change this.
357 playground::g_policy.allow_file_namespace = true;
358 fd = open("/dev/null", O_RDONLY);
359 assert(fd == -1);
360 assert(errno == EACCES);
361 }
362
363 TEST(test_open_enabled) {
364 playground::g_policy.allow_file_namespace = true;
365 StartSeccompSandbox();
366 int fd = open("/dev/null", O_RDONLY);
367 assert(fd >= 0);
368 int rc = close(fd);
369 assert(rc == 0);
370 fd = open("/dev/null", O_WRONLY);
371 assert(fd == -1);
372 assert(errno == EACCES);
373 }
374
375 TEST(test_access_disabled) {
376 StartSeccompSandbox();
377 int rc = access("/dev/null", R_OK);
378 assert(rc == -1);
379 assert(errno == EACCES);
380 }
381
382 TEST(test_access_enabled) {
383 playground::g_policy.allow_file_namespace = true;
384 StartSeccompSandbox();
385 int rc = access("/dev/null", R_OK);
386 assert(rc == 0);
387 rc = access("path-that-does-not-exist", R_OK);
388 assert(rc == -1);
389 assert(errno == ENOENT);
390 }
391
392 TEST(test_stat_disabled) {
393 StartSeccompSandbox();
394 struct stat st;
395 int rc = stat("/dev/null", &st);
396 assert(rc == -1);
397 assert(errno == EACCES);
398 }
399
400 TEST(test_stat_enabled) {
401 playground::g_policy.allow_file_namespace = true;
402 StartSeccompSandbox();
403 struct stat st;
404 int rc = stat("/dev/null", &st);
405 assert(rc == 0);
406 rc = stat("path-that-does-not-exist", &st);
407 assert(rc == -1);
408 assert(errno == ENOENT);
409 }
410
411 static int g_value;
412
413 static void signal_handler(int sig) {
414 g_value = 300;
415 MSG("In signal handler\n");
416 }
417
418 static void sigaction_handler(int sig, siginfo_t *a, void *b) {
419 g_value = 300;
420 MSG("In sigaction handler\n");
421 }
422
423 static void (*g_sig_handler_ptr)(int sig, void *addr) asm("g_sig_handler_ptr");
424
425 static void non_fatal_sig_handler(int sig, void *addr) {
426 g_value = 300;
427 MSG("Caught signal %d at %p\n", sig, addr);
428 }
429
430 static void fatal_sig_handler(int sig, void *addr) {
431 // Recursively trigger another segmentation fault while already in the SEGV
432 // handler. This should terminate the program if SIGSEGV is marked as a
433 // deferred signal.
434 // Only do this on the first entry to this function. Otherwise, the signal
435 // handler was probably marked as SA_NODEFER and we want to continue
436 // execution.
437 if (!g_value++) {
438 MSG("Caught signal %d at %p\n", sig, addr);
439 if (sig == SIGSEGV) {
440 asm volatile("hlt");
441 } else {
442 asm volatile("int3");
443 }
444 }
445 }
446
447 static void (*generic_signal_handler(void))
448 (int signo, siginfo_t *info, void *context) {
449 void (*hdl)(int, siginfo_t *, void *);
450 asm volatile(
451 "lea 0f, %0\n"
452 "jmp 999f\n"
453 "0:\n"
454
455 #if defined(__x86_64__)
456 "mov 0xB0(%%rsp), %%rsi\n" // Pass original %rip to signal handler
457 "cmpb $0xF4, 0(%%rsi)\n" // hlt
458 "jnz 1f\n"
459 "addq $1, 0xB0(%%rsp)\n" // Adjust %eip past failing instruction
460 "1:jmp *g_sig_handler_ptr\n" // Call actual signal handler
461 #elif defined(__i386__)
462 // TODO(markus): We currently don't guarantee that signal handlers always
463 // have the correct "magic" restorer function. If we fix
464 // this, we should add a test for it (both for SEGV and
465 // non-SEGV).
466 "cmpw $0, 0xA(%%esp)\n"
467 "lea 0x40(%%esp), %%eax\n" // %eip at time of exception
468 "jz 1f\n"
469 "add $0x9C, %%eax\n" // %eip at time of exception
470 "1:mov 0(%%eax), %%ecx\n"
471 "cmpb $0xF4, 0(%%ecx)\n" // hlt
472 "jnz 2f\n"
473 "addl $1, 0(%%eax)\n" // Adjust %eip past failing instruction
474 "2:push %%ecx\n" // Pass original %eip to signal handler
475 "mov 8(%%esp), %%eax\n"
476 "push %%eax\n" // Pass signal number to signal handler
477 "call *g_sig_handler_ptr\n" // Call actual signal handler
478 "pop %%eax\n"
479 "pop %%ecx\n"
480 "ret\n"
481 #else
482 #error Unsupported target platform
483 #endif
484
485 "999:\n"
486 : "=r"(hdl));
487 return hdl;
488 }
489
490 TEST(test_signal_handler) {
491 sighandler_t result = signal(SIGTRAP, signal_handler);
492 assert(result != SIG_ERR);
493
494 StartSeccompSandbox();
495
496 result = signal(SIGTRAP, signal_handler);
497 assert(result != SIG_ERR);
498
499 g_value = 200;
500 asm("int3");
501 assert(g_value == 300);
502 }
503
504 TEST(test_sigaction_handler) {
505 struct sigaction act;
506 act.sa_sigaction = sigaction_handler;
507 sigemptyset(&act.sa_mask);
508 act.sa_flags = SA_SIGINFO;
509 int rc = sigaction(SIGTRAP, &act, NULL);
510 assert(rc == 0);
511
512 StartSeccompSandbox();
513
514 rc = sigaction(SIGTRAP, &act, NULL);
515 assert(rc == 0);
516
517 g_value = 200;
518 asm("int3");
519 assert(g_value == 300);
520 }
521
522 TEST(test_blocked_signal) {
523 sighandler_t result = signal(SIGTRAP, signal_handler);
524 assert(result != SIG_ERR);
525 StartSeccompSandbox();
526
527 // Initially the signal should not be blocked.
528 sigset_t sigs;
529 sigfillset(&sigs);
530 int rc = sigprocmask(0, NULL, &sigs);
531 assert(rc == 0);
532 assert(!sigismember(&sigs, SIGTRAP));
533
534 sigemptyset(&sigs);
535 sigaddset(&sigs, SIGTRAP);
536 rc = sigprocmask(SIG_BLOCK, &sigs, NULL);
537 assert(rc == 0);
538
539 // Check that we can read back the blocked status.
540 sigemptyset(&sigs);
541 rc = sigprocmask(0, NULL, &sigs);
542 assert(rc == 0);
543 assert(sigismember(&sigs, SIGTRAP));
544
545 // Check that the signal handler really is blocked.
546 intend_exit_status(SIGTRAP, true);
547 asm("int3");
548 }
549
550 TEST(test_sigaltstack) {
551 // The sandbox does not support sigaltstack() yet. Just test that
552 // it returns an error.
553 StartSeccompSandbox();
554 stack_t st;
555 st.ss_size = 0x4000;
556 st.ss_sp = malloc(st.ss_size);
557 assert(st.ss_sp != NULL);
558 st.ss_flags = 0;
559 int rc = sigaltstack(&st, NULL);
560 assert(rc == -1);
561 assert(errno == ENOSYS);
562 }
563
564 TEST(test_sa_flags) {
565 StartSeccompSandbox();
566 int flags[4] = { 0, SA_NODEFER, SA_SIGINFO, SA_SIGINFO | SA_NODEFER };
567 for (int i = 0; i < 4; ++i) {
568 struct sigaction sa;
569 memset(&sa, 0, sizeof(sa));
570 sa.sa_sigaction = generic_signal_handler();
571 g_sig_handler_ptr = non_fatal_sig_handler;
572 sa.sa_flags = flags[i];
573
574 // Test SEGV handling
575 g_value = 200;
576 sigaction(SIGSEGV, &sa, NULL);
577 asm volatile("hlt");
578 assert(g_value == 300);
579
580 // Test non-SEGV handling
581 g_value = 200;
582 sigaction(SIGTRAP, &sa, NULL);
583 asm volatile("int3");
584 assert(g_value == 300);
585 }
586 }
587
588 TEST(test_segv_defer) {
589 StartSeccompSandbox();
590 struct sigaction sa;
591 memset(&sa, 0, sizeof(sa));
592 sa.sa_sigaction = generic_signal_handler();
593 g_sig_handler_ptr = fatal_sig_handler;
594
595 // Test non-deferred SEGV (should continue execution)
596 sa.sa_flags = SA_NODEFER;
597 sigaction(SIGSEGV, &sa, NULL);
598 g_value = 0;
599 asm volatile("hlt");
600
601 // Test deferred SEGV (should terminate program)
602 sa.sa_flags = 0;
603 sigaction(SIGSEGV, &sa, NULL);
604 g_value = 0;
605 intend_exit_status(SIGSEGV, true);
606 asm volatile("hlt");
607 }
608
609 TEST(test_trap_defer) {
610 StartSeccompSandbox();
611 struct sigaction sa;
612 memset(&sa, 0, sizeof(sa));
613 sa.sa_sigaction = generic_signal_handler();
614 g_sig_handler_ptr = fatal_sig_handler;
615
616 // Test non-deferred TRAP (should continue execution)
617 sa.sa_flags = SA_NODEFER;
618 sigaction(SIGTRAP, &sa, NULL);
619 g_value = 0;
620 asm volatile("int3");
621
622 // Test deferred TRAP (should terminate program)
623 sa.sa_flags = 0;
624 sigaction(SIGTRAP, &sa, NULL);
625 g_value = 0;
626 intend_exit_status(SIGTRAP, true);
627 asm volatile("int3");
628 }
629
630 TEST(test_segv_resethand) {
631 StartSeccompSandbox();
632 struct sigaction sa;
633 memset(&sa, 0, sizeof(sa));
634 sa.sa_sigaction = generic_signal_handler();
635 g_sig_handler_ptr = non_fatal_sig_handler;
636 sa.sa_flags = SA_RESETHAND;
637 sigaction(SIGSEGV, &sa, NULL);
638
639 // Test first invocation of signal handler (should continue execution)
640 asm volatile("hlt");
641
642 // Test second invocation of signal handler (should terminate program)
643 intend_exit_status(SIGSEGV, true);
644 asm volatile("hlt");
645 }
646
647 TEST(test_trap_resethand) {
648 StartSeccompSandbox();
649 struct sigaction sa;
650 memset(&sa, 0, sizeof(sa));
651 sa.sa_sigaction = generic_signal_handler();
652 g_sig_handler_ptr = non_fatal_sig_handler;
653 sa.sa_flags = SA_RESETHAND;
654 sigaction(SIGTRAP, &sa, NULL);
655
656 // Test first invocation of signal handler (should continue execution)
657 asm volatile("int3");
658
659 // Test second invocation of signal handler (should terminate program)
660 intend_exit_status(SIGTRAP, true);
661 asm volatile("int3");
662 }
663
664 struct testcase {
665 const char *test_name;
666 void (*test_func)();
667 };
668
669 struct testcase all_tests[] = {
670 #include "test-list.h"
671 { NULL, NULL },
672 };
673
674 static int run_test_forked(struct testcase *test) {
675 printf("** %s\n", test->test_name);
676 int pipe_fds[2];
677 int rc = pipe(pipe_fds);
678 assert(rc == 0);
679 int pid = fork();
680 if (pid == 0) {
681 rc = close(pipe_fds[0]);
682 assert(rc == 0);
683 g_intended_status_fd = pipe_fds[1];
684
685 test->test_func();
686 intend_exit_status(0, false);
687 _exit(0);
688 }
689 rc = close(pipe_fds[1]);
690 assert(rc == 0);
691
692 int intended_status;
693 int got = read(pipe_fds[0], &intended_status, sizeof(intended_status));
694 bool got_intended_status = got == sizeof(intended_status);
695 if (!got_intended_status) {
696 printf("Test runner: Did not receive intended status\n");
697 }
698
699 int status;
700 int pid2 = waitpid(pid, &status, 0);
701 assert(pid2 == pid);
702 if (!got_intended_status) {
703 printf("Test returned exit status %i\n", status);
704 return 1;
705 }
706 else if ((status & ~WCOREFLAG) != intended_status) {
707 printf("Test failed with exit status %i, expected %i\n",
708 status, intended_status);
709 return 1;
710 }
711 else {
712 return 0;
713 }
714 }
715
716 static int run_test_by_name(const char *name) {
717 struct testcase *test;
718 for (test = all_tests; test->test_name != NULL; test++) {
719 if (strcmp(name, test->test_name) == 0) {
720 printf("Running test %s...\n", name);
721 test->test_func();
722 printf("OK\n");
723 return 0;
724 }
725 }
726 fprintf(stderr, "Test '%s' not found\n", name);
727 return 1;
728 }
729
730 int main(int argc, char **argv) {
731 setvbuf(stdout, NULL, _IONBF, 0);
732 setvbuf(stderr, NULL, _IONBF, 0);
733 if (argc == 2) {
734 // Run one test without forking, to aid debugging.
735 return run_test_by_name(argv[1]);
736 }
737 else if (argc > 2) {
738 // TODO: run multiple tests.
739 fprintf(stderr, "Too many arguments\n");
740 return 1;
741 }
742 else {
743 // Run all tests.
744 struct testcase *test;
745 int failures = 0;
746 for (test = all_tests; test->test_name != NULL; test++) {
747 failures += run_test_forked(test);
748 }
749 if (failures == 0) {
750 printf("OK\n");
751 return 0;
752 }
753 else {
754 printf("%i FAILURE(S)\n", failures);
755 return 1;
756 }
757 }
758 }
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp/tests/list_tests.py ('k') | sandbox/linux/seccomp/timestats.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698