Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'linux-kselftest-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kselftest update from Shuah Khan:
"This update adds two new test suites: futex and seccomp.

In addition, it includes fixes for bugs in timers, other tests, and
compile framework. It introduces new quicktest feature to enable
users to choose to run tests that complete in a short time"

* tag 'linux-kselftest-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
selftests: add quicktest support
selftests: add seccomp suite
selftest, x86: fix incorrect comment
tools selftests: Fix 'clean' target with make 3.81
selftests/futex: Add .gitignore
kselftest: Add exit code defines
selftests: Add futex tests to the top-level Makefile
selftests/futex: Increment ksft pass and fail counters
selftests/futex: Update Makefile to use lib.mk
selftests: Add futex functional tests
kselftests: timers: Check _ALARM clockids are supported before suspending
kselftests: timers: Ease alarmtimer-suspend unreasonable latency value
kselftests: timers: Increase delay between suspends in alarmtimer-suspend
selftests/exec: do not install subdir as it is already created
selftests/ftrace: install test.d
selftests: copy TEST_DIRS to INSTALL_PATH
Test compaction of mlocked memory
selftests/mount: output WARN messages when mount test skipped
selftests/timers: Make git ignore all binaries in timers test suite

+4875 -13
+1
MAINTAINERS
··· 8986 8986 F: kernel/seccomp.c 8987 8987 F: include/uapi/linux/seccomp.h 8988 8988 F: include/linux/seccomp.h 8989 + F: tools/testing/selftests/seccomp/* 8989 8990 K: \bsecure_computing 8990 8991 K: \bTIF_SECCOMP\b 8991 8992
+7 -1
tools/testing/selftests/Makefile
··· 4 4 TARGETS += exec 5 5 TARGETS += firmware 6 6 TARGETS += ftrace 7 + TARGETS += futex 7 8 TARGETS += kcmp 8 9 TARGETS += memfd 9 10 TARGETS += memory-hotplug ··· 13 12 TARGETS += net 14 13 TARGETS += powerpc 15 14 TARGETS += ptrace 15 + TARGETS += seccomp 16 16 TARGETS += size 17 17 TARGETS += sysctl 18 + ifneq (1, $(quicktest)) 18 19 TARGETS += timers 20 + endif 19 21 TARGETS += user 20 22 TARGETS += vm 21 23 TARGETS += x86 22 24 #Please keep the TARGETS list alphabetically sorted 25 + # Run "make quicktest=1 run_tests" or 26 + # "make quicktest=1 kselftest from top level Makefile 23 27 24 28 TARGETS_HOTPLUG = cpu-hotplug 25 29 TARGETS_HOTPLUG += memory-hotplug ··· 33 27 # Makefile to avoid test build failures when test 34 28 # Makefile doesn't have explicit build rules. 35 29 ifeq (1,$(MAKELEVEL)) 36 - undefine LDFLAGS 30 + override LDFLAGS = 37 31 override MAKEFLAGS = 38 32 endif 39 33
+1 -1
tools/testing/selftests/exec/Makefile
··· 1 1 CFLAGS = -Wall 2 2 BINARIES = execveat 3 - DEPS = execveat.symlink execveat.denatured script subdir 3 + DEPS = execveat.symlink execveat.denatured script 4 4 all: $(BINARIES) $(DEPS) 5 5 6 6 subdir:
+1
tools/testing/selftests/ftrace/Makefile
··· 1 1 all: 2 2 3 3 TEST_PROGS := ftracetest 4 + TEST_DIRS := test.d/ 4 5 5 6 include ../lib.mk 6 7
+29
tools/testing/selftests/futex/Makefile
··· 1 + SUBDIRS := functional 2 + 3 + TEST_PROGS := run.sh 4 + 5 + .PHONY: all clean 6 + all: 7 + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done 8 + 9 + include ../lib.mk 10 + 11 + override define RUN_TESTS 12 + ./run.sh 13 + endef 14 + 15 + override define INSTALL_RULE 16 + mkdir -p $(INSTALL_PATH) 17 + install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) 18 + 19 + @for SUBDIR in $(SUBDIRS); do \ 20 + $(MAKE) -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ 21 + done; 22 + endef 23 + 24 + override define EMIT_TESTS 25 + echo "./run.sh" 26 + endef 27 + 28 + clean: 29 + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
+62
tools/testing/selftests/futex/README
··· 1 + Futex Test 2 + ========== 3 + Futex Test is intended to thoroughly test the Linux kernel futex system call 4 + API. 5 + 6 + Functional tests shall test the documented behavior of the futex operation 7 + code under test. This includes checking for proper behavior under normal use, 8 + odd corner cases, regression tests, and abject abuse and misuse. 9 + 10 + Futextest will also provide example implementation of mutual exclusion 11 + primitives. These can be used as is in user applications or can serve as 12 + examples for system libraries. These will likely be added to either a new lib/ 13 + directory or purely as header files under include/, I'm leaning toward the 14 + latter. 15 + 16 + Quick Start 17 + ----------- 18 + # make 19 + # ./run.sh 20 + 21 + Design and Implementation Goals 22 + ------------------------------- 23 + o Tests should be as self contained as is practical so as to facilitate sharing 24 + the individual tests on mailing list discussions and bug reports. 25 + o The build system shall remain as simple as possible, avoiding any archive or 26 + shared object building and linking. 27 + o Where possible, any helper functions or other package-wide code shall be 28 + implemented in header files, avoiding the need to compile intermediate object 29 + files. 30 + o External dependendencies shall remain as minimal as possible. Currently gcc 31 + and glibc are the only dependencies. 32 + o Tests return 0 for success and < 0 for failure. 33 + 34 + Output Formatting 35 + ----------------- 36 + Test output shall be easily parsable by both human and machine. Title and 37 + results are printed to stdout, while intermediate ERROR or FAIL messages are 38 + sent to stderr. Tests shall support the -c option to print PASS, FAIL, and 39 + ERROR strings in color for easy visual parsing. Output shall conform to the 40 + following format: 41 + 42 + test_name: Description of the test 43 + Arguments: arg1=val1 #units specified for clarity where appropriate 44 + ERROR: Description of unexpected error 45 + FAIL: Reason for test failure 46 + # FIXME: Perhaps an " INFO: informational message" option would be 47 + # useful here. Using -v to toggle it them on and off, as with -c. 48 + # there may be multiple ERROR or FAIL messages 49 + Result: (PASS|FAIL|ERROR) 50 + 51 + Naming 52 + ------ 53 + o FIXME: decide on a sane test naming scheme. Currently the tests are named 54 + based on the primary futex operation they test. Eventually this will become a 55 + problem as we intend to write multiple tests which collide in this namespace. 56 + Perhaps something like "wait-wake-1" "wait-wake-2" is adequate, leaving the 57 + detailed description in the test source and the output. 58 + 59 + Coding Style 60 + ------------ 61 + o The Futex Test project adheres to the coding standards set forth by Linux 62 + kernel as defined in the Linux source Documentation/CodingStyle.
+7
tools/testing/selftests/futex/functional/.gitignore
··· 1 + futex_requeue_pi 2 + futex_requeue_pi_mismatched_ops 3 + futex_requeue_pi_signal_restart 4 + futex_wait_private_mapped_file 5 + futex_wait_timeout 6 + futex_wait_uninitialized_heap 7 + futex_wait_wouldblock
+25
tools/testing/selftests/futex/functional/Makefile
··· 1 + INCLUDES := -I../include -I../../ 2 + CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES) 3 + LDFLAGS := $(LDFLAGS) -pthread -lrt 4 + 5 + HEADERS := ../include/futextest.h 6 + TARGETS := \ 7 + futex_wait_timeout \ 8 + futex_wait_wouldblock \ 9 + futex_requeue_pi \ 10 + futex_requeue_pi_signal_restart \ 11 + futex_requeue_pi_mismatched_ops \ 12 + futex_wait_uninitialized_heap \ 13 + futex_wait_private_mapped_file 14 + 15 + TEST_PROGS := $(TARGETS) run.sh 16 + 17 + .PHONY: all clean 18 + all: $(TARGETS) 19 + 20 + $(TARGETS): $(HEADERS) 21 + 22 + include ../../lib.mk 23 + 24 + clean: 25 + rm -f $(TARGETS)
+409
tools/testing/selftests/futex/functional/futex_requeue_pi.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2006-2008 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * This test excercises the futex syscall op codes needed for requeuing 12 + * priority inheritance aware POSIX condition variables and mutexes. 13 + * 14 + * AUTHORS 15 + * Sripathi Kodi <sripathik@in.ibm.com> 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2008-Jan-13: Initial version by Sripathi Kodi <sripathik@in.ibm.com> 20 + * 2009-Nov-6: futex test adaptation by Darren Hart <dvhart@linux.intel.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <errno.h> 25 + #include <limits.h> 26 + #include <pthread.h> 27 + #include <stdio.h> 28 + #include <stdlib.h> 29 + #include <signal.h> 30 + #include <string.h> 31 + #include "atomic.h" 32 + #include "futextest.h" 33 + #include "logging.h" 34 + 35 + #define MAX_WAKE_ITERS 1000 36 + #define THREAD_MAX 10 37 + #define SIGNAL_PERIOD_US 100 38 + 39 + atomic_t waiters_blocked = ATOMIC_INITIALIZER; 40 + atomic_t waiters_woken = ATOMIC_INITIALIZER; 41 + 42 + futex_t f1 = FUTEX_INITIALIZER; 43 + futex_t f2 = FUTEX_INITIALIZER; 44 + futex_t wake_complete = FUTEX_INITIALIZER; 45 + 46 + /* Test option defaults */ 47 + static long timeout_ns; 48 + static int broadcast; 49 + static int owner; 50 + static int locked; 51 + 52 + struct thread_arg { 53 + long id; 54 + struct timespec *timeout; 55 + int lock; 56 + int ret; 57 + }; 58 + #define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 } 59 + 60 + void usage(char *prog) 61 + { 62 + printf("Usage: %s\n", prog); 63 + printf(" -b Broadcast wakeup (all waiters)\n"); 64 + printf(" -c Use color\n"); 65 + printf(" -h Display this help message\n"); 66 + printf(" -l Lock the pi futex across requeue\n"); 67 + printf(" -o Use a third party pi futex owner during requeue (cancels -l)\n"); 68 + printf(" -t N Timeout in nanoseconds (default: 0)\n"); 69 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 70 + VQUIET, VCRITICAL, VINFO); 71 + } 72 + 73 + int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, 74 + int policy, int prio) 75 + { 76 + int ret; 77 + struct sched_param schedp; 78 + pthread_attr_t attr; 79 + 80 + pthread_attr_init(&attr); 81 + memset(&schedp, 0, sizeof(schedp)); 82 + 83 + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 84 + if (ret) { 85 + error("pthread_attr_setinheritsched\n", ret); 86 + return -1; 87 + } 88 + 89 + ret = pthread_attr_setschedpolicy(&attr, policy); 90 + if (ret) { 91 + error("pthread_attr_setschedpolicy\n", ret); 92 + return -1; 93 + } 94 + 95 + schedp.sched_priority = prio; 96 + ret = pthread_attr_setschedparam(&attr, &schedp); 97 + if (ret) { 98 + error("pthread_attr_setschedparam\n", ret); 99 + return -1; 100 + } 101 + 102 + ret = pthread_create(pth, &attr, func, arg); 103 + if (ret) { 104 + error("pthread_create\n", ret); 105 + return -1; 106 + } 107 + return 0; 108 + } 109 + 110 + 111 + void *waiterfn(void *arg) 112 + { 113 + struct thread_arg *args = (struct thread_arg *)arg; 114 + futex_t old_val; 115 + 116 + info("Waiter %ld: running\n", args->id); 117 + /* Each thread sleeps for a different amount of time 118 + * This is to avoid races, because we don't lock the 119 + * external mutex here */ 120 + usleep(1000 * (long)args->id); 121 + 122 + old_val = f1; 123 + atomic_inc(&waiters_blocked); 124 + info("Calling futex_wait_requeue_pi: %p (%u) -> %p\n", 125 + &f1, f1, &f2); 126 + args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout, 127 + FUTEX_PRIVATE_FLAG); 128 + 129 + info("waiter %ld woke with %d %s\n", args->id, args->ret, 130 + args->ret < 0 ? strerror(errno) : ""); 131 + atomic_inc(&waiters_woken); 132 + if (args->ret < 0) { 133 + if (args->timeout && errno == ETIMEDOUT) 134 + args->ret = 0; 135 + else { 136 + args->ret = RET_ERROR; 137 + error("futex_wait_requeue_pi\n", errno); 138 + } 139 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 140 + } 141 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 142 + 143 + info("Waiter %ld: exiting with %d\n", args->id, args->ret); 144 + pthread_exit((void *)&args->ret); 145 + } 146 + 147 + void *broadcast_wakerfn(void *arg) 148 + { 149 + struct thread_arg *args = (struct thread_arg *)arg; 150 + int nr_requeue = INT_MAX; 151 + int task_count = 0; 152 + futex_t old_val; 153 + int nr_wake = 1; 154 + int i = 0; 155 + 156 + info("Waker: waiting for waiters to block\n"); 157 + while (waiters_blocked.val < THREAD_MAX) 158 + usleep(1000); 159 + usleep(1000); 160 + 161 + info("Waker: Calling broadcast\n"); 162 + if (args->lock) { 163 + info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2); 164 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 165 + } 166 + continue_requeue: 167 + old_val = f1; 168 + args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue, 169 + FUTEX_PRIVATE_FLAG); 170 + if (args->ret < 0) { 171 + args->ret = RET_ERROR; 172 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 173 + } else if (++i < MAX_WAKE_ITERS) { 174 + task_count += args->ret; 175 + if (task_count < THREAD_MAX - waiters_woken.val) 176 + goto continue_requeue; 177 + } else { 178 + error("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n", 179 + 0, MAX_WAKE_ITERS, task_count, THREAD_MAX); 180 + args->ret = RET_ERROR; 181 + } 182 + 183 + futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG); 184 + 185 + if (args->lock) 186 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 187 + 188 + if (args->ret > 0) 189 + args->ret = task_count; 190 + 191 + info("Waker: exiting with %d\n", args->ret); 192 + pthread_exit((void *)&args->ret); 193 + } 194 + 195 + void *signal_wakerfn(void *arg) 196 + { 197 + struct thread_arg *args = (struct thread_arg *)arg; 198 + unsigned int old_val; 199 + int nr_requeue = 0; 200 + int task_count = 0; 201 + int nr_wake = 1; 202 + int i = 0; 203 + 204 + info("Waker: waiting for waiters to block\n"); 205 + while (waiters_blocked.val < THREAD_MAX) 206 + usleep(1000); 207 + usleep(1000); 208 + 209 + while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) { 210 + info("task_count: %d, waiters_woken: %d\n", 211 + task_count, waiters_woken.val); 212 + if (args->lock) { 213 + info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", 214 + f2, &f2); 215 + futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 216 + } 217 + info("Waker: Calling signal\n"); 218 + /* cond_signal */ 219 + old_val = f1; 220 + args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, 221 + nr_wake, nr_requeue, 222 + FUTEX_PRIVATE_FLAG); 223 + if (args->ret < 0) 224 + args->ret = -errno; 225 + info("futex: %x\n", f2); 226 + if (args->lock) { 227 + info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", 228 + f2, &f2); 229 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 230 + } 231 + info("futex: %x\n", f2); 232 + if (args->ret < 0) { 233 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 234 + args->ret = RET_ERROR; 235 + break; 236 + } 237 + 238 + task_count += args->ret; 239 + usleep(SIGNAL_PERIOD_US); 240 + i++; 241 + /* we have to loop at least THREAD_MAX times */ 242 + if (i > MAX_WAKE_ITERS + THREAD_MAX) { 243 + error("max signaling iterations (%d) reached, giving up on pending waiters.\n", 244 + 0, MAX_WAKE_ITERS + THREAD_MAX); 245 + args->ret = RET_ERROR; 246 + break; 247 + } 248 + } 249 + 250 + futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG); 251 + 252 + if (args->ret >= 0) 253 + args->ret = task_count; 254 + 255 + info("Waker: exiting with %d\n", args->ret); 256 + info("Waker: waiters_woken: %d\n", waiters_woken.val); 257 + pthread_exit((void *)&args->ret); 258 + } 259 + 260 + void *third_party_blocker(void *arg) 261 + { 262 + struct thread_arg *args = (struct thread_arg *)arg; 263 + int ret2 = 0; 264 + 265 + args->ret = futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); 266 + if (args->ret) 267 + goto out; 268 + args->ret = futex_wait(&wake_complete, wake_complete, NULL, 269 + FUTEX_PRIVATE_FLAG); 270 + ret2 = futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 271 + 272 + out: 273 + if (args->ret || ret2) { 274 + error("third_party_blocker() futex error", 0); 275 + args->ret = RET_ERROR; 276 + } 277 + 278 + pthread_exit((void *)&args->ret); 279 + } 280 + 281 + int unit_test(int broadcast, long lock, int third_party_owner, long timeout_ns) 282 + { 283 + void *(*wakerfn)(void *) = signal_wakerfn; 284 + struct thread_arg blocker_arg = THREAD_ARG_INITIALIZER; 285 + struct thread_arg waker_arg = THREAD_ARG_INITIALIZER; 286 + pthread_t waiter[THREAD_MAX], waker, blocker; 287 + struct timespec ts, *tsp = NULL; 288 + struct thread_arg args[THREAD_MAX]; 289 + int *waiter_ret; 290 + int i, ret = RET_PASS; 291 + 292 + if (timeout_ns) { 293 + time_t secs; 294 + 295 + info("timeout_ns = %ld\n", timeout_ns); 296 + ret = clock_gettime(CLOCK_MONOTONIC, &ts); 297 + secs = (ts.tv_nsec + timeout_ns) / 1000000000; 298 + ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000; 299 + ts.tv_sec += secs; 300 + info("ts.tv_sec = %ld\n", ts.tv_sec); 301 + info("ts.tv_nsec = %ld\n", ts.tv_nsec); 302 + tsp = &ts; 303 + } 304 + 305 + if (broadcast) 306 + wakerfn = broadcast_wakerfn; 307 + 308 + if (third_party_owner) { 309 + if (create_rt_thread(&blocker, third_party_blocker, 310 + (void *)&blocker_arg, SCHED_FIFO, 1)) { 311 + error("Creating third party blocker thread failed\n", 312 + errno); 313 + ret = RET_ERROR; 314 + goto out; 315 + } 316 + } 317 + 318 + atomic_set(&waiters_woken, 0); 319 + for (i = 0; i < THREAD_MAX; i++) { 320 + args[i].id = i; 321 + args[i].timeout = tsp; 322 + info("Starting thread %d\n", i); 323 + if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i], 324 + SCHED_FIFO, 1)) { 325 + error("Creating waiting thread failed\n", errno); 326 + ret = RET_ERROR; 327 + goto out; 328 + } 329 + } 330 + waker_arg.lock = lock; 331 + if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg, 332 + SCHED_FIFO, 1)) { 333 + error("Creating waker thread failed\n", errno); 334 + ret = RET_ERROR; 335 + goto out; 336 + } 337 + 338 + /* Wait for threads to finish */ 339 + /* Store the first error or failure encountered in waiter_ret */ 340 + waiter_ret = &args[0].ret; 341 + for (i = 0; i < THREAD_MAX; i++) 342 + pthread_join(waiter[i], 343 + *waiter_ret ? NULL : (void **)&waiter_ret); 344 + 345 + if (third_party_owner) 346 + pthread_join(blocker, NULL); 347 + pthread_join(waker, NULL); 348 + 349 + out: 350 + if (!ret) { 351 + if (*waiter_ret) 352 + ret = *waiter_ret; 353 + else if (waker_arg.ret < 0) 354 + ret = waker_arg.ret; 355 + else if (blocker_arg.ret) 356 + ret = blocker_arg.ret; 357 + } 358 + 359 + return ret; 360 + } 361 + 362 + int main(int argc, char *argv[]) 363 + { 364 + int c, ret; 365 + 366 + while ((c = getopt(argc, argv, "bchlot:v:")) != -1) { 367 + switch (c) { 368 + case 'b': 369 + broadcast = 1; 370 + break; 371 + case 'c': 372 + log_color(1); 373 + break; 374 + case 'h': 375 + usage(basename(argv[0])); 376 + exit(0); 377 + case 'l': 378 + locked = 1; 379 + break; 380 + case 'o': 381 + owner = 1; 382 + locked = 0; 383 + break; 384 + case 't': 385 + timeout_ns = atoi(optarg); 386 + break; 387 + case 'v': 388 + log_verbosity(atoi(optarg)); 389 + break; 390 + default: 391 + usage(basename(argv[0])); 392 + exit(1); 393 + } 394 + } 395 + 396 + printf("%s: Test requeue functionality\n", basename(argv[0])); 397 + printf("\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n", 398 + broadcast, locked, owner, timeout_ns); 399 + 400 + /* 401 + * FIXME: unit_test is obsolete now that we parse options and the 402 + * various style of runs are done by run.sh - simplify the code and move 403 + * unit_test into main() 404 + */ 405 + ret = unit_test(broadcast, locked, owner, timeout_ns); 406 + 407 + print_result(ret); 408 + return ret; 409 + }
+135
tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * 1. Block a thread using FUTEX_WAIT 12 + * 2. Attempt to use FUTEX_CMP_REQUEUE_PI on the futex from 1. 13 + * 3. The kernel must detect the mismatch and return -EINVAL. 14 + * 15 + * AUTHOR 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + * 21 + *****************************************************************************/ 22 + 23 + #include <errno.h> 24 + #include <getopt.h> 25 + #include <pthread.h> 26 + #include <stdio.h> 27 + #include <stdlib.h> 28 + #include <string.h> 29 + #include <time.h> 30 + #include "futextest.h" 31 + #include "logging.h" 32 + 33 + futex_t f1 = FUTEX_INITIALIZER; 34 + futex_t f2 = FUTEX_INITIALIZER; 35 + int child_ret = 0; 36 + 37 + void usage(char *prog) 38 + { 39 + printf("Usage: %s\n", prog); 40 + printf(" -c Use color\n"); 41 + printf(" -h Display this help message\n"); 42 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 43 + VQUIET, VCRITICAL, VINFO); 44 + } 45 + 46 + void *blocking_child(void *arg) 47 + { 48 + child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG); 49 + if (child_ret < 0) { 50 + child_ret = -errno; 51 + error("futex_wait\n", errno); 52 + } 53 + return (void *)&child_ret; 54 + } 55 + 56 + int main(int argc, char *argv[]) 57 + { 58 + int ret = RET_PASS; 59 + pthread_t child; 60 + int c; 61 + 62 + while ((c = getopt(argc, argv, "chv:")) != -1) { 63 + switch (c) { 64 + case 'c': 65 + log_color(1); 66 + break; 67 + case 'h': 68 + usage(basename(argv[0])); 69 + exit(0); 70 + case 'v': 71 + log_verbosity(atoi(optarg)); 72 + break; 73 + default: 74 + usage(basename(argv[0])); 75 + exit(1); 76 + } 77 + } 78 + 79 + printf("%s: Detect mismatched requeue_pi operations\n", 80 + basename(argv[0])); 81 + 82 + if (pthread_create(&child, NULL, blocking_child, NULL)) { 83 + error("pthread_create\n", errno); 84 + ret = RET_ERROR; 85 + goto out; 86 + } 87 + /* Allow the child to block in the kernel. */ 88 + sleep(1); 89 + 90 + /* 91 + * The kernel should detect the waiter did not setup the 92 + * q->requeue_pi_key and return -EINVAL. If it does not, 93 + * it likely gave the lock to the child, which is now hung 94 + * in the kernel. 95 + */ 96 + ret = futex_cmp_requeue_pi(&f1, f1, &f2, 1, 0, FUTEX_PRIVATE_FLAG); 97 + if (ret < 0) { 98 + if (errno == EINVAL) { 99 + /* 100 + * The kernel correctly detected the mismatched 101 + * requeue_pi target and aborted. Wake the child with 102 + * FUTEX_WAKE. 103 + */ 104 + ret = futex_wake(&f1, 1, FUTEX_PRIVATE_FLAG); 105 + if (ret == 1) { 106 + ret = RET_PASS; 107 + } else if (ret < 0) { 108 + error("futex_wake\n", errno); 109 + ret = RET_ERROR; 110 + } else { 111 + error("futex_wake did not wake the child\n", 0); 112 + ret = RET_ERROR; 113 + } 114 + } else { 115 + error("futex_cmp_requeue_pi\n", errno); 116 + ret = RET_ERROR; 117 + } 118 + } else if (ret > 0) { 119 + fail("futex_cmp_requeue_pi failed to detect the mismatch\n"); 120 + ret = RET_FAIL; 121 + } else { 122 + error("futex_cmp_requeue_pi found no waiters\n", 0); 123 + ret = RET_ERROR; 124 + } 125 + 126 + pthread_join(child, NULL); 127 + 128 + if (!ret) 129 + ret = child_ret; 130 + 131 + out: 132 + /* If the kernel crashes, we shouldn't return at all. */ 133 + print_result(ret); 134 + return ret; 135 + }
+223
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2006-2008 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * This test exercises the futex_wait_requeue_pi() signal handling both 12 + * before and after the requeue. The first should be restarted by the 13 + * kernel. The latter should return EWOULDBLOCK to the waiter. 14 + * 15 + * AUTHORS 16 + * Darren Hart <dvhart@linux.intel.com> 17 + * 18 + * HISTORY 19 + * 2008-May-5: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + * 21 + *****************************************************************************/ 22 + 23 + #include <errno.h> 24 + #include <getopt.h> 25 + #include <limits.h> 26 + #include <pthread.h> 27 + #include <signal.h> 28 + #include <stdio.h> 29 + #include <stdlib.h> 30 + #include <string.h> 31 + #include "atomic.h" 32 + #include "futextest.h" 33 + #include "logging.h" 34 + 35 + #define DELAY_US 100 36 + 37 + futex_t f1 = FUTEX_INITIALIZER; 38 + futex_t f2 = FUTEX_INITIALIZER; 39 + atomic_t requeued = ATOMIC_INITIALIZER; 40 + 41 + int waiter_ret = 0; 42 + 43 + void usage(char *prog) 44 + { 45 + printf("Usage: %s\n", prog); 46 + printf(" -c Use color\n"); 47 + printf(" -h Display this help message\n"); 48 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 49 + VQUIET, VCRITICAL, VINFO); 50 + } 51 + 52 + int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg, 53 + int policy, int prio) 54 + { 55 + struct sched_param schedp; 56 + pthread_attr_t attr; 57 + int ret; 58 + 59 + pthread_attr_init(&attr); 60 + memset(&schedp, 0, sizeof(schedp)); 61 + 62 + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 63 + if (ret) { 64 + error("pthread_attr_setinheritsched\n", ret); 65 + return -1; 66 + } 67 + 68 + ret = pthread_attr_setschedpolicy(&attr, policy); 69 + if (ret) { 70 + error("pthread_attr_setschedpolicy\n", ret); 71 + return -1; 72 + } 73 + 74 + schedp.sched_priority = prio; 75 + ret = pthread_attr_setschedparam(&attr, &schedp); 76 + if (ret) { 77 + error("pthread_attr_setschedparam\n", ret); 78 + return -1; 79 + } 80 + 81 + ret = pthread_create(pth, &attr, func, arg); 82 + if (ret) { 83 + error("pthread_create\n", ret); 84 + return -1; 85 + } 86 + return 0; 87 + } 88 + 89 + void handle_signal(int signo) 90 + { 91 + info("signal received %s requeue\n", 92 + requeued.val ? "after" : "prior to"); 93 + } 94 + 95 + void *waiterfn(void *arg) 96 + { 97 + unsigned int old_val; 98 + int res; 99 + 100 + waiter_ret = RET_PASS; 101 + 102 + info("Waiter running\n"); 103 + info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); 104 + old_val = f1; 105 + res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL, 106 + FUTEX_PRIVATE_FLAG); 107 + if (!requeued.val || errno != EWOULDBLOCK) { 108 + fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n", 109 + res, strerror(errno)); 110 + info("w2:futex: %x\n", f2); 111 + if (!res) 112 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 113 + waiter_ret = RET_FAIL; 114 + } 115 + 116 + info("Waiter exiting with %d\n", waiter_ret); 117 + pthread_exit(NULL); 118 + } 119 + 120 + 121 + int main(int argc, char *argv[]) 122 + { 123 + unsigned int old_val; 124 + struct sigaction sa; 125 + pthread_t waiter; 126 + int c, res, ret = RET_PASS; 127 + 128 + while ((c = getopt(argc, argv, "chv:")) != -1) { 129 + switch (c) { 130 + case 'c': 131 + log_color(1); 132 + break; 133 + case 'h': 134 + usage(basename(argv[0])); 135 + exit(0); 136 + case 'v': 137 + log_verbosity(atoi(optarg)); 138 + break; 139 + default: 140 + usage(basename(argv[0])); 141 + exit(1); 142 + } 143 + } 144 + 145 + printf("%s: Test signal handling during requeue_pi\n", 146 + basename(argv[0])); 147 + printf("\tArguments: <none>\n"); 148 + 149 + sa.sa_handler = handle_signal; 150 + sigemptyset(&sa.sa_mask); 151 + sa.sa_flags = 0; 152 + if (sigaction(SIGUSR1, &sa, NULL)) { 153 + error("sigaction\n", errno); 154 + exit(1); 155 + } 156 + 157 + info("m1:f2: %x\n", f2); 158 + info("Creating waiter\n"); 159 + res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1); 160 + if (res) { 161 + error("Creating waiting thread failed", res); 162 + ret = RET_ERROR; 163 + goto out; 164 + } 165 + 166 + info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); 167 + info("m2:f2: %x\n", f2); 168 + futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG); 169 + info("m3:f2: %x\n", f2); 170 + 171 + while (1) { 172 + /* 173 + * signal the waiter before requeue, waiter should automatically 174 + * restart futex_wait_requeue_pi() in the kernel. Wait for the 175 + * waiter to block on f1 again. 176 + */ 177 + info("Issuing SIGUSR1 to waiter\n"); 178 + pthread_kill(waiter, SIGUSR1); 179 + usleep(DELAY_US); 180 + 181 + info("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n"); 182 + old_val = f1; 183 + res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0, 184 + FUTEX_PRIVATE_FLAG); 185 + /* 186 + * If res is non-zero, we either requeued the waiter or hit an 187 + * error, break out and handle it. If it is zero, then the 188 + * signal may have hit before the the waiter was blocked on f1. 189 + * Try again. 190 + */ 191 + if (res > 0) { 192 + atomic_set(&requeued, 1); 193 + break; 194 + } else if (res > 0) { 195 + error("FUTEX_CMP_REQUEUE_PI failed\n", errno); 196 + ret = RET_ERROR; 197 + break; 198 + } 199 + } 200 + info("m4:f2: %x\n", f2); 201 + 202 + /* 203 + * Signal the waiter after requeue, waiter should return from 204 + * futex_wait_requeue_pi() with EWOULDBLOCK. Join the thread here so the 205 + * futex_unlock_pi() can't happen before the signal wakeup is detected 206 + * in the kernel. 207 + */ 208 + info("Issuing SIGUSR1 to waiter\n"); 209 + pthread_kill(waiter, SIGUSR1); 210 + info("Waiting for waiter to return\n"); 211 + pthread_join(waiter, NULL); 212 + 213 + info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2); 214 + futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); 215 + info("m5:f2: %x\n", f2); 216 + 217 + out: 218 + if (ret == RET_PASS && waiter_ret) 219 + ret = waiter_ret; 220 + 221 + print_result(ret); 222 + return ret; 223 + }
+125
tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright FUJITSU LIMITED 2010 4 + * Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * DESCRIPTION 12 + * Internally, Futex has two handling mode, anon and file. The private file 13 + * mapping is special. At first it behave as file, but after write anything 14 + * it behave as anon. This test is intent to test such case. 15 + * 16 + * AUTHOR 17 + * KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 18 + * 19 + * HISTORY 20 + * 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <syscall.h> 27 + #include <unistd.h> 28 + #include <errno.h> 29 + #include <linux/futex.h> 30 + #include <pthread.h> 31 + #include <libgen.h> 32 + #include <signal.h> 33 + 34 + #include "logging.h" 35 + #include "futextest.h" 36 + 37 + #define PAGE_SZ 4096 38 + 39 + char pad[PAGE_SZ] = {1}; 40 + futex_t val = 1; 41 + char pad2[PAGE_SZ] = {1}; 42 + 43 + #define WAKE_WAIT_US 3000000 44 + struct timespec wait_timeout = { .tv_sec = 5, .tv_nsec = 0}; 45 + 46 + void usage(char *prog) 47 + { 48 + printf("Usage: %s\n", prog); 49 + printf(" -c Use color\n"); 50 + printf(" -h Display this help message\n"); 51 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 52 + VQUIET, VCRITICAL, VINFO); 53 + } 54 + 55 + void *thr_futex_wait(void *arg) 56 + { 57 + int ret; 58 + 59 + info("futex wait\n"); 60 + ret = futex_wait(&val, 1, &wait_timeout, 0); 61 + if (ret && errno != EWOULDBLOCK && errno != ETIMEDOUT) { 62 + error("futex error.\n", errno); 63 + print_result(RET_ERROR); 64 + exit(RET_ERROR); 65 + } 66 + 67 + if (ret && errno == ETIMEDOUT) 68 + fail("waiter timedout\n"); 69 + 70 + info("futex_wait: ret = %d, errno = %d\n", ret, errno); 71 + 72 + return NULL; 73 + } 74 + 75 + int main(int argc, char **argv) 76 + { 77 + pthread_t thr; 78 + int ret = RET_PASS; 79 + int res; 80 + int c; 81 + 82 + while ((c = getopt(argc, argv, "chv:")) != -1) { 83 + switch (c) { 84 + case 'c': 85 + log_color(1); 86 + break; 87 + case 'h': 88 + usage(basename(argv[0])); 89 + exit(0); 90 + case 'v': 91 + log_verbosity(atoi(optarg)); 92 + break; 93 + default: 94 + usage(basename(argv[0])); 95 + exit(1); 96 + } 97 + } 98 + 99 + printf("%s: Test the futex value of private file mappings in FUTEX_WAIT\n", 100 + basename(argv[0])); 101 + 102 + ret = pthread_create(&thr, NULL, thr_futex_wait, NULL); 103 + if (ret < 0) { 104 + fprintf(stderr, "pthread_create error\n"); 105 + ret = RET_ERROR; 106 + goto out; 107 + } 108 + 109 + info("wait a while\n"); 110 + usleep(WAKE_WAIT_US); 111 + val = 2; 112 + res = futex_wake(&val, 1, 0); 113 + info("futex_wake %d\n", res); 114 + if (res != 1) { 115 + fail("FUTEX_WAKE didn't find the waiting thread.\n"); 116 + ret = RET_FAIL; 117 + } 118 + 119 + info("join\n"); 120 + pthread_join(thr, NULL); 121 + 122 + out: 123 + print_result(ret); 124 + return ret; 125 + }
+86
tools/testing/selftests/futex/functional/futex_wait_timeout.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Block on a futex and wait for timeout. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #include <errno.h> 22 + #include <getopt.h> 23 + #include <stdio.h> 24 + #include <stdlib.h> 25 + #include <string.h> 26 + #include <time.h> 27 + #include "futextest.h" 28 + #include "logging.h" 29 + 30 + static long timeout_ns = 100000; /* 100us default timeout */ 31 + 32 + void usage(char *prog) 33 + { 34 + printf("Usage: %s\n", prog); 35 + printf(" -c Use color\n"); 36 + printf(" -h Display this help message\n"); 37 + printf(" -t N Timeout in nanoseconds (default: 100,000)\n"); 38 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 39 + VQUIET, VCRITICAL, VINFO); 40 + } 41 + 42 + int main(int argc, char *argv[]) 43 + { 44 + futex_t f1 = FUTEX_INITIALIZER; 45 + struct timespec to; 46 + int res, ret = RET_PASS; 47 + int c; 48 + 49 + while ((c = getopt(argc, argv, "cht:v:")) != -1) { 50 + switch (c) { 51 + case 'c': 52 + log_color(1); 53 + break; 54 + case 'h': 55 + usage(basename(argv[0])); 56 + exit(0); 57 + case 't': 58 + timeout_ns = atoi(optarg); 59 + break; 60 + case 'v': 61 + log_verbosity(atoi(optarg)); 62 + break; 63 + default: 64 + usage(basename(argv[0])); 65 + exit(1); 66 + } 67 + } 68 + 69 + printf("%s: Block on a futex and wait for timeout\n", 70 + basename(argv[0])); 71 + printf("\tArguments: timeout=%ldns\n", timeout_ns); 72 + 73 + /* initialize timeout */ 74 + to.tv_sec = 0; 75 + to.tv_nsec = timeout_ns; 76 + 77 + info("Calling futex_wait on f1: %u @ %p\n", f1, &f1); 78 + res = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG); 79 + if (!res || errno != ETIMEDOUT) { 80 + fail("futex_wait returned %d\n", ret < 0 ? errno : ret); 81 + ret = RET_FAIL; 82 + } 83 + 84 + print_result(ret); 85 + return ret; 86 + }
+124
tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright FUJITSU LIMITED 2010 4 + * Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * DESCRIPTION 12 + * Wait on uninitialized heap. It shold be zero and FUTEX_WAIT should 13 + * return immediately. This test is intent to test zero page handling in 14 + * futex. 15 + * 16 + * AUTHOR 17 + * KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 18 + * 19 + * HISTORY 20 + * 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 21 + * 22 + *****************************************************************************/ 23 + 24 + #include <pthread.h> 25 + #include <stdio.h> 26 + #include <stdlib.h> 27 + #include <sys/mman.h> 28 + #include <syscall.h> 29 + #include <sys/types.h> 30 + #include <sys/stat.h> 31 + #include <unistd.h> 32 + #include <errno.h> 33 + #include <linux/futex.h> 34 + #include <libgen.h> 35 + 36 + #include "logging.h" 37 + #include "futextest.h" 38 + 39 + #define WAIT_US 5000000 40 + 41 + static int child_blocked = 1; 42 + static int child_ret; 43 + void *buf; 44 + 45 + void usage(char *prog) 46 + { 47 + printf("Usage: %s\n", prog); 48 + printf(" -c Use color\n"); 49 + printf(" -h Display this help message\n"); 50 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 51 + VQUIET, VCRITICAL, VINFO); 52 + } 53 + 54 + void *wait_thread(void *arg) 55 + { 56 + int res; 57 + 58 + child_ret = RET_PASS; 59 + res = futex_wait(buf, 1, NULL, 0); 60 + child_blocked = 0; 61 + 62 + if (res != 0 && errno != EWOULDBLOCK) { 63 + error("futex failure\n", errno); 64 + child_ret = RET_ERROR; 65 + } 66 + pthread_exit(NULL); 67 + } 68 + 69 + int main(int argc, char **argv) 70 + { 71 + int c, ret = RET_PASS; 72 + long page_size; 73 + pthread_t thr; 74 + 75 + while ((c = getopt(argc, argv, "chv:")) != -1) { 76 + switch (c) { 77 + case 'c': 78 + log_color(1); 79 + break; 80 + case 'h': 81 + usage(basename(argv[0])); 82 + exit(0); 83 + case 'v': 84 + log_verbosity(atoi(optarg)); 85 + break; 86 + default: 87 + usage(basename(argv[0])); 88 + exit(1); 89 + } 90 + } 91 + 92 + page_size = sysconf(_SC_PAGESIZE); 93 + 94 + buf = mmap(NULL, page_size, PROT_READ|PROT_WRITE, 95 + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 96 + if (buf == (void *)-1) { 97 + error("mmap\n", errno); 98 + exit(1); 99 + } 100 + 101 + printf("%s: Test the uninitialized futex value in FUTEX_WAIT\n", 102 + basename(argv[0])); 103 + 104 + 105 + ret = pthread_create(&thr, NULL, wait_thread, NULL); 106 + if (ret) { 107 + error("pthread_create\n", errno); 108 + ret = RET_ERROR; 109 + goto out; 110 + } 111 + 112 + info("waiting %dus for child to return\n", WAIT_US); 113 + usleep(WAIT_US); 114 + 115 + ret = child_ret; 116 + if (child_blocked) { 117 + fail("child blocked in kernel\n"); 118 + ret = RET_FAIL; 119 + } 120 + 121 + out: 122 + print_result(ret); 123 + return ret; 124 + }
+79
tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Test if FUTEX_WAIT op returns -EWOULDBLOCK if the futex value differs 12 + * from the expected one. 13 + * 14 + * AUTHOR 15 + * Gowrishankar <gowrishankar.m@in.ibm.com> 16 + * 17 + * HISTORY 18 + * 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com> 19 + * 20 + *****************************************************************************/ 21 + 22 + #include <errno.h> 23 + #include <getopt.h> 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <time.h> 28 + #include "futextest.h" 29 + #include "logging.h" 30 + 31 + #define timeout_ns 100000 32 + 33 + void usage(char *prog) 34 + { 35 + printf("Usage: %s\n", prog); 36 + printf(" -c Use color\n"); 37 + printf(" -h Display this help message\n"); 38 + printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n", 39 + VQUIET, VCRITICAL, VINFO); 40 + } 41 + 42 + int main(int argc, char *argv[]) 43 + { 44 + struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns}; 45 + futex_t f1 = FUTEX_INITIALIZER; 46 + int res, ret = RET_PASS; 47 + int c; 48 + 49 + while ((c = getopt(argc, argv, "cht:v:")) != -1) { 50 + switch (c) { 51 + case 'c': 52 + log_color(1); 53 + break; 54 + case 'h': 55 + usage(basename(argv[0])); 56 + exit(0); 57 + case 'v': 58 + log_verbosity(atoi(optarg)); 59 + break; 60 + default: 61 + usage(basename(argv[0])); 62 + exit(1); 63 + } 64 + } 65 + 66 + printf("%s: Test the unexpected futex value in FUTEX_WAIT\n", 67 + basename(argv[0])); 68 + 69 + info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1); 70 + res = futex_wait(&f1, f1+1, &to, FUTEX_PRIVATE_FLAG); 71 + if (!res || errno != EWOULDBLOCK) { 72 + fail("futex_wait returned: %d %s\n", 73 + res ? errno : res, res ? strerror(errno) : ""); 74 + ret = RET_FAIL; 75 + } 76 + 77 + print_result(ret); 78 + return ret; 79 + }
+79
tools/testing/selftests/futex/functional/run.sh
··· 1 + #!/bin/sh 2 + 3 + ############################################################################### 4 + # 5 + # Copyright © International Business Machines Corp., 2009 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # DESCRIPTION 13 + # Run tests in the current directory. 14 + # 15 + # AUTHOR 16 + # Darren Hart <dvhart@linux.intel.com> 17 + # 18 + # HISTORY 19 + # 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 20 + # 2010-Jan-6: Add futex_wait_uninitialized_heap and futex_wait_private_mapped_file 21 + # by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 22 + # 23 + ############################################################################### 24 + 25 + # Test for a color capable console 26 + if [ -z "$USE_COLOR" ]; then 27 + tput setf 7 28 + if [ $? -eq 0 ]; then 29 + USE_COLOR=1 30 + tput sgr0 31 + fi 32 + fi 33 + if [ "$USE_COLOR" -eq 1 ]; then 34 + COLOR="-c" 35 + fi 36 + 37 + 38 + echo 39 + # requeue pi testing 40 + # without timeouts 41 + ./futex_requeue_pi $COLOR 42 + ./futex_requeue_pi $COLOR -b 43 + ./futex_requeue_pi $COLOR -b -l 44 + ./futex_requeue_pi $COLOR -b -o 45 + ./futex_requeue_pi $COLOR -l 46 + ./futex_requeue_pi $COLOR -o 47 + # with timeouts 48 + ./futex_requeue_pi $COLOR -b -l -t 5000 49 + ./futex_requeue_pi $COLOR -l -t 5000 50 + ./futex_requeue_pi $COLOR -b -l -t 500000 51 + ./futex_requeue_pi $COLOR -l -t 500000 52 + ./futex_requeue_pi $COLOR -b -t 5000 53 + ./futex_requeue_pi $COLOR -t 5000 54 + ./futex_requeue_pi $COLOR -b -t 500000 55 + ./futex_requeue_pi $COLOR -t 500000 56 + ./futex_requeue_pi $COLOR -b -o -t 5000 57 + ./futex_requeue_pi $COLOR -l -t 5000 58 + ./futex_requeue_pi $COLOR -b -o -t 500000 59 + ./futex_requeue_pi $COLOR -l -t 500000 60 + # with long timeout 61 + ./futex_requeue_pi $COLOR -b -l -t 2000000000 62 + ./futex_requeue_pi $COLOR -l -t 2000000000 63 + 64 + 65 + echo 66 + ./futex_requeue_pi_mismatched_ops $COLOR 67 + 68 + echo 69 + ./futex_requeue_pi_signal_restart $COLOR 70 + 71 + echo 72 + ./futex_wait_timeout $COLOR 73 + 74 + echo 75 + ./futex_wait_wouldblock $COLOR 76 + 77 + echo 78 + ./futex_wait_uninitialized_heap $COLOR 79 + ./futex_wait_private_mapped_file $COLOR
+83
tools/testing/selftests/futex/include/atomic.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * GCC atomic builtin wrappers 12 + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 13 + * 14 + * AUTHOR 15 + * Darren Hart <dvhart@linux.intel.com> 16 + * 17 + * HISTORY 18 + * 2009-Nov-17: Initial version by Darren Hart <dvhart@linux.intel.com> 19 + * 20 + *****************************************************************************/ 21 + 22 + #ifndef _ATOMIC_H 23 + #define _ATOMIC_H 24 + 25 + typedef struct { 26 + volatile int val; 27 + } atomic_t; 28 + 29 + #define ATOMIC_INITIALIZER { 0 } 30 + 31 + /** 32 + * atomic_cmpxchg() - Atomic compare and exchange 33 + * @uaddr: The address of the futex to be modified 34 + * @oldval: The expected value of the futex 35 + * @newval: The new value to try and assign the futex 36 + * 37 + * Return the old value of addr->val. 38 + */ 39 + static inline int 40 + atomic_cmpxchg(atomic_t *addr, int oldval, int newval) 41 + { 42 + return __sync_val_compare_and_swap(&addr->val, oldval, newval); 43 + } 44 + 45 + /** 46 + * atomic_inc() - Atomic incrememnt 47 + * @addr: Address of the variable to increment 48 + * 49 + * Return the new value of addr->val. 50 + */ 51 + static inline int 52 + atomic_inc(atomic_t *addr) 53 + { 54 + return __sync_add_and_fetch(&addr->val, 1); 55 + } 56 + 57 + /** 58 + * atomic_dec() - Atomic decrement 59 + * @addr: Address of the variable to decrement 60 + * 61 + * Return the new value of addr-val. 62 + */ 63 + static inline int 64 + atomic_dec(atomic_t *addr) 65 + { 66 + return __sync_sub_and_fetch(&addr->val, 1); 67 + } 68 + 69 + /** 70 + * atomic_set() - Atomic set 71 + * @addr: Address of the variable to set 72 + * @newval: New value for the atomic_t 73 + * 74 + * Return the new value of addr->val. 75 + */ 76 + static inline int 77 + atomic_set(atomic_t *addr, int newval) 78 + { 79 + addr->val = newval; 80 + return newval; 81 + } 82 + 83 + #endif
+266
tools/testing/selftests/futex/include/futextest.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Glibc independent futex library for testing kernel functionality. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #ifndef _FUTEXTEST_H 22 + #define _FUTEXTEST_H 23 + 24 + #include <unistd.h> 25 + #include <sys/syscall.h> 26 + #include <sys/types.h> 27 + #include <linux/futex.h> 28 + 29 + typedef volatile u_int32_t futex_t; 30 + #define FUTEX_INITIALIZER 0 31 + 32 + /* Define the newer op codes if the system header file is not up to date. */ 33 + #ifndef FUTEX_WAIT_BITSET 34 + #define FUTEX_WAIT_BITSET 9 35 + #endif 36 + #ifndef FUTEX_WAKE_BITSET 37 + #define FUTEX_WAKE_BITSET 10 38 + #endif 39 + #ifndef FUTEX_WAIT_REQUEUE_PI 40 + #define FUTEX_WAIT_REQUEUE_PI 11 41 + #endif 42 + #ifndef FUTEX_CMP_REQUEUE_PI 43 + #define FUTEX_CMP_REQUEUE_PI 12 44 + #endif 45 + #ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE 46 + #define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ 47 + FUTEX_PRIVATE_FLAG) 48 + #endif 49 + #ifndef FUTEX_REQUEUE_PI_PRIVATE 50 + #define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ 51 + FUTEX_PRIVATE_FLAG) 52 + #endif 53 + 54 + /** 55 + * futex() - SYS_futex syscall wrapper 56 + * @uaddr: address of first futex 57 + * @op: futex op code 58 + * @val: typically expected value of uaddr, but varies by op 59 + * @timeout: typically an absolute struct timespec (except where noted 60 + * otherwise). Overloaded by some ops 61 + * @uaddr2: address of second futex for some ops\ 62 + * @val3: varies by op 63 + * @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG 64 + * 65 + * futex() is used by all the following futex op wrappers. It can also be 66 + * used for misuse and abuse testing. Generally, the specific op wrappers 67 + * should be used instead. It is a macro instead of an static inline function as 68 + * some of the types over overloaded (timeout is used for nr_requeue for 69 + * example). 70 + * 71 + * These argument descriptions are the defaults for all 72 + * like-named arguments in the following wrappers except where noted below. 73 + */ 74 + #define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \ 75 + syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3) 76 + 77 + /** 78 + * futex_wait() - block on uaddr with optional timeout 79 + * @timeout: relative timeout 80 + */ 81 + static inline int 82 + futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags) 83 + { 84 + return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags); 85 + } 86 + 87 + /** 88 + * futex_wake() - wake one or more tasks blocked on uaddr 89 + * @nr_wake: wake up to this many tasks 90 + */ 91 + static inline int 92 + futex_wake(futex_t *uaddr, int nr_wake, int opflags) 93 + { 94 + return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags); 95 + } 96 + 97 + /** 98 + * futex_wait_bitset() - block on uaddr with bitset 99 + * @bitset: bitset to be used with futex_wake_bitset 100 + */ 101 + static inline int 102 + futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout, 103 + u_int32_t bitset, int opflags) 104 + { 105 + return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset, 106 + opflags); 107 + } 108 + 109 + /** 110 + * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset 111 + * @bitset: bitset to compare with that used in futex_wait_bitset 112 + */ 113 + static inline int 114 + futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags) 115 + { 116 + return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset, 117 + opflags); 118 + } 119 + 120 + /** 121 + * futex_lock_pi() - block on uaddr as a PI mutex 122 + * @detect: whether (1) or not (0) to perform deadlock detection 123 + */ 124 + static inline int 125 + futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect, 126 + int opflags) 127 + { 128 + return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); 129 + } 130 + 131 + /** 132 + * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter 133 + */ 134 + static inline int 135 + futex_unlock_pi(futex_t *uaddr, int opflags) 136 + { 137 + return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags); 138 + } 139 + 140 + /** 141 + * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION 142 + */ 143 + static inline int 144 + futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2, 145 + int wake_op, int opflags) 146 + { 147 + return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op, 148 + opflags); 149 + } 150 + 151 + /** 152 + * futex_requeue() - requeue without expected value comparison, deprecated 153 + * @nr_wake: wake up to this many tasks 154 + * @nr_requeue: requeue up to this many tasks 155 + * 156 + * Due to its inherently racy implementation, futex_requeue() is deprecated in 157 + * favor of futex_cmp_requeue(). 158 + */ 159 + static inline int 160 + futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue, 161 + int opflags) 162 + { 163 + return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0, 164 + opflags); 165 + } 166 + 167 + /** 168 + * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2 169 + * @nr_wake: wake up to this many tasks 170 + * @nr_requeue: requeue up to this many tasks 171 + */ 172 + static inline int 173 + futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 174 + int nr_requeue, int opflags) 175 + { 176 + return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2, 177 + val, opflags); 178 + } 179 + 180 + /** 181 + * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2 182 + * @uaddr: non-PI futex source 183 + * @uaddr2: PI futex target 184 + * 185 + * This is the first half of the requeue_pi mechanism. It shall always be 186 + * paired with futex_cmp_requeue_pi(). 187 + */ 188 + static inline int 189 + futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, 190 + struct timespec *timeout, int opflags) 191 + { 192 + return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0, 193 + opflags); 194 + } 195 + 196 + /** 197 + * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware) 198 + * @uaddr: non-PI futex source 199 + * @uaddr2: PI futex target 200 + * @nr_wake: wake up to this many tasks 201 + * @nr_requeue: requeue up to this many tasks 202 + */ 203 + static inline int 204 + futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake, 205 + int nr_requeue, int opflags) 206 + { 207 + return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2, 208 + val, opflags); 209 + } 210 + 211 + /** 212 + * futex_cmpxchg() - atomic compare and exchange 213 + * @uaddr: The address of the futex to be modified 214 + * @oldval: The expected value of the futex 215 + * @newval: The new value to try and assign the futex 216 + * 217 + * Implement cmpxchg using gcc atomic builtins. 218 + * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html 219 + * 220 + * Return the old futex value. 221 + */ 222 + static inline u_int32_t 223 + futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval) 224 + { 225 + return __sync_val_compare_and_swap(uaddr, oldval, newval); 226 + } 227 + 228 + /** 229 + * futex_dec() - atomic decrement of the futex value 230 + * @uaddr: The address of the futex to be modified 231 + * 232 + * Return the new futex value. 233 + */ 234 + static inline u_int32_t 235 + futex_dec(futex_t *uaddr) 236 + { 237 + return __sync_sub_and_fetch(uaddr, 1); 238 + } 239 + 240 + /** 241 + * futex_inc() - atomic increment of the futex value 242 + * @uaddr: the address of the futex to be modified 243 + * 244 + * Return the new futex value. 245 + */ 246 + static inline u_int32_t 247 + futex_inc(futex_t *uaddr) 248 + { 249 + return __sync_add_and_fetch(uaddr, 1); 250 + } 251 + 252 + /** 253 + * futex_set() - atomic decrement of the futex value 254 + * @uaddr: the address of the futex to be modified 255 + * @newval: New value for the atomic_t 256 + * 257 + * Return the new futex value. 258 + */ 259 + static inline u_int32_t 260 + futex_set(futex_t *uaddr, u_int32_t newval) 261 + { 262 + *uaddr = newval; 263 + return newval; 264 + } 265 + 266 + #endif
+153
tools/testing/selftests/futex/include/logging.h
··· 1 + /****************************************************************************** 2 + * 3 + * Copyright © International Business Machines Corp., 2009 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * DESCRIPTION 11 + * Glibc independent futex library for testing kernel functionality. 12 + * 13 + * AUTHOR 14 + * Darren Hart <dvhart@linux.intel.com> 15 + * 16 + * HISTORY 17 + * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com> 18 + * 19 + *****************************************************************************/ 20 + 21 + #ifndef _LOGGING_H 22 + #define _LOGGING_H 23 + 24 + #include <string.h> 25 + #include <unistd.h> 26 + #include <linux/futex.h> 27 + #include "kselftest.h" 28 + 29 + /* 30 + * Define PASS, ERROR, and FAIL strings with and without color escape 31 + * sequences, default to no color. 32 + */ 33 + #define ESC 0x1B, '[' 34 + #define BRIGHT '1' 35 + #define GREEN '3', '2' 36 + #define YELLOW '3', '3' 37 + #define RED '3', '1' 38 + #define ESCEND 'm' 39 + #define BRIGHT_GREEN ESC, BRIGHT, ';', GREEN, ESCEND 40 + #define BRIGHT_YELLOW ESC, BRIGHT, ';', YELLOW, ESCEND 41 + #define BRIGHT_RED ESC, BRIGHT, ';', RED, ESCEND 42 + #define RESET_COLOR ESC, '0', 'm' 43 + static const char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S', 44 + RESET_COLOR, 0}; 45 + static const char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R', 46 + RESET_COLOR, 0}; 47 + static const char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L', 48 + RESET_COLOR, 0}; 49 + static const char INFO_NORMAL[] = " INFO"; 50 + static const char PASS_NORMAL[] = " PASS"; 51 + static const char ERROR_NORMAL[] = "ERROR"; 52 + static const char FAIL_NORMAL[] = " FAIL"; 53 + const char *INFO = INFO_NORMAL; 54 + const char *PASS = PASS_NORMAL; 55 + const char *ERROR = ERROR_NORMAL; 56 + const char *FAIL = FAIL_NORMAL; 57 + 58 + /* Verbosity setting for INFO messages */ 59 + #define VQUIET 0 60 + #define VCRITICAL 1 61 + #define VINFO 2 62 + #define VMAX VINFO 63 + int _verbose = VCRITICAL; 64 + 65 + /* Functional test return codes */ 66 + #define RET_PASS 0 67 + #define RET_ERROR -1 68 + #define RET_FAIL -2 69 + 70 + /** 71 + * log_color() - Use colored output for PASS, ERROR, and FAIL strings 72 + * @use_color: use color (1) or not (0) 73 + */ 74 + void log_color(int use_color) 75 + { 76 + if (use_color) { 77 + PASS = PASS_COLOR; 78 + ERROR = ERROR_COLOR; 79 + FAIL = FAIL_COLOR; 80 + } else { 81 + PASS = PASS_NORMAL; 82 + ERROR = ERROR_NORMAL; 83 + FAIL = FAIL_NORMAL; 84 + } 85 + } 86 + 87 + /** 88 + * log_verbosity() - Set verbosity of test output 89 + * @verbose: Enable (1) verbose output or not (0) 90 + * 91 + * Currently setting verbose=1 will enable INFO messages and 0 will disable 92 + * them. FAIL and ERROR messages are always displayed. 93 + */ 94 + void log_verbosity(int level) 95 + { 96 + if (level > VMAX) 97 + level = VMAX; 98 + else if (level < 0) 99 + level = 0; 100 + _verbose = level; 101 + } 102 + 103 + /** 104 + * print_result() - Print standard PASS | ERROR | FAIL results 105 + * @ret: the return value to be considered: 0 | RET_ERROR | RET_FAIL 106 + * 107 + * print_result() is primarily intended for functional tests. 108 + */ 109 + void print_result(int ret) 110 + { 111 + const char *result = "Unknown return code"; 112 + 113 + switch (ret) { 114 + case RET_PASS: 115 + ksft_inc_pass_cnt(); 116 + result = PASS; 117 + break; 118 + case RET_ERROR: 119 + result = ERROR; 120 + break; 121 + case RET_FAIL: 122 + ksft_inc_fail_cnt(); 123 + result = FAIL; 124 + break; 125 + } 126 + printf("Result: %s\n", result); 127 + } 128 + 129 + /* log level macros */ 130 + #define info(message, vargs...) \ 131 + do { \ 132 + if (_verbose >= VINFO) \ 133 + fprintf(stderr, "\t%s: "message, INFO, ##vargs); \ 134 + } while (0) 135 + 136 + #define error(message, err, args...) \ 137 + do { \ 138 + if (_verbose >= VCRITICAL) {\ 139 + if (err) \ 140 + fprintf(stderr, "\t%s: %s: "message, \ 141 + ERROR, strerror(err), ##args); \ 142 + else \ 143 + fprintf(stderr, "\t%s: "message, ERROR, ##args); \ 144 + } \ 145 + } while (0) 146 + 147 + #define fail(message, args...) \ 148 + do { \ 149 + if (_verbose >= VCRITICAL) \ 150 + fprintf(stderr, "\t%s: "message, FAIL, ##args); \ 151 + } while (0) 152 + 153 + #endif
+33
tools/testing/selftests/futex/run.sh
··· 1 + #!/bin/sh 2 + 3 + ############################################################################### 4 + # 5 + # Copyright © International Business Machines Corp., 2009 6 + # 7 + # This program is free software; you can redistribute it and/or modify 8 + # it under the terms of the GNU General Public License as published by 9 + # the Free Software Foundation; either version 2 of the License, or 10 + # (at your option) any later version. 11 + # 12 + # DESCRIPTION 13 + # Run all tests under the functional, performance, and stress directories. 14 + # Format and summarize the results. 15 + # 16 + # AUTHOR 17 + # Darren Hart <dvhart@linux.intel.com> 18 + # 19 + # HISTORY 20 + # 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com> 21 + # 22 + ############################################################################### 23 + 24 + # Test for a color capable shell and pass the result to the subdir scripts 25 + USE_COLOR=0 26 + tput setf 7 27 + if [ $? -eq 0 ]; then 28 + USE_COLOR=1 29 + tput sgr0 30 + fi 31 + export USE_COLOR 32 + 33 + (cd functional; ./run.sh)
+12 -5
tools/testing/selftests/kselftest.h
··· 13 13 #include <stdlib.h> 14 14 #include <unistd.h> 15 15 16 + /* define kselftest exit codes */ 17 + #define KSFT_PASS 0 18 + #define KSFT_FAIL 1 19 + #define KSFT_XFAIL 2 20 + #define KSFT_XPASS 3 21 + #define KSFT_SKIP 4 22 + 16 23 /* counters */ 17 24 struct ksft_count { 18 25 unsigned int ksft_pass; ··· 47 40 48 41 static inline int ksft_exit_pass(void) 49 42 { 50 - exit(0); 43 + exit(KSFT_PASS); 51 44 } 52 45 static inline int ksft_exit_fail(void) 53 46 { 54 - exit(1); 47 + exit(KSFT_FAIL); 55 48 } 56 49 static inline int ksft_exit_xfail(void) 57 50 { 58 - exit(2); 51 + exit(KSFT_XFAIL); 59 52 } 60 53 static inline int ksft_exit_xpass(void) 61 54 { 62 - exit(3); 55 + exit(KSFT_XPASS); 63 56 } 64 57 static inline int ksft_exit_skip(void) 65 58 { 66 - exit(4); 59 + exit(KSFT_SKIP); 67 60 } 68 61 69 62 #endif /* __KSELFTEST_H */
+3
tools/testing/selftests/lib.mk
··· 13 13 14 14 define INSTALL_RULE 15 15 mkdir -p $(INSTALL_PATH) 16 + @for TEST_DIR in $(TEST_DIRS); do\ 17 + cp -r $$TEST_DIR $(INSTALL_PATH); \ 18 + done; 16 19 install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) 17 20 endef 18 21
+6 -1
tools/testing/selftests/mount/Makefile
··· 9 9 include ../lib.mk 10 10 11 11 TEST_PROGS := unprivileged-remount-test 12 - override RUN_TESTS := if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi 12 + override RUN_TESTS := if [ -f /proc/self/uid_map ] ; \ 13 + then \ 14 + ./unprivileged-remount-test ; \ 15 + else \ 16 + echo "WARN: No /proc/self/uid_map exist, test skipped." ; \ 17 + fi 13 18 override EMIT_TESTS := echo "$(RUN_TESTS)" 14 19 15 20 clean:
+1
tools/testing/selftests/seccomp/.gitignore
··· 1 + seccomp_bpf
+10
tools/testing/selftests/seccomp/Makefile
··· 1 + TEST_PROGS := seccomp_bpf 2 + CFLAGS += -Wl,-no-as-needed -Wall 3 + LDFLAGS += -lpthread 4 + 5 + all: $(TEST_PROGS) 6 + 7 + include ../lib.mk 8 + 9 + clean: 10 + $(RM) $(TEST_PROGS)
+2109
tools/testing/selftests/seccomp/seccomp_bpf.c
··· 1 + /* 2 + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 3 + * Use of this source code is governed by the GPLv2 license. 4 + * 5 + * Test code for seccomp bpf. 6 + */ 7 + 8 + #include <asm/siginfo.h> 9 + #define __have_siginfo_t 1 10 + #define __have_sigval_t 1 11 + #define __have_sigevent_t 1 12 + 13 + #include <errno.h> 14 + #include <linux/filter.h> 15 + #include <sys/prctl.h> 16 + #include <sys/ptrace.h> 17 + #include <sys/user.h> 18 + #include <linux/prctl.h> 19 + #include <linux/ptrace.h> 20 + #include <linux/seccomp.h> 21 + #include <poll.h> 22 + #include <pthread.h> 23 + #include <semaphore.h> 24 + #include <signal.h> 25 + #include <stddef.h> 26 + #include <stdbool.h> 27 + #include <string.h> 28 + #include <linux/elf.h> 29 + #include <sys/uio.h> 30 + 31 + #define _GNU_SOURCE 32 + #include <unistd.h> 33 + #include <sys/syscall.h> 34 + 35 + #include "test_harness.h" 36 + 37 + #ifndef PR_SET_PTRACER 38 + # define PR_SET_PTRACER 0x59616d61 39 + #endif 40 + 41 + #ifndef PR_SET_NO_NEW_PRIVS 42 + #define PR_SET_NO_NEW_PRIVS 38 43 + #define PR_GET_NO_NEW_PRIVS 39 44 + #endif 45 + 46 + #ifndef PR_SECCOMP_EXT 47 + #define PR_SECCOMP_EXT 43 48 + #endif 49 + 50 + #ifndef SECCOMP_EXT_ACT 51 + #define SECCOMP_EXT_ACT 1 52 + #endif 53 + 54 + #ifndef SECCOMP_EXT_ACT_TSYNC 55 + #define SECCOMP_EXT_ACT_TSYNC 1 56 + #endif 57 + 58 + #ifndef SECCOMP_MODE_STRICT 59 + #define SECCOMP_MODE_STRICT 1 60 + #endif 61 + 62 + #ifndef SECCOMP_MODE_FILTER 63 + #define SECCOMP_MODE_FILTER 2 64 + #endif 65 + 66 + #ifndef SECCOMP_RET_KILL 67 + #define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ 68 + #define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ 69 + #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ 70 + #define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ 71 + #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ 72 + 73 + /* Masks for the return value sections. */ 74 + #define SECCOMP_RET_ACTION 0x7fff0000U 75 + #define SECCOMP_RET_DATA 0x0000ffffU 76 + 77 + struct seccomp_data { 78 + int nr; 79 + __u32 arch; 80 + __u64 instruction_pointer; 81 + __u64 args[6]; 82 + }; 83 + #endif 84 + 85 + #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n])) 86 + 87 + #define SIBLING_EXIT_UNKILLED 0xbadbeef 88 + #define SIBLING_EXIT_FAILURE 0xbadface 89 + #define SIBLING_EXIT_NEWPRIVS 0xbadfeed 90 + 91 + TEST(mode_strict_support) 92 + { 93 + long ret; 94 + 95 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL); 96 + ASSERT_EQ(0, ret) { 97 + TH_LOG("Kernel does not support CONFIG_SECCOMP"); 98 + } 99 + syscall(__NR_exit, 1); 100 + } 101 + 102 + TEST_SIGNAL(mode_strict_cannot_call_prctl, SIGKILL) 103 + { 104 + long ret; 105 + 106 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, NULL, NULL); 107 + ASSERT_EQ(0, ret) { 108 + TH_LOG("Kernel does not support CONFIG_SECCOMP"); 109 + } 110 + syscall(__NR_prctl, PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 111 + NULL, NULL, NULL); 112 + EXPECT_FALSE(true) { 113 + TH_LOG("Unreachable!"); 114 + } 115 + } 116 + 117 + /* Note! This doesn't test no new privs behavior */ 118 + TEST(no_new_privs_support) 119 + { 120 + long ret; 121 + 122 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 123 + EXPECT_EQ(0, ret) { 124 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 125 + } 126 + } 127 + 128 + /* Tests kernel support by checking for a copy_from_user() fault on * NULL. */ 129 + TEST(mode_filter_support) 130 + { 131 + long ret; 132 + 133 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0); 134 + ASSERT_EQ(0, ret) { 135 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 136 + } 137 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, NULL, NULL); 138 + EXPECT_EQ(-1, ret); 139 + EXPECT_EQ(EFAULT, errno) { 140 + TH_LOG("Kernel does not support CONFIG_SECCOMP_FILTER!"); 141 + } 142 + } 143 + 144 + TEST(mode_filter_without_nnp) 145 + { 146 + struct sock_filter filter[] = { 147 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 148 + }; 149 + struct sock_fprog prog = { 150 + .len = (unsigned short)ARRAY_SIZE(filter), 151 + .filter = filter, 152 + }; 153 + long ret; 154 + 155 + ret = prctl(PR_GET_NO_NEW_PRIVS, 0, NULL, 0, 0); 156 + ASSERT_LE(0, ret) { 157 + TH_LOG("Expected 0 or unsupported for NO_NEW_PRIVS"); 158 + } 159 + errno = 0; 160 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 161 + /* Succeeds with CAP_SYS_ADMIN, fails without */ 162 + /* TODO(wad) check caps not euid */ 163 + if (geteuid()) { 164 + EXPECT_EQ(-1, ret); 165 + EXPECT_EQ(EACCES, errno); 166 + } else { 167 + EXPECT_EQ(0, ret); 168 + } 169 + } 170 + 171 + #define MAX_INSNS_PER_PATH 32768 172 + 173 + TEST(filter_size_limits) 174 + { 175 + int i; 176 + int count = BPF_MAXINSNS + 1; 177 + struct sock_filter allow[] = { 178 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 179 + }; 180 + struct sock_filter *filter; 181 + struct sock_fprog prog = { }; 182 + long ret; 183 + 184 + filter = calloc(count, sizeof(*filter)); 185 + ASSERT_NE(NULL, filter); 186 + 187 + for (i = 0; i < count; i++) 188 + filter[i] = allow[0]; 189 + 190 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 191 + ASSERT_EQ(0, ret); 192 + 193 + prog.filter = filter; 194 + prog.len = count; 195 + 196 + /* Too many filter instructions in a single filter. */ 197 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 198 + ASSERT_NE(0, ret) { 199 + TH_LOG("Installing %d insn filter was allowed", prog.len); 200 + } 201 + 202 + /* One less is okay, though. */ 203 + prog.len -= 1; 204 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 205 + ASSERT_EQ(0, ret) { 206 + TH_LOG("Installing %d insn filter wasn't allowed", prog.len); 207 + } 208 + } 209 + 210 + TEST(filter_chain_limits) 211 + { 212 + int i; 213 + int count = BPF_MAXINSNS; 214 + struct sock_filter allow[] = { 215 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 216 + }; 217 + struct sock_filter *filter; 218 + struct sock_fprog prog = { }; 219 + long ret; 220 + 221 + filter = calloc(count, sizeof(*filter)); 222 + ASSERT_NE(NULL, filter); 223 + 224 + for (i = 0; i < count; i++) 225 + filter[i] = allow[0]; 226 + 227 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 228 + ASSERT_EQ(0, ret); 229 + 230 + prog.filter = filter; 231 + prog.len = 1; 232 + 233 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 234 + ASSERT_EQ(0, ret); 235 + 236 + prog.len = count; 237 + 238 + /* Too many total filter instructions. */ 239 + for (i = 0; i < MAX_INSNS_PER_PATH; i++) { 240 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 241 + if (ret != 0) 242 + break; 243 + } 244 + ASSERT_NE(0, ret) { 245 + TH_LOG("Allowed %d %d-insn filters (total with penalties:%d)", 246 + i, count, i * (count + 4)); 247 + } 248 + } 249 + 250 + TEST(mode_filter_cannot_move_to_strict) 251 + { 252 + struct sock_filter filter[] = { 253 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 254 + }; 255 + struct sock_fprog prog = { 256 + .len = (unsigned short)ARRAY_SIZE(filter), 257 + .filter = filter, 258 + }; 259 + long ret; 260 + 261 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 262 + ASSERT_EQ(0, ret); 263 + 264 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 265 + ASSERT_EQ(0, ret); 266 + 267 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL, 0, 0); 268 + EXPECT_EQ(-1, ret); 269 + EXPECT_EQ(EINVAL, errno); 270 + } 271 + 272 + 273 + TEST(mode_filter_get_seccomp) 274 + { 275 + struct sock_filter filter[] = { 276 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 277 + }; 278 + struct sock_fprog prog = { 279 + .len = (unsigned short)ARRAY_SIZE(filter), 280 + .filter = filter, 281 + }; 282 + long ret; 283 + 284 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 285 + ASSERT_EQ(0, ret); 286 + 287 + ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0); 288 + EXPECT_EQ(0, ret); 289 + 290 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 291 + ASSERT_EQ(0, ret); 292 + 293 + ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0); 294 + EXPECT_EQ(2, ret); 295 + } 296 + 297 + 298 + TEST(ALLOW_all) 299 + { 300 + struct sock_filter filter[] = { 301 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 302 + }; 303 + struct sock_fprog prog = { 304 + .len = (unsigned short)ARRAY_SIZE(filter), 305 + .filter = filter, 306 + }; 307 + long ret; 308 + 309 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 310 + ASSERT_EQ(0, ret); 311 + 312 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 313 + ASSERT_EQ(0, ret); 314 + } 315 + 316 + TEST(empty_prog) 317 + { 318 + struct sock_filter filter[] = { 319 + }; 320 + struct sock_fprog prog = { 321 + .len = (unsigned short)ARRAY_SIZE(filter), 322 + .filter = filter, 323 + }; 324 + long ret; 325 + 326 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 327 + ASSERT_EQ(0, ret); 328 + 329 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 330 + EXPECT_EQ(-1, ret); 331 + EXPECT_EQ(EINVAL, errno); 332 + } 333 + 334 + TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS) 335 + { 336 + struct sock_filter filter[] = { 337 + BPF_STMT(BPF_RET|BPF_K, 0x10000000U), 338 + }; 339 + struct sock_fprog prog = { 340 + .len = (unsigned short)ARRAY_SIZE(filter), 341 + .filter = filter, 342 + }; 343 + long ret; 344 + 345 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 346 + ASSERT_EQ(0, ret); 347 + 348 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 349 + ASSERT_EQ(0, ret); 350 + EXPECT_EQ(0, syscall(__NR_getpid)) { 351 + TH_LOG("getpid() shouldn't ever return"); 352 + } 353 + } 354 + 355 + /* return code >= 0x80000000 is unused. */ 356 + TEST_SIGNAL(unknown_ret_is_kill_above_allow, SIGSYS) 357 + { 358 + struct sock_filter filter[] = { 359 + BPF_STMT(BPF_RET|BPF_K, 0x90000000U), 360 + }; 361 + struct sock_fprog prog = { 362 + .len = (unsigned short)ARRAY_SIZE(filter), 363 + .filter = filter, 364 + }; 365 + long ret; 366 + 367 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 368 + ASSERT_EQ(0, ret); 369 + 370 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 371 + ASSERT_EQ(0, ret); 372 + EXPECT_EQ(0, syscall(__NR_getpid)) { 373 + TH_LOG("getpid() shouldn't ever return"); 374 + } 375 + } 376 + 377 + TEST_SIGNAL(KILL_all, SIGSYS) 378 + { 379 + struct sock_filter filter[] = { 380 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 381 + }; 382 + struct sock_fprog prog = { 383 + .len = (unsigned short)ARRAY_SIZE(filter), 384 + .filter = filter, 385 + }; 386 + long ret; 387 + 388 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 389 + ASSERT_EQ(0, ret); 390 + 391 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 392 + ASSERT_EQ(0, ret); 393 + } 394 + 395 + TEST_SIGNAL(KILL_one, SIGSYS) 396 + { 397 + struct sock_filter filter[] = { 398 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 399 + offsetof(struct seccomp_data, nr)), 400 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), 401 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 402 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 403 + }; 404 + struct sock_fprog prog = { 405 + .len = (unsigned short)ARRAY_SIZE(filter), 406 + .filter = filter, 407 + }; 408 + long ret; 409 + pid_t parent = getppid(); 410 + 411 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 412 + ASSERT_EQ(0, ret); 413 + 414 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 415 + ASSERT_EQ(0, ret); 416 + 417 + EXPECT_EQ(parent, syscall(__NR_getppid)); 418 + /* getpid() should never return. */ 419 + EXPECT_EQ(0, syscall(__NR_getpid)); 420 + } 421 + 422 + TEST_SIGNAL(KILL_one_arg_one, SIGSYS) 423 + { 424 + struct sock_filter filter[] = { 425 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 426 + offsetof(struct seccomp_data, nr)), 427 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 428 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 429 + /* Only both with lower 32-bit for now. */ 430 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)), 431 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1), 432 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 433 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 434 + }; 435 + struct sock_fprog prog = { 436 + .len = (unsigned short)ARRAY_SIZE(filter), 437 + .filter = filter, 438 + }; 439 + long ret; 440 + pid_t parent = getppid(); 441 + pid_t pid = getpid(); 442 + 443 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 444 + ASSERT_EQ(0, ret); 445 + 446 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 447 + ASSERT_EQ(0, ret); 448 + 449 + EXPECT_EQ(parent, syscall(__NR_getppid)); 450 + EXPECT_EQ(pid, syscall(__NR_getpid)); 451 + /* getpid() should never return. */ 452 + EXPECT_EQ(0, syscall(__NR_getpid, 0x0C0FFEE)); 453 + } 454 + 455 + TEST_SIGNAL(KILL_one_arg_six, SIGSYS) 456 + { 457 + struct sock_filter filter[] = { 458 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 459 + offsetof(struct seccomp_data, nr)), 460 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 461 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 462 + /* Only both with lower 32-bit for now. */ 463 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)), 464 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1), 465 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 466 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 467 + }; 468 + struct sock_fprog prog = { 469 + .len = (unsigned short)ARRAY_SIZE(filter), 470 + .filter = filter, 471 + }; 472 + long ret; 473 + pid_t parent = getppid(); 474 + pid_t pid = getpid(); 475 + 476 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 477 + ASSERT_EQ(0, ret); 478 + 479 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 480 + ASSERT_EQ(0, ret); 481 + 482 + EXPECT_EQ(parent, syscall(__NR_getppid)); 483 + EXPECT_EQ(pid, syscall(__NR_getpid)); 484 + /* getpid() should never return. */ 485 + EXPECT_EQ(0, syscall(__NR_getpid, 1, 2, 3, 4, 5, 0x0C0FFEE)); 486 + } 487 + 488 + /* TODO(wad) add 64-bit versus 32-bit arg tests. */ 489 + TEST(arg_out_of_range) 490 + { 491 + struct sock_filter filter[] = { 492 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(6)), 493 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 494 + }; 495 + struct sock_fprog prog = { 496 + .len = (unsigned short)ARRAY_SIZE(filter), 497 + .filter = filter, 498 + }; 499 + long ret; 500 + 501 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 502 + ASSERT_EQ(0, ret); 503 + 504 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 505 + EXPECT_EQ(-1, ret); 506 + EXPECT_EQ(EINVAL, errno); 507 + } 508 + 509 + TEST(ERRNO_valid) 510 + { 511 + struct sock_filter filter[] = { 512 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 513 + offsetof(struct seccomp_data, nr)), 514 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), 515 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | E2BIG), 516 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 517 + }; 518 + struct sock_fprog prog = { 519 + .len = (unsigned short)ARRAY_SIZE(filter), 520 + .filter = filter, 521 + }; 522 + long ret; 523 + pid_t parent = getppid(); 524 + 525 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 526 + ASSERT_EQ(0, ret); 527 + 528 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 529 + ASSERT_EQ(0, ret); 530 + 531 + EXPECT_EQ(parent, syscall(__NR_getppid)); 532 + EXPECT_EQ(-1, read(0, NULL, 0)); 533 + EXPECT_EQ(E2BIG, errno); 534 + } 535 + 536 + TEST(ERRNO_zero) 537 + { 538 + struct sock_filter filter[] = { 539 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 540 + offsetof(struct seccomp_data, nr)), 541 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), 542 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 0), 543 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 544 + }; 545 + struct sock_fprog prog = { 546 + .len = (unsigned short)ARRAY_SIZE(filter), 547 + .filter = filter, 548 + }; 549 + long ret; 550 + pid_t parent = getppid(); 551 + 552 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 553 + ASSERT_EQ(0, ret); 554 + 555 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 556 + ASSERT_EQ(0, ret); 557 + 558 + EXPECT_EQ(parent, syscall(__NR_getppid)); 559 + /* "errno" of 0 is ok. */ 560 + EXPECT_EQ(0, read(0, NULL, 0)); 561 + } 562 + 563 + TEST(ERRNO_capped) 564 + { 565 + struct sock_filter filter[] = { 566 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 567 + offsetof(struct seccomp_data, nr)), 568 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), 569 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | 4096), 570 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 571 + }; 572 + struct sock_fprog prog = { 573 + .len = (unsigned short)ARRAY_SIZE(filter), 574 + .filter = filter, 575 + }; 576 + long ret; 577 + pid_t parent = getppid(); 578 + 579 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 580 + ASSERT_EQ(0, ret); 581 + 582 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 583 + ASSERT_EQ(0, ret); 584 + 585 + EXPECT_EQ(parent, syscall(__NR_getppid)); 586 + EXPECT_EQ(-1, read(0, NULL, 0)); 587 + EXPECT_EQ(4095, errno); 588 + } 589 + 590 + FIXTURE_DATA(TRAP) { 591 + struct sock_fprog prog; 592 + }; 593 + 594 + FIXTURE_SETUP(TRAP) 595 + { 596 + struct sock_filter filter[] = { 597 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 598 + offsetof(struct seccomp_data, nr)), 599 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), 600 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP), 601 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 602 + }; 603 + 604 + memset(&self->prog, 0, sizeof(self->prog)); 605 + self->prog.filter = malloc(sizeof(filter)); 606 + ASSERT_NE(NULL, self->prog.filter); 607 + memcpy(self->prog.filter, filter, sizeof(filter)); 608 + self->prog.len = (unsigned short)ARRAY_SIZE(filter); 609 + } 610 + 611 + FIXTURE_TEARDOWN(TRAP) 612 + { 613 + if (self->prog.filter) 614 + free(self->prog.filter); 615 + } 616 + 617 + TEST_F_SIGNAL(TRAP, dfl, SIGSYS) 618 + { 619 + long ret; 620 + 621 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 622 + ASSERT_EQ(0, ret); 623 + 624 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog); 625 + ASSERT_EQ(0, ret); 626 + syscall(__NR_getpid); 627 + } 628 + 629 + /* Ensure that SIGSYS overrides SIG_IGN */ 630 + TEST_F_SIGNAL(TRAP, ign, SIGSYS) 631 + { 632 + long ret; 633 + 634 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 635 + ASSERT_EQ(0, ret); 636 + 637 + signal(SIGSYS, SIG_IGN); 638 + 639 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog); 640 + ASSERT_EQ(0, ret); 641 + syscall(__NR_getpid); 642 + } 643 + 644 + static struct siginfo TRAP_info; 645 + static volatile int TRAP_nr; 646 + static void TRAP_action(int nr, siginfo_t *info, void *void_context) 647 + { 648 + memcpy(&TRAP_info, info, sizeof(TRAP_info)); 649 + TRAP_nr = nr; 650 + } 651 + 652 + TEST_F(TRAP, handler) 653 + { 654 + int ret, test; 655 + struct sigaction act; 656 + sigset_t mask; 657 + 658 + memset(&act, 0, sizeof(act)); 659 + sigemptyset(&mask); 660 + sigaddset(&mask, SIGSYS); 661 + 662 + act.sa_sigaction = &TRAP_action; 663 + act.sa_flags = SA_SIGINFO; 664 + ret = sigaction(SIGSYS, &act, NULL); 665 + ASSERT_EQ(0, ret) { 666 + TH_LOG("sigaction failed"); 667 + } 668 + ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); 669 + ASSERT_EQ(0, ret) { 670 + TH_LOG("sigprocmask failed"); 671 + } 672 + 673 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 674 + ASSERT_EQ(0, ret); 675 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog); 676 + ASSERT_EQ(0, ret); 677 + TRAP_nr = 0; 678 + memset(&TRAP_info, 0, sizeof(TRAP_info)); 679 + /* Expect the registers to be rolled back. (nr = error) may vary 680 + * based on arch. */ 681 + ret = syscall(__NR_getpid); 682 + /* Silence gcc warning about volatile. */ 683 + test = TRAP_nr; 684 + EXPECT_EQ(SIGSYS, test); 685 + struct local_sigsys { 686 + void *_call_addr; /* calling user insn */ 687 + int _syscall; /* triggering system call number */ 688 + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ 689 + } *sigsys = (struct local_sigsys *) 690 + #ifdef si_syscall 691 + &(TRAP_info.si_call_addr); 692 + #else 693 + &TRAP_info.si_pid; 694 + #endif 695 + EXPECT_EQ(__NR_getpid, sigsys->_syscall); 696 + /* Make sure arch is non-zero. */ 697 + EXPECT_NE(0, sigsys->_arch); 698 + EXPECT_NE(0, (unsigned long)sigsys->_call_addr); 699 + } 700 + 701 + FIXTURE_DATA(precedence) { 702 + struct sock_fprog allow; 703 + struct sock_fprog trace; 704 + struct sock_fprog error; 705 + struct sock_fprog trap; 706 + struct sock_fprog kill; 707 + }; 708 + 709 + FIXTURE_SETUP(precedence) 710 + { 711 + struct sock_filter allow_insns[] = { 712 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 713 + }; 714 + struct sock_filter trace_insns[] = { 715 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 716 + offsetof(struct seccomp_data, nr)), 717 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 718 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 719 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE), 720 + }; 721 + struct sock_filter error_insns[] = { 722 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 723 + offsetof(struct seccomp_data, nr)), 724 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 725 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 726 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO), 727 + }; 728 + struct sock_filter trap_insns[] = { 729 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 730 + offsetof(struct seccomp_data, nr)), 731 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 732 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 733 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP), 734 + }; 735 + struct sock_filter kill_insns[] = { 736 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 737 + offsetof(struct seccomp_data, nr)), 738 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), 739 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 740 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 741 + }; 742 + 743 + memset(self, 0, sizeof(*self)); 744 + #define FILTER_ALLOC(_x) \ 745 + self->_x.filter = malloc(sizeof(_x##_insns)); \ 746 + ASSERT_NE(NULL, self->_x.filter); \ 747 + memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \ 748 + self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns) 749 + FILTER_ALLOC(allow); 750 + FILTER_ALLOC(trace); 751 + FILTER_ALLOC(error); 752 + FILTER_ALLOC(trap); 753 + FILTER_ALLOC(kill); 754 + } 755 + 756 + FIXTURE_TEARDOWN(precedence) 757 + { 758 + #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter) 759 + FILTER_FREE(allow); 760 + FILTER_FREE(trace); 761 + FILTER_FREE(error); 762 + FILTER_FREE(trap); 763 + FILTER_FREE(kill); 764 + } 765 + 766 + TEST_F(precedence, allow_ok) 767 + { 768 + pid_t parent, res = 0; 769 + long ret; 770 + 771 + parent = getppid(); 772 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 773 + ASSERT_EQ(0, ret); 774 + 775 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 776 + ASSERT_EQ(0, ret); 777 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 778 + ASSERT_EQ(0, ret); 779 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 780 + ASSERT_EQ(0, ret); 781 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); 782 + ASSERT_EQ(0, ret); 783 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill); 784 + ASSERT_EQ(0, ret); 785 + /* Should work just fine. */ 786 + res = syscall(__NR_getppid); 787 + EXPECT_EQ(parent, res); 788 + } 789 + 790 + TEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS) 791 + { 792 + pid_t parent, res = 0; 793 + long ret; 794 + 795 + parent = getppid(); 796 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 797 + ASSERT_EQ(0, ret); 798 + 799 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 800 + ASSERT_EQ(0, ret); 801 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 802 + ASSERT_EQ(0, ret); 803 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 804 + ASSERT_EQ(0, ret); 805 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); 806 + ASSERT_EQ(0, ret); 807 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill); 808 + ASSERT_EQ(0, ret); 809 + /* Should work just fine. */ 810 + res = syscall(__NR_getppid); 811 + EXPECT_EQ(parent, res); 812 + /* getpid() should never return. */ 813 + res = syscall(__NR_getpid); 814 + EXPECT_EQ(0, res); 815 + } 816 + 817 + TEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS) 818 + { 819 + pid_t parent; 820 + long ret; 821 + 822 + parent = getppid(); 823 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 824 + ASSERT_EQ(0, ret); 825 + 826 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 827 + ASSERT_EQ(0, ret); 828 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->kill); 829 + ASSERT_EQ(0, ret); 830 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 831 + ASSERT_EQ(0, ret); 832 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 833 + ASSERT_EQ(0, ret); 834 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); 835 + ASSERT_EQ(0, ret); 836 + /* Should work just fine. */ 837 + EXPECT_EQ(parent, syscall(__NR_getppid)); 838 + /* getpid() should never return. */ 839 + EXPECT_EQ(0, syscall(__NR_getpid)); 840 + } 841 + 842 + TEST_F_SIGNAL(precedence, trap_is_second, SIGSYS) 843 + { 844 + pid_t parent; 845 + long ret; 846 + 847 + parent = getppid(); 848 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 849 + ASSERT_EQ(0, ret); 850 + 851 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 852 + ASSERT_EQ(0, ret); 853 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 854 + ASSERT_EQ(0, ret); 855 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 856 + ASSERT_EQ(0, ret); 857 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); 858 + ASSERT_EQ(0, ret); 859 + /* Should work just fine. */ 860 + EXPECT_EQ(parent, syscall(__NR_getppid)); 861 + /* getpid() should never return. */ 862 + EXPECT_EQ(0, syscall(__NR_getpid)); 863 + } 864 + 865 + TEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS) 866 + { 867 + pid_t parent; 868 + long ret; 869 + 870 + parent = getppid(); 871 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 872 + ASSERT_EQ(0, ret); 873 + 874 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 875 + ASSERT_EQ(0, ret); 876 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap); 877 + ASSERT_EQ(0, ret); 878 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 879 + ASSERT_EQ(0, ret); 880 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 881 + ASSERT_EQ(0, ret); 882 + /* Should work just fine. */ 883 + EXPECT_EQ(parent, syscall(__NR_getppid)); 884 + /* getpid() should never return. */ 885 + EXPECT_EQ(0, syscall(__NR_getpid)); 886 + } 887 + 888 + TEST_F(precedence, errno_is_third) 889 + { 890 + pid_t parent; 891 + long ret; 892 + 893 + parent = getppid(); 894 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 895 + ASSERT_EQ(0, ret); 896 + 897 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 898 + ASSERT_EQ(0, ret); 899 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 900 + ASSERT_EQ(0, ret); 901 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 902 + ASSERT_EQ(0, ret); 903 + /* Should work just fine. */ 904 + EXPECT_EQ(parent, syscall(__NR_getppid)); 905 + EXPECT_EQ(0, syscall(__NR_getpid)); 906 + } 907 + 908 + TEST_F(precedence, errno_is_third_in_any_order) 909 + { 910 + pid_t parent; 911 + long ret; 912 + 913 + parent = getppid(); 914 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 915 + ASSERT_EQ(0, ret); 916 + 917 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error); 918 + ASSERT_EQ(0, ret); 919 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 920 + ASSERT_EQ(0, ret); 921 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 922 + ASSERT_EQ(0, ret); 923 + /* Should work just fine. */ 924 + EXPECT_EQ(parent, syscall(__NR_getppid)); 925 + EXPECT_EQ(0, syscall(__NR_getpid)); 926 + } 927 + 928 + TEST_F(precedence, trace_is_fourth) 929 + { 930 + pid_t parent; 931 + long ret; 932 + 933 + parent = getppid(); 934 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 935 + ASSERT_EQ(0, ret); 936 + 937 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 938 + ASSERT_EQ(0, ret); 939 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 940 + ASSERT_EQ(0, ret); 941 + /* Should work just fine. */ 942 + EXPECT_EQ(parent, syscall(__NR_getppid)); 943 + /* No ptracer */ 944 + EXPECT_EQ(-1, syscall(__NR_getpid)); 945 + } 946 + 947 + TEST_F(precedence, trace_is_fourth_in_any_order) 948 + { 949 + pid_t parent; 950 + long ret; 951 + 952 + parent = getppid(); 953 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 954 + ASSERT_EQ(0, ret); 955 + 956 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace); 957 + ASSERT_EQ(0, ret); 958 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow); 959 + ASSERT_EQ(0, ret); 960 + /* Should work just fine. */ 961 + EXPECT_EQ(parent, syscall(__NR_getppid)); 962 + /* No ptracer */ 963 + EXPECT_EQ(-1, syscall(__NR_getpid)); 964 + } 965 + 966 + #ifndef PTRACE_O_TRACESECCOMP 967 + #define PTRACE_O_TRACESECCOMP 0x00000080 968 + #endif 969 + 970 + /* Catch the Ubuntu 12.04 value error. */ 971 + #if PTRACE_EVENT_SECCOMP != 7 972 + #undef PTRACE_EVENT_SECCOMP 973 + #endif 974 + 975 + #ifndef PTRACE_EVENT_SECCOMP 976 + #define PTRACE_EVENT_SECCOMP 7 977 + #endif 978 + 979 + #define IS_SECCOMP_EVENT(status) ((status >> 16) == PTRACE_EVENT_SECCOMP) 980 + bool tracer_running; 981 + void tracer_stop(int sig) 982 + { 983 + tracer_running = false; 984 + } 985 + 986 + typedef void tracer_func_t(struct __test_metadata *_metadata, 987 + pid_t tracee, int status, void *args); 988 + 989 + void tracer(struct __test_metadata *_metadata, int fd, pid_t tracee, 990 + tracer_func_t tracer_func, void *args) 991 + { 992 + int ret = -1; 993 + struct sigaction action = { 994 + .sa_handler = tracer_stop, 995 + }; 996 + 997 + /* Allow external shutdown. */ 998 + tracer_running = true; 999 + ASSERT_EQ(0, sigaction(SIGUSR1, &action, NULL)); 1000 + 1001 + errno = 0; 1002 + while (ret == -1 && errno != EINVAL) 1003 + ret = ptrace(PTRACE_ATTACH, tracee, NULL, 0); 1004 + ASSERT_EQ(0, ret) { 1005 + kill(tracee, SIGKILL); 1006 + } 1007 + /* Wait for attach stop */ 1008 + wait(NULL); 1009 + 1010 + ret = ptrace(PTRACE_SETOPTIONS, tracee, NULL, PTRACE_O_TRACESECCOMP); 1011 + ASSERT_EQ(0, ret) { 1012 + TH_LOG("Failed to set PTRACE_O_TRACESECCOMP"); 1013 + kill(tracee, SIGKILL); 1014 + } 1015 + ptrace(PTRACE_CONT, tracee, NULL, 0); 1016 + 1017 + /* Unblock the tracee */ 1018 + ASSERT_EQ(1, write(fd, "A", 1)); 1019 + ASSERT_EQ(0, close(fd)); 1020 + 1021 + /* Run until we're shut down. Must assert to stop execution. */ 1022 + while (tracer_running) { 1023 + int status; 1024 + 1025 + if (wait(&status) != tracee) 1026 + continue; 1027 + if (WIFSIGNALED(status) || WIFEXITED(status)) 1028 + /* Child is dead. Time to go. */ 1029 + return; 1030 + 1031 + /* Make sure this is a seccomp event. */ 1032 + ASSERT_EQ(true, IS_SECCOMP_EVENT(status)); 1033 + 1034 + tracer_func(_metadata, tracee, status, args); 1035 + 1036 + ret = ptrace(PTRACE_CONT, tracee, NULL, NULL); 1037 + ASSERT_EQ(0, ret); 1038 + } 1039 + /* Directly report the status of our test harness results. */ 1040 + syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 1041 + } 1042 + 1043 + /* Common tracer setup/teardown functions. */ 1044 + void cont_handler(int num) 1045 + { } 1046 + pid_t setup_trace_fixture(struct __test_metadata *_metadata, 1047 + tracer_func_t func, void *args) 1048 + { 1049 + char sync; 1050 + int pipefd[2]; 1051 + pid_t tracer_pid; 1052 + pid_t tracee = getpid(); 1053 + 1054 + /* Setup a pipe for clean synchronization. */ 1055 + ASSERT_EQ(0, pipe(pipefd)); 1056 + 1057 + /* Fork a child which we'll promote to tracer */ 1058 + tracer_pid = fork(); 1059 + ASSERT_LE(0, tracer_pid); 1060 + signal(SIGALRM, cont_handler); 1061 + if (tracer_pid == 0) { 1062 + close(pipefd[0]); 1063 + tracer(_metadata, pipefd[1], tracee, func, args); 1064 + syscall(__NR_exit, 0); 1065 + } 1066 + close(pipefd[1]); 1067 + prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); 1068 + read(pipefd[0], &sync, 1); 1069 + close(pipefd[0]); 1070 + 1071 + return tracer_pid; 1072 + } 1073 + void teardown_trace_fixture(struct __test_metadata *_metadata, 1074 + pid_t tracer) 1075 + { 1076 + if (tracer) { 1077 + int status; 1078 + /* 1079 + * Extract the exit code from the other process and 1080 + * adopt it for ourselves in case its asserts failed. 1081 + */ 1082 + ASSERT_EQ(0, kill(tracer, SIGUSR1)); 1083 + ASSERT_EQ(tracer, waitpid(tracer, &status, 0)); 1084 + if (WEXITSTATUS(status)) 1085 + _metadata->passed = 0; 1086 + } 1087 + } 1088 + 1089 + /* "poke" tracer arguments and function. */ 1090 + struct tracer_args_poke_t { 1091 + unsigned long poke_addr; 1092 + }; 1093 + 1094 + void tracer_poke(struct __test_metadata *_metadata, pid_t tracee, int status, 1095 + void *args) 1096 + { 1097 + int ret; 1098 + unsigned long msg; 1099 + struct tracer_args_poke_t *info = (struct tracer_args_poke_t *)args; 1100 + 1101 + ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg); 1102 + EXPECT_EQ(0, ret); 1103 + /* If this fails, don't try to recover. */ 1104 + ASSERT_EQ(0x1001, msg) { 1105 + kill(tracee, SIGKILL); 1106 + } 1107 + /* 1108 + * Poke in the message. 1109 + * Registers are not touched to try to keep this relatively arch 1110 + * agnostic. 1111 + */ 1112 + ret = ptrace(PTRACE_POKEDATA, tracee, info->poke_addr, 0x1001); 1113 + EXPECT_EQ(0, ret); 1114 + } 1115 + 1116 + FIXTURE_DATA(TRACE_poke) { 1117 + struct sock_fprog prog; 1118 + pid_t tracer; 1119 + long poked; 1120 + struct tracer_args_poke_t tracer_args; 1121 + }; 1122 + 1123 + FIXTURE_SETUP(TRACE_poke) 1124 + { 1125 + struct sock_filter filter[] = { 1126 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 1127 + offsetof(struct seccomp_data, nr)), 1128 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), 1129 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1001), 1130 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1131 + }; 1132 + 1133 + self->poked = 0; 1134 + memset(&self->prog, 0, sizeof(self->prog)); 1135 + self->prog.filter = malloc(sizeof(filter)); 1136 + ASSERT_NE(NULL, self->prog.filter); 1137 + memcpy(self->prog.filter, filter, sizeof(filter)); 1138 + self->prog.len = (unsigned short)ARRAY_SIZE(filter); 1139 + 1140 + /* Set up tracer args. */ 1141 + self->tracer_args.poke_addr = (unsigned long)&self->poked; 1142 + 1143 + /* Launch tracer. */ 1144 + self->tracer = setup_trace_fixture(_metadata, tracer_poke, 1145 + &self->tracer_args); 1146 + } 1147 + 1148 + FIXTURE_TEARDOWN(TRACE_poke) 1149 + { 1150 + teardown_trace_fixture(_metadata, self->tracer); 1151 + if (self->prog.filter) 1152 + free(self->prog.filter); 1153 + } 1154 + 1155 + TEST_F(TRACE_poke, read_has_side_effects) 1156 + { 1157 + ssize_t ret; 1158 + 1159 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1160 + ASSERT_EQ(0, ret); 1161 + 1162 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); 1163 + ASSERT_EQ(0, ret); 1164 + 1165 + EXPECT_EQ(0, self->poked); 1166 + ret = read(-1, NULL, 0); 1167 + EXPECT_EQ(-1, ret); 1168 + EXPECT_EQ(0x1001, self->poked); 1169 + } 1170 + 1171 + TEST_F(TRACE_poke, getpid_runs_normally) 1172 + { 1173 + long ret; 1174 + 1175 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1176 + ASSERT_EQ(0, ret); 1177 + 1178 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); 1179 + ASSERT_EQ(0, ret); 1180 + 1181 + EXPECT_EQ(0, self->poked); 1182 + EXPECT_NE(0, syscall(__NR_getpid)); 1183 + EXPECT_EQ(0, self->poked); 1184 + } 1185 + 1186 + #if defined(__x86_64__) 1187 + # define ARCH_REGS struct user_regs_struct 1188 + # define SYSCALL_NUM orig_rax 1189 + # define SYSCALL_RET rax 1190 + #elif defined(__i386__) 1191 + # define ARCH_REGS struct user_regs_struct 1192 + # define SYSCALL_NUM orig_eax 1193 + # define SYSCALL_RET eax 1194 + #elif defined(__arm__) 1195 + # define ARCH_REGS struct pt_regs 1196 + # define SYSCALL_NUM ARM_r7 1197 + # define SYSCALL_RET ARM_r0 1198 + #elif defined(__aarch64__) 1199 + # define ARCH_REGS struct user_pt_regs 1200 + # define SYSCALL_NUM regs[8] 1201 + # define SYSCALL_RET regs[0] 1202 + #else 1203 + # error "Do not know how to find your architecture's registers and syscalls" 1204 + #endif 1205 + 1206 + /* Architecture-specific syscall fetching routine. */ 1207 + int get_syscall(struct __test_metadata *_metadata, pid_t tracee) 1208 + { 1209 + struct iovec iov; 1210 + ARCH_REGS regs; 1211 + 1212 + iov.iov_base = &regs; 1213 + iov.iov_len = sizeof(regs); 1214 + EXPECT_EQ(0, ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov)) { 1215 + TH_LOG("PTRACE_GETREGSET failed"); 1216 + return -1; 1217 + } 1218 + 1219 + return regs.SYSCALL_NUM; 1220 + } 1221 + 1222 + /* Architecture-specific syscall changing routine. */ 1223 + void change_syscall(struct __test_metadata *_metadata, 1224 + pid_t tracee, int syscall) 1225 + { 1226 + struct iovec iov; 1227 + int ret; 1228 + ARCH_REGS regs; 1229 + 1230 + iov.iov_base = &regs; 1231 + iov.iov_len = sizeof(regs); 1232 + ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov); 1233 + EXPECT_EQ(0, ret); 1234 + 1235 + #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 1236 + { 1237 + regs.SYSCALL_NUM = syscall; 1238 + } 1239 + 1240 + #elif defined(__arm__) 1241 + # ifndef PTRACE_SET_SYSCALL 1242 + # define PTRACE_SET_SYSCALL 23 1243 + # endif 1244 + { 1245 + ret = ptrace(PTRACE_SET_SYSCALL, tracee, NULL, syscall); 1246 + EXPECT_EQ(0, ret); 1247 + } 1248 + 1249 + #else 1250 + ASSERT_EQ(1, 0) { 1251 + TH_LOG("How is the syscall changed on this architecture?"); 1252 + } 1253 + #endif 1254 + 1255 + /* If syscall is skipped, change return value. */ 1256 + if (syscall == -1) 1257 + regs.SYSCALL_RET = 1; 1258 + 1259 + ret = ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &iov); 1260 + EXPECT_EQ(0, ret); 1261 + } 1262 + 1263 + void tracer_syscall(struct __test_metadata *_metadata, pid_t tracee, 1264 + int status, void *args) 1265 + { 1266 + int ret; 1267 + unsigned long msg; 1268 + 1269 + /* Make sure we got the right message. */ 1270 + ret = ptrace(PTRACE_GETEVENTMSG, tracee, NULL, &msg); 1271 + EXPECT_EQ(0, ret); 1272 + 1273 + switch (msg) { 1274 + case 0x1002: 1275 + /* change getpid to getppid. */ 1276 + change_syscall(_metadata, tracee, __NR_getppid); 1277 + break; 1278 + case 0x1003: 1279 + /* skip gettid. */ 1280 + change_syscall(_metadata, tracee, -1); 1281 + break; 1282 + case 0x1004: 1283 + /* do nothing (allow getppid) */ 1284 + break; 1285 + default: 1286 + EXPECT_EQ(0, msg) { 1287 + TH_LOG("Unknown PTRACE_GETEVENTMSG: 0x%lx", msg); 1288 + kill(tracee, SIGKILL); 1289 + } 1290 + } 1291 + 1292 + } 1293 + 1294 + FIXTURE_DATA(TRACE_syscall) { 1295 + struct sock_fprog prog; 1296 + pid_t tracer, mytid, mypid, parent; 1297 + }; 1298 + 1299 + FIXTURE_SETUP(TRACE_syscall) 1300 + { 1301 + struct sock_filter filter[] = { 1302 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 1303 + offsetof(struct seccomp_data, nr)), 1304 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), 1305 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1002), 1306 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_gettid, 0, 1), 1307 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1003), 1308 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getppid, 0, 1), 1309 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE | 0x1004), 1310 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1311 + }; 1312 + 1313 + memset(&self->prog, 0, sizeof(self->prog)); 1314 + self->prog.filter = malloc(sizeof(filter)); 1315 + ASSERT_NE(NULL, self->prog.filter); 1316 + memcpy(self->prog.filter, filter, sizeof(filter)); 1317 + self->prog.len = (unsigned short)ARRAY_SIZE(filter); 1318 + 1319 + /* Prepare some testable syscall results. */ 1320 + self->mytid = syscall(__NR_gettid); 1321 + ASSERT_GT(self->mytid, 0); 1322 + ASSERT_NE(self->mytid, 1) { 1323 + TH_LOG("Running this test as init is not supported. :)"); 1324 + } 1325 + 1326 + self->mypid = getpid(); 1327 + ASSERT_GT(self->mypid, 0); 1328 + ASSERT_EQ(self->mytid, self->mypid); 1329 + 1330 + self->parent = getppid(); 1331 + ASSERT_GT(self->parent, 0); 1332 + ASSERT_NE(self->parent, self->mypid); 1333 + 1334 + /* Launch tracer. */ 1335 + self->tracer = setup_trace_fixture(_metadata, tracer_syscall, NULL); 1336 + } 1337 + 1338 + FIXTURE_TEARDOWN(TRACE_syscall) 1339 + { 1340 + teardown_trace_fixture(_metadata, self->tracer); 1341 + if (self->prog.filter) 1342 + free(self->prog.filter); 1343 + } 1344 + 1345 + TEST_F(TRACE_syscall, syscall_allowed) 1346 + { 1347 + long ret; 1348 + 1349 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1350 + ASSERT_EQ(0, ret); 1351 + 1352 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); 1353 + ASSERT_EQ(0, ret); 1354 + 1355 + /* getppid works as expected (no changes). */ 1356 + EXPECT_EQ(self->parent, syscall(__NR_getppid)); 1357 + EXPECT_NE(self->mypid, syscall(__NR_getppid)); 1358 + } 1359 + 1360 + TEST_F(TRACE_syscall, syscall_redirected) 1361 + { 1362 + long ret; 1363 + 1364 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1365 + ASSERT_EQ(0, ret); 1366 + 1367 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); 1368 + ASSERT_EQ(0, ret); 1369 + 1370 + /* getpid has been redirected to getppid as expected. */ 1371 + EXPECT_EQ(self->parent, syscall(__NR_getpid)); 1372 + EXPECT_NE(self->mypid, syscall(__NR_getpid)); 1373 + } 1374 + 1375 + TEST_F(TRACE_syscall, syscall_dropped) 1376 + { 1377 + long ret; 1378 + 1379 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1380 + ASSERT_EQ(0, ret); 1381 + 1382 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); 1383 + ASSERT_EQ(0, ret); 1384 + 1385 + /* gettid has been skipped and an altered return value stored. */ 1386 + EXPECT_EQ(1, syscall(__NR_gettid)); 1387 + EXPECT_NE(self->mytid, syscall(__NR_gettid)); 1388 + } 1389 + 1390 + #ifndef __NR_seccomp 1391 + # if defined(__i386__) 1392 + # define __NR_seccomp 354 1393 + # elif defined(__x86_64__) 1394 + # define __NR_seccomp 317 1395 + # elif defined(__arm__) 1396 + # define __NR_seccomp 383 1397 + # elif defined(__aarch64__) 1398 + # define __NR_seccomp 277 1399 + # else 1400 + # warning "seccomp syscall number unknown for this architecture" 1401 + # define __NR_seccomp 0xffff 1402 + # endif 1403 + #endif 1404 + 1405 + #ifndef SECCOMP_SET_MODE_STRICT 1406 + #define SECCOMP_SET_MODE_STRICT 0 1407 + #endif 1408 + 1409 + #ifndef SECCOMP_SET_MODE_FILTER 1410 + #define SECCOMP_SET_MODE_FILTER 1 1411 + #endif 1412 + 1413 + #ifndef SECCOMP_FLAG_FILTER_TSYNC 1414 + #define SECCOMP_FLAG_FILTER_TSYNC 1 1415 + #endif 1416 + 1417 + #ifndef seccomp 1418 + int seccomp(unsigned int op, unsigned int flags, struct sock_fprog *filter) 1419 + { 1420 + errno = 0; 1421 + return syscall(__NR_seccomp, op, flags, filter); 1422 + } 1423 + #endif 1424 + 1425 + TEST(seccomp_syscall) 1426 + { 1427 + struct sock_filter filter[] = { 1428 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1429 + }; 1430 + struct sock_fprog prog = { 1431 + .len = (unsigned short)ARRAY_SIZE(filter), 1432 + .filter = filter, 1433 + }; 1434 + long ret; 1435 + 1436 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 1437 + ASSERT_EQ(0, ret) { 1438 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1439 + } 1440 + 1441 + /* Reject insane operation. */ 1442 + ret = seccomp(-1, 0, &prog); 1443 + EXPECT_EQ(EINVAL, errno) { 1444 + TH_LOG("Did not reject crazy op value!"); 1445 + } 1446 + 1447 + /* Reject strict with flags or pointer. */ 1448 + ret = seccomp(SECCOMP_SET_MODE_STRICT, -1, NULL); 1449 + EXPECT_EQ(EINVAL, errno) { 1450 + TH_LOG("Did not reject mode strict with flags!"); 1451 + } 1452 + ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, &prog); 1453 + EXPECT_EQ(EINVAL, errno) { 1454 + TH_LOG("Did not reject mode strict with uargs!"); 1455 + } 1456 + 1457 + /* Reject insane args for filter. */ 1458 + ret = seccomp(SECCOMP_SET_MODE_FILTER, -1, &prog); 1459 + EXPECT_EQ(EINVAL, errno) { 1460 + TH_LOG("Did not reject crazy filter flags!"); 1461 + } 1462 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, NULL); 1463 + EXPECT_EQ(EFAULT, errno) { 1464 + TH_LOG("Did not reject NULL filter!"); 1465 + } 1466 + 1467 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog); 1468 + EXPECT_EQ(0, errno) { 1469 + TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER: %s", 1470 + strerror(errno)); 1471 + } 1472 + } 1473 + 1474 + TEST(seccomp_syscall_mode_lock) 1475 + { 1476 + struct sock_filter filter[] = { 1477 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1478 + }; 1479 + struct sock_fprog prog = { 1480 + .len = (unsigned short)ARRAY_SIZE(filter), 1481 + .filter = filter, 1482 + }; 1483 + long ret; 1484 + 1485 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0); 1486 + ASSERT_EQ(0, ret) { 1487 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1488 + } 1489 + 1490 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog); 1491 + EXPECT_EQ(0, ret) { 1492 + TH_LOG("Could not install filter!"); 1493 + } 1494 + 1495 + /* Make sure neither entry point will switch to strict. */ 1496 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, 0, 0, 0); 1497 + EXPECT_EQ(EINVAL, errno) { 1498 + TH_LOG("Switched to mode strict!"); 1499 + } 1500 + 1501 + ret = seccomp(SECCOMP_SET_MODE_STRICT, 0, NULL); 1502 + EXPECT_EQ(EINVAL, errno) { 1503 + TH_LOG("Switched to mode strict!"); 1504 + } 1505 + } 1506 + 1507 + TEST(TSYNC_first) 1508 + { 1509 + struct sock_filter filter[] = { 1510 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1511 + }; 1512 + struct sock_fprog prog = { 1513 + .len = (unsigned short)ARRAY_SIZE(filter), 1514 + .filter = filter, 1515 + }; 1516 + long ret; 1517 + 1518 + ret = prctl(PR_SET_NO_NEW_PRIVS, 1, NULL, 0, 0); 1519 + ASSERT_EQ(0, ret) { 1520 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1521 + } 1522 + 1523 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1524 + &prog); 1525 + EXPECT_EQ(0, ret) { 1526 + TH_LOG("Could not install initial filter with TSYNC!"); 1527 + } 1528 + } 1529 + 1530 + #define TSYNC_SIBLINGS 2 1531 + struct tsync_sibling { 1532 + pthread_t tid; 1533 + pid_t system_tid; 1534 + sem_t *started; 1535 + pthread_cond_t *cond; 1536 + pthread_mutex_t *mutex; 1537 + int diverge; 1538 + int num_waits; 1539 + struct sock_fprog *prog; 1540 + struct __test_metadata *metadata; 1541 + }; 1542 + 1543 + FIXTURE_DATA(TSYNC) { 1544 + struct sock_fprog root_prog, apply_prog; 1545 + struct tsync_sibling sibling[TSYNC_SIBLINGS]; 1546 + sem_t started; 1547 + pthread_cond_t cond; 1548 + pthread_mutex_t mutex; 1549 + int sibling_count; 1550 + }; 1551 + 1552 + FIXTURE_SETUP(TSYNC) 1553 + { 1554 + struct sock_filter root_filter[] = { 1555 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1556 + }; 1557 + struct sock_filter apply_filter[] = { 1558 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 1559 + offsetof(struct seccomp_data, nr)), 1560 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 0, 1), 1561 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 1562 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1563 + }; 1564 + 1565 + memset(&self->root_prog, 0, sizeof(self->root_prog)); 1566 + memset(&self->apply_prog, 0, sizeof(self->apply_prog)); 1567 + memset(&self->sibling, 0, sizeof(self->sibling)); 1568 + self->root_prog.filter = malloc(sizeof(root_filter)); 1569 + ASSERT_NE(NULL, self->root_prog.filter); 1570 + memcpy(self->root_prog.filter, &root_filter, sizeof(root_filter)); 1571 + self->root_prog.len = (unsigned short)ARRAY_SIZE(root_filter); 1572 + 1573 + self->apply_prog.filter = malloc(sizeof(apply_filter)); 1574 + ASSERT_NE(NULL, self->apply_prog.filter); 1575 + memcpy(self->apply_prog.filter, &apply_filter, sizeof(apply_filter)); 1576 + self->apply_prog.len = (unsigned short)ARRAY_SIZE(apply_filter); 1577 + 1578 + self->sibling_count = 0; 1579 + pthread_mutex_init(&self->mutex, NULL); 1580 + pthread_cond_init(&self->cond, NULL); 1581 + sem_init(&self->started, 0, 0); 1582 + self->sibling[0].tid = 0; 1583 + self->sibling[0].cond = &self->cond; 1584 + self->sibling[0].started = &self->started; 1585 + self->sibling[0].mutex = &self->mutex; 1586 + self->sibling[0].diverge = 0; 1587 + self->sibling[0].num_waits = 1; 1588 + self->sibling[0].prog = &self->root_prog; 1589 + self->sibling[0].metadata = _metadata; 1590 + self->sibling[1].tid = 0; 1591 + self->sibling[1].cond = &self->cond; 1592 + self->sibling[1].started = &self->started; 1593 + self->sibling[1].mutex = &self->mutex; 1594 + self->sibling[1].diverge = 0; 1595 + self->sibling[1].prog = &self->root_prog; 1596 + self->sibling[1].num_waits = 1; 1597 + self->sibling[1].metadata = _metadata; 1598 + } 1599 + 1600 + FIXTURE_TEARDOWN(TSYNC) 1601 + { 1602 + int sib = 0; 1603 + 1604 + if (self->root_prog.filter) 1605 + free(self->root_prog.filter); 1606 + if (self->apply_prog.filter) 1607 + free(self->apply_prog.filter); 1608 + 1609 + for ( ; sib < self->sibling_count; ++sib) { 1610 + struct tsync_sibling *s = &self->sibling[sib]; 1611 + void *status; 1612 + 1613 + if (!s->tid) 1614 + continue; 1615 + if (pthread_kill(s->tid, 0)) { 1616 + pthread_cancel(s->tid); 1617 + pthread_join(s->tid, &status); 1618 + } 1619 + } 1620 + pthread_mutex_destroy(&self->mutex); 1621 + pthread_cond_destroy(&self->cond); 1622 + sem_destroy(&self->started); 1623 + } 1624 + 1625 + void *tsync_sibling(void *data) 1626 + { 1627 + long ret = 0; 1628 + struct tsync_sibling *me = data; 1629 + 1630 + me->system_tid = syscall(__NR_gettid); 1631 + 1632 + pthread_mutex_lock(me->mutex); 1633 + if (me->diverge) { 1634 + /* Just re-apply the root prog to fork the tree */ 1635 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 1636 + me->prog, 0, 0); 1637 + } 1638 + sem_post(me->started); 1639 + /* Return outside of started so parent notices failures. */ 1640 + if (ret) { 1641 + pthread_mutex_unlock(me->mutex); 1642 + return (void *)SIBLING_EXIT_FAILURE; 1643 + } 1644 + do { 1645 + pthread_cond_wait(me->cond, me->mutex); 1646 + me->num_waits = me->num_waits - 1; 1647 + } while (me->num_waits); 1648 + pthread_mutex_unlock(me->mutex); 1649 + 1650 + ret = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0); 1651 + if (!ret) 1652 + return (void *)SIBLING_EXIT_NEWPRIVS; 1653 + read(0, NULL, 0); 1654 + return (void *)SIBLING_EXIT_UNKILLED; 1655 + } 1656 + 1657 + void tsync_start_sibling(struct tsync_sibling *sibling) 1658 + { 1659 + pthread_create(&sibling->tid, NULL, tsync_sibling, (void *)sibling); 1660 + } 1661 + 1662 + TEST_F(TSYNC, siblings_fail_prctl) 1663 + { 1664 + long ret; 1665 + void *status; 1666 + struct sock_filter filter[] = { 1667 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 1668 + offsetof(struct seccomp_data, nr)), 1669 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_prctl, 0, 1), 1670 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO | EINVAL), 1671 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1672 + }; 1673 + struct sock_fprog prog = { 1674 + .len = (unsigned short)ARRAY_SIZE(filter), 1675 + .filter = filter, 1676 + }; 1677 + 1678 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1679 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1680 + } 1681 + 1682 + /* Check prctl failure detection by requesting sib 0 diverge. */ 1683 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog); 1684 + ASSERT_EQ(0, ret) { 1685 + TH_LOG("setting filter failed"); 1686 + } 1687 + 1688 + self->sibling[0].diverge = 1; 1689 + tsync_start_sibling(&self->sibling[0]); 1690 + tsync_start_sibling(&self->sibling[1]); 1691 + 1692 + while (self->sibling_count < TSYNC_SIBLINGS) { 1693 + sem_wait(&self->started); 1694 + self->sibling_count++; 1695 + } 1696 + 1697 + /* Signal the threads to clean up*/ 1698 + pthread_mutex_lock(&self->mutex); 1699 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1700 + TH_LOG("cond broadcast non-zero"); 1701 + } 1702 + pthread_mutex_unlock(&self->mutex); 1703 + 1704 + /* Ensure diverging sibling failed to call prctl. */ 1705 + pthread_join(self->sibling[0].tid, &status); 1706 + EXPECT_EQ(SIBLING_EXIT_FAILURE, (long)status); 1707 + pthread_join(self->sibling[1].tid, &status); 1708 + EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); 1709 + } 1710 + 1711 + TEST_F(TSYNC, two_siblings_with_ancestor) 1712 + { 1713 + long ret; 1714 + void *status; 1715 + 1716 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1717 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1718 + } 1719 + 1720 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog); 1721 + ASSERT_EQ(0, ret) { 1722 + TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!"); 1723 + } 1724 + tsync_start_sibling(&self->sibling[0]); 1725 + tsync_start_sibling(&self->sibling[1]); 1726 + 1727 + while (self->sibling_count < TSYNC_SIBLINGS) { 1728 + sem_wait(&self->started); 1729 + self->sibling_count++; 1730 + } 1731 + 1732 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1733 + &self->apply_prog); 1734 + ASSERT_EQ(0, ret) { 1735 + TH_LOG("Could install filter on all threads!"); 1736 + } 1737 + /* Tell the siblings to test the policy */ 1738 + pthread_mutex_lock(&self->mutex); 1739 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1740 + TH_LOG("cond broadcast non-zero"); 1741 + } 1742 + pthread_mutex_unlock(&self->mutex); 1743 + /* Ensure they are both killed and don't exit cleanly. */ 1744 + pthread_join(self->sibling[0].tid, &status); 1745 + EXPECT_EQ(0x0, (long)status); 1746 + pthread_join(self->sibling[1].tid, &status); 1747 + EXPECT_EQ(0x0, (long)status); 1748 + } 1749 + 1750 + TEST_F(TSYNC, two_sibling_want_nnp) 1751 + { 1752 + void *status; 1753 + 1754 + /* start siblings before any prctl() operations */ 1755 + tsync_start_sibling(&self->sibling[0]); 1756 + tsync_start_sibling(&self->sibling[1]); 1757 + while (self->sibling_count < TSYNC_SIBLINGS) { 1758 + sem_wait(&self->started); 1759 + self->sibling_count++; 1760 + } 1761 + 1762 + /* Tell the siblings to test no policy */ 1763 + pthread_mutex_lock(&self->mutex); 1764 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1765 + TH_LOG("cond broadcast non-zero"); 1766 + } 1767 + pthread_mutex_unlock(&self->mutex); 1768 + 1769 + /* Ensure they are both upset about lacking nnp. */ 1770 + pthread_join(self->sibling[0].tid, &status); 1771 + EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); 1772 + pthread_join(self->sibling[1].tid, &status); 1773 + EXPECT_EQ(SIBLING_EXIT_NEWPRIVS, (long)status); 1774 + } 1775 + 1776 + TEST_F(TSYNC, two_siblings_with_no_filter) 1777 + { 1778 + long ret; 1779 + void *status; 1780 + 1781 + /* start siblings before any prctl() operations */ 1782 + tsync_start_sibling(&self->sibling[0]); 1783 + tsync_start_sibling(&self->sibling[1]); 1784 + while (self->sibling_count < TSYNC_SIBLINGS) { 1785 + sem_wait(&self->started); 1786 + self->sibling_count++; 1787 + } 1788 + 1789 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1790 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1791 + } 1792 + 1793 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1794 + &self->apply_prog); 1795 + ASSERT_EQ(0, ret) { 1796 + TH_LOG("Could install filter on all threads!"); 1797 + } 1798 + 1799 + /* Tell the siblings to test the policy */ 1800 + pthread_mutex_lock(&self->mutex); 1801 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1802 + TH_LOG("cond broadcast non-zero"); 1803 + } 1804 + pthread_mutex_unlock(&self->mutex); 1805 + 1806 + /* Ensure they are both killed and don't exit cleanly. */ 1807 + pthread_join(self->sibling[0].tid, &status); 1808 + EXPECT_EQ(0x0, (long)status); 1809 + pthread_join(self->sibling[1].tid, &status); 1810 + EXPECT_EQ(0x0, (long)status); 1811 + } 1812 + 1813 + TEST_F(TSYNC, two_siblings_with_one_divergence) 1814 + { 1815 + long ret; 1816 + void *status; 1817 + 1818 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1819 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1820 + } 1821 + 1822 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog); 1823 + ASSERT_EQ(0, ret) { 1824 + TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!"); 1825 + } 1826 + self->sibling[0].diverge = 1; 1827 + tsync_start_sibling(&self->sibling[0]); 1828 + tsync_start_sibling(&self->sibling[1]); 1829 + 1830 + while (self->sibling_count < TSYNC_SIBLINGS) { 1831 + sem_wait(&self->started); 1832 + self->sibling_count++; 1833 + } 1834 + 1835 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1836 + &self->apply_prog); 1837 + ASSERT_EQ(self->sibling[0].system_tid, ret) { 1838 + TH_LOG("Did not fail on diverged sibling."); 1839 + } 1840 + 1841 + /* Wake the threads */ 1842 + pthread_mutex_lock(&self->mutex); 1843 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1844 + TH_LOG("cond broadcast non-zero"); 1845 + } 1846 + pthread_mutex_unlock(&self->mutex); 1847 + 1848 + /* Ensure they are both unkilled. */ 1849 + pthread_join(self->sibling[0].tid, &status); 1850 + EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); 1851 + pthread_join(self->sibling[1].tid, &status); 1852 + EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); 1853 + } 1854 + 1855 + TEST_F(TSYNC, two_siblings_not_under_filter) 1856 + { 1857 + long ret, sib; 1858 + void *status; 1859 + 1860 + ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1861 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1862 + } 1863 + 1864 + /* 1865 + * Sibling 0 will have its own seccomp policy 1866 + * and Sibling 1 will not be under seccomp at 1867 + * all. Sibling 1 will enter seccomp and 0 1868 + * will cause failure. 1869 + */ 1870 + self->sibling[0].diverge = 1; 1871 + tsync_start_sibling(&self->sibling[0]); 1872 + tsync_start_sibling(&self->sibling[1]); 1873 + 1874 + while (self->sibling_count < TSYNC_SIBLINGS) { 1875 + sem_wait(&self->started); 1876 + self->sibling_count++; 1877 + } 1878 + 1879 + ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog); 1880 + ASSERT_EQ(0, ret) { 1881 + TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!"); 1882 + } 1883 + 1884 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1885 + &self->apply_prog); 1886 + ASSERT_EQ(ret, self->sibling[0].system_tid) { 1887 + TH_LOG("Did not fail on diverged sibling."); 1888 + } 1889 + sib = 1; 1890 + if (ret == self->sibling[0].system_tid) 1891 + sib = 0; 1892 + 1893 + pthread_mutex_lock(&self->mutex); 1894 + 1895 + /* Increment the other siblings num_waits so we can clean up 1896 + * the one we just saw. 1897 + */ 1898 + self->sibling[!sib].num_waits += 1; 1899 + 1900 + /* Signal the thread to clean up*/ 1901 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1902 + TH_LOG("cond broadcast non-zero"); 1903 + } 1904 + pthread_mutex_unlock(&self->mutex); 1905 + pthread_join(self->sibling[sib].tid, &status); 1906 + EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status); 1907 + /* Poll for actual task death. pthread_join doesn't guarantee it. */ 1908 + while (!kill(self->sibling[sib].system_tid, 0)) 1909 + sleep(0.1); 1910 + /* Switch to the remaining sibling */ 1911 + sib = !sib; 1912 + 1913 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1914 + &self->apply_prog); 1915 + ASSERT_EQ(0, ret) { 1916 + TH_LOG("Expected the remaining sibling to sync"); 1917 + }; 1918 + 1919 + pthread_mutex_lock(&self->mutex); 1920 + 1921 + /* If remaining sibling didn't have a chance to wake up during 1922 + * the first broadcast, manually reduce the num_waits now. 1923 + */ 1924 + if (self->sibling[sib].num_waits > 1) 1925 + self->sibling[sib].num_waits = 1; 1926 + ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) { 1927 + TH_LOG("cond broadcast non-zero"); 1928 + } 1929 + pthread_mutex_unlock(&self->mutex); 1930 + pthread_join(self->sibling[sib].tid, &status); 1931 + EXPECT_EQ(0, (long)status); 1932 + /* Poll for actual task death. pthread_join doesn't guarantee it. */ 1933 + while (!kill(self->sibling[sib].system_tid, 0)) 1934 + sleep(0.1); 1935 + 1936 + ret = seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FLAG_FILTER_TSYNC, 1937 + &self->apply_prog); 1938 + ASSERT_EQ(0, ret); /* just us chickens */ 1939 + } 1940 + 1941 + /* Make sure restarted syscalls are seen directly as "restart_syscall". */ 1942 + TEST(syscall_restart) 1943 + { 1944 + long ret; 1945 + unsigned long msg; 1946 + pid_t child_pid; 1947 + int pipefd[2]; 1948 + int status; 1949 + siginfo_t info = { }; 1950 + struct sock_filter filter[] = { 1951 + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 1952 + offsetof(struct seccomp_data, nr)), 1953 + 1954 + #ifdef __NR_sigreturn 1955 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_sigreturn, 6, 0), 1956 + #endif 1957 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 5, 0), 1958 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit, 4, 0), 1959 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_rt_sigreturn, 3, 0), 1960 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_poll, 4, 0), 1961 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_restart_syscall, 4, 0), 1962 + 1963 + /* Allow __NR_write for easy logging. */ 1964 + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_write, 0, 1), 1965 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 1966 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), 1967 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100), /* poll */ 1968 + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200), /* restart */ 1969 + }; 1970 + struct sock_fprog prog = { 1971 + .len = (unsigned short)ARRAY_SIZE(filter), 1972 + .filter = filter, 1973 + }; 1974 + 1975 + ASSERT_EQ(0, pipe(pipefd)); 1976 + 1977 + child_pid = fork(); 1978 + ASSERT_LE(0, child_pid); 1979 + if (child_pid == 0) { 1980 + /* Child uses EXPECT not ASSERT to deliver status correctly. */ 1981 + char buf = ' '; 1982 + struct pollfd fds = { 1983 + .fd = pipefd[0], 1984 + .events = POLLIN, 1985 + }; 1986 + 1987 + /* Attach parent as tracer and stop. */ 1988 + EXPECT_EQ(0, ptrace(PTRACE_TRACEME)); 1989 + EXPECT_EQ(0, raise(SIGSTOP)); 1990 + 1991 + EXPECT_EQ(0, close(pipefd[1])); 1992 + 1993 + EXPECT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 1994 + TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!"); 1995 + } 1996 + 1997 + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0); 1998 + EXPECT_EQ(0, ret) { 1999 + TH_LOG("Failed to install filter!"); 2000 + } 2001 + 2002 + EXPECT_EQ(1, read(pipefd[0], &buf, 1)) { 2003 + TH_LOG("Failed to read() sync from parent"); 2004 + } 2005 + EXPECT_EQ('.', buf) { 2006 + TH_LOG("Failed to get sync data from read()"); 2007 + } 2008 + 2009 + /* Start poll to be interrupted. */ 2010 + errno = 0; 2011 + EXPECT_EQ(1, poll(&fds, 1, -1)) { 2012 + TH_LOG("Call to poll() failed (errno %d)", errno); 2013 + } 2014 + 2015 + /* Read final sync from parent. */ 2016 + EXPECT_EQ(1, read(pipefd[0], &buf, 1)) { 2017 + TH_LOG("Failed final read() from parent"); 2018 + } 2019 + EXPECT_EQ('!', buf) { 2020 + TH_LOG("Failed to get final data from read()"); 2021 + } 2022 + 2023 + /* Directly report the status of our test harness results. */ 2024 + syscall(__NR_exit, _metadata->passed ? EXIT_SUCCESS 2025 + : EXIT_FAILURE); 2026 + } 2027 + EXPECT_EQ(0, close(pipefd[0])); 2028 + 2029 + /* Attach to child, setup options, and release. */ 2030 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2031 + ASSERT_EQ(true, WIFSTOPPED(status)); 2032 + ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid, NULL, 2033 + PTRACE_O_TRACESECCOMP)); 2034 + ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); 2035 + ASSERT_EQ(1, write(pipefd[1], ".", 1)); 2036 + 2037 + /* Wait for poll() to start. */ 2038 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2039 + ASSERT_EQ(true, WIFSTOPPED(status)); 2040 + ASSERT_EQ(SIGTRAP, WSTOPSIG(status)); 2041 + ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16)); 2042 + ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg)); 2043 + ASSERT_EQ(0x100, msg); 2044 + EXPECT_EQ(__NR_poll, get_syscall(_metadata, child_pid)); 2045 + 2046 + /* Might as well check siginfo for sanity while we're here. */ 2047 + ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info)); 2048 + ASSERT_EQ(SIGTRAP, info.si_signo); 2049 + ASSERT_EQ(SIGTRAP | (PTRACE_EVENT_SECCOMP << 8), info.si_code); 2050 + EXPECT_EQ(0, info.si_errno); 2051 + EXPECT_EQ(getuid(), info.si_uid); 2052 + /* Verify signal delivery came from child (seccomp-triggered). */ 2053 + EXPECT_EQ(child_pid, info.si_pid); 2054 + 2055 + /* Interrupt poll with SIGSTOP (which we'll need to handle). */ 2056 + ASSERT_EQ(0, kill(child_pid, SIGSTOP)); 2057 + ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); 2058 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2059 + ASSERT_EQ(true, WIFSTOPPED(status)); 2060 + ASSERT_EQ(SIGSTOP, WSTOPSIG(status)); 2061 + /* Verify signal delivery came from parent now. */ 2062 + ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info)); 2063 + EXPECT_EQ(getpid(), info.si_pid); 2064 + 2065 + /* Restart poll with SIGCONT, which triggers restart_syscall. */ 2066 + ASSERT_EQ(0, kill(child_pid, SIGCONT)); 2067 + ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); 2068 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2069 + ASSERT_EQ(true, WIFSTOPPED(status)); 2070 + ASSERT_EQ(SIGCONT, WSTOPSIG(status)); 2071 + ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); 2072 + 2073 + /* Wait for restart_syscall() to start. */ 2074 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2075 + ASSERT_EQ(true, WIFSTOPPED(status)); 2076 + ASSERT_EQ(SIGTRAP, WSTOPSIG(status)); 2077 + ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16)); 2078 + ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg)); 2079 + ASSERT_EQ(0x200, msg); 2080 + ret = get_syscall(_metadata, child_pid); 2081 + #if defined(__arm__) 2082 + /* FIXME: ARM does not expose true syscall in registers. */ 2083 + EXPECT_EQ(__NR_poll, ret); 2084 + #else 2085 + EXPECT_EQ(__NR_restart_syscall, ret); 2086 + #endif 2087 + 2088 + /* Write again to end poll. */ 2089 + ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); 2090 + ASSERT_EQ(1, write(pipefd[1], "!", 1)); 2091 + EXPECT_EQ(0, close(pipefd[1])); 2092 + 2093 + ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); 2094 + if (WIFSIGNALED(status) || WEXITSTATUS(status)) 2095 + _metadata->passed = 0; 2096 + } 2097 + 2098 + /* 2099 + * TODO: 2100 + * - add microbenchmarks 2101 + * - expand NNP testing 2102 + * - better arch-specific TRACE and TRAP handlers. 2103 + * - endianness checking when appropriate 2104 + * - 64-bit arg prodding 2105 + * - arch value testing (x86 modes especially) 2106 + * - ... 2107 + */ 2108 + 2109 + TEST_HARNESS_MAIN
+537
tools/testing/selftests/seccomp/test_harness.h
··· 1 + /* 2 + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 3 + * Use of this source code is governed by the GPLv2 license. 4 + * 5 + * test_harness.h: simple C unit test helper. 6 + * 7 + * Usage: 8 + * #include "test_harness.h" 9 + * TEST(standalone_test) { 10 + * do_some_stuff; 11 + * EXPECT_GT(10, stuff) { 12 + * stuff_state_t state; 13 + * enumerate_stuff_state(&state); 14 + * TH_LOG("expectation failed with state: %s", state.msg); 15 + * } 16 + * more_stuff; 17 + * ASSERT_NE(some_stuff, NULL) TH_LOG("how did it happen?!"); 18 + * last_stuff; 19 + * EXPECT_EQ(0, last_stuff); 20 + * } 21 + * 22 + * FIXTURE(my_fixture) { 23 + * mytype_t *data; 24 + * int awesomeness_level; 25 + * }; 26 + * FIXTURE_SETUP(my_fixture) { 27 + * self->data = mytype_new(); 28 + * ASSERT_NE(NULL, self->data); 29 + * } 30 + * FIXTURE_TEARDOWN(my_fixture) { 31 + * mytype_free(self->data); 32 + * } 33 + * TEST_F(my_fixture, data_is_good) { 34 + * EXPECT_EQ(1, is_my_data_good(self->data)); 35 + * } 36 + * 37 + * TEST_HARNESS_MAIN 38 + * 39 + * API inspired by code.google.com/p/googletest 40 + */ 41 + #ifndef TEST_HARNESS_H_ 42 + #define TEST_HARNESS_H_ 43 + 44 + #define _GNU_SOURCE 45 + #include <stdio.h> 46 + #include <stdlib.h> 47 + #include <string.h> 48 + #include <sys/types.h> 49 + #include <sys/wait.h> 50 + #include <unistd.h> 51 + 52 + /* All exported functionality should be declared through this macro. */ 53 + #define TEST_API(x) _##x 54 + 55 + /* 56 + * Exported APIs 57 + */ 58 + 59 + /* TEST(name) { implementation } 60 + * Defines a test by name. 61 + * Names must be unique and tests must not be run in parallel. The 62 + * implementation containing block is a function and scoping should be treated 63 + * as such. Returning early may be performed with a bare "return;" statement. 64 + * 65 + * EXPECT_* and ASSERT_* are valid in a TEST() { } context. 66 + */ 67 + #define TEST TEST_API(TEST) 68 + 69 + /* TEST_SIGNAL(name, signal) { implementation } 70 + * Defines a test by name and the expected term signal. 71 + * Names must be unique and tests must not be run in parallel. The 72 + * implementation containing block is a function and scoping should be treated 73 + * as such. Returning early may be performed with a bare "return;" statement. 74 + * 75 + * EXPECT_* and ASSERT_* are valid in a TEST() { } context. 76 + */ 77 + #define TEST_SIGNAL TEST_API(TEST_SIGNAL) 78 + 79 + /* FIXTURE(datatype name) { 80 + * type property1; 81 + * ... 82 + * }; 83 + * Defines the data provided to TEST_F()-defined tests as |self|. It should be 84 + * populated and cleaned up using FIXTURE_SETUP and FIXTURE_TEARDOWN. 85 + */ 86 + #define FIXTURE TEST_API(FIXTURE) 87 + 88 + /* FIXTURE_DATA(datatype name) 89 + * This call may be used when the type of the fixture data 90 + * is needed. In general, this should not be needed unless 91 + * the |self| is being passed to a helper directly. 92 + */ 93 + #define FIXTURE_DATA TEST_API(FIXTURE_DATA) 94 + 95 + /* FIXTURE_SETUP(fixture name) { implementation } 96 + * Populates the required "setup" function for a fixture. An instance of the 97 + * datatype defined with _FIXTURE_DATA will be exposed as |self| for the 98 + * implementation. 99 + * 100 + * ASSERT_* are valid for use in this context and will prempt the execution 101 + * of any dependent fixture tests. 102 + * 103 + * A bare "return;" statement may be used to return early. 104 + */ 105 + #define FIXTURE_SETUP TEST_API(FIXTURE_SETUP) 106 + 107 + /* FIXTURE_TEARDOWN(fixture name) { implementation } 108 + * Populates the required "teardown" function for a fixture. An instance of the 109 + * datatype defined with _FIXTURE_DATA will be exposed as |self| for the 110 + * implementation to clean up. 111 + * 112 + * A bare "return;" statement may be used to return early. 113 + */ 114 + #define FIXTURE_TEARDOWN TEST_API(FIXTURE_TEARDOWN) 115 + 116 + /* TEST_F(fixture, name) { implementation } 117 + * Defines a test that depends on a fixture (e.g., is part of a test case). 118 + * Very similar to TEST() except that |self| is the setup instance of fixture's 119 + * datatype exposed for use by the implementation. 120 + */ 121 + #define TEST_F TEST_API(TEST_F) 122 + 123 + #define TEST_F_SIGNAL TEST_API(TEST_F_SIGNAL) 124 + 125 + /* Use once to append a main() to the test file. E.g., 126 + * TEST_HARNESS_MAIN 127 + */ 128 + #define TEST_HARNESS_MAIN TEST_API(TEST_HARNESS_MAIN) 129 + 130 + /* 131 + * Operators for use in TEST and TEST_F. 132 + * ASSERT_* calls will stop test execution immediately. 133 + * EXPECT_* calls will emit a failure warning, note it, and continue. 134 + */ 135 + 136 + /* ASSERT_EQ(expected, measured): expected == measured */ 137 + #define ASSERT_EQ TEST_API(ASSERT_EQ) 138 + /* ASSERT_NE(expected, measured): expected != measured */ 139 + #define ASSERT_NE TEST_API(ASSERT_NE) 140 + /* ASSERT_LT(expected, measured): expected < measured */ 141 + #define ASSERT_LT TEST_API(ASSERT_LT) 142 + /* ASSERT_LE(expected, measured): expected <= measured */ 143 + #define ASSERT_LE TEST_API(ASSERT_LE) 144 + /* ASSERT_GT(expected, measured): expected > measured */ 145 + #define ASSERT_GT TEST_API(ASSERT_GT) 146 + /* ASSERT_GE(expected, measured): expected >= measured */ 147 + #define ASSERT_GE TEST_API(ASSERT_GE) 148 + /* ASSERT_NULL(measured): NULL == measured */ 149 + #define ASSERT_NULL TEST_API(ASSERT_NULL) 150 + /* ASSERT_TRUE(measured): measured != 0 */ 151 + #define ASSERT_TRUE TEST_API(ASSERT_TRUE) 152 + /* ASSERT_FALSE(measured): measured == 0 */ 153 + #define ASSERT_FALSE TEST_API(ASSERT_FALSE) 154 + /* ASSERT_STREQ(expected, measured): !strcmp(expected, measured) */ 155 + #define ASSERT_STREQ TEST_API(ASSERT_STREQ) 156 + /* ASSERT_STRNE(expected, measured): strcmp(expected, measured) */ 157 + #define ASSERT_STRNE TEST_API(ASSERT_STRNE) 158 + /* EXPECT_EQ(expected, measured): expected == measured */ 159 + #define EXPECT_EQ TEST_API(EXPECT_EQ) 160 + /* EXPECT_NE(expected, measured): expected != measured */ 161 + #define EXPECT_NE TEST_API(EXPECT_NE) 162 + /* EXPECT_LT(expected, measured): expected < measured */ 163 + #define EXPECT_LT TEST_API(EXPECT_LT) 164 + /* EXPECT_LE(expected, measured): expected <= measured */ 165 + #define EXPECT_LE TEST_API(EXPECT_LE) 166 + /* EXPECT_GT(expected, measured): expected > measured */ 167 + #define EXPECT_GT TEST_API(EXPECT_GT) 168 + /* EXPECT_GE(expected, measured): expected >= measured */ 169 + #define EXPECT_GE TEST_API(EXPECT_GE) 170 + /* EXPECT_NULL(measured): NULL == measured */ 171 + #define EXPECT_NULL TEST_API(EXPECT_NULL) 172 + /* EXPECT_TRUE(measured): 0 != measured */ 173 + #define EXPECT_TRUE TEST_API(EXPECT_TRUE) 174 + /* EXPECT_FALSE(measured): 0 == measured */ 175 + #define EXPECT_FALSE TEST_API(EXPECT_FALSE) 176 + /* EXPECT_STREQ(expected, measured): !strcmp(expected, measured) */ 177 + #define EXPECT_STREQ TEST_API(EXPECT_STREQ) 178 + /* EXPECT_STRNE(expected, measured): strcmp(expected, measured) */ 179 + #define EXPECT_STRNE TEST_API(EXPECT_STRNE) 180 + 181 + /* TH_LOG(format, ...) 182 + * Optional debug logging function available for use in tests. 183 + * Logging may be enabled or disabled by defining TH_LOG_ENABLED. 184 + * E.g., #define TH_LOG_ENABLED 1 185 + * If no definition is provided, logging is enabled by default. 186 + */ 187 + #define TH_LOG TEST_API(TH_LOG) 188 + 189 + /* 190 + * Internal implementation. 191 + * 192 + */ 193 + 194 + /* Utilities exposed to the test definitions */ 195 + #ifndef TH_LOG_STREAM 196 + # define TH_LOG_STREAM stderr 197 + #endif 198 + 199 + #ifndef TH_LOG_ENABLED 200 + # define TH_LOG_ENABLED 1 201 + #endif 202 + 203 + #define _TH_LOG(fmt, ...) do { \ 204 + if (TH_LOG_ENABLED) \ 205 + __TH_LOG(fmt, ##__VA_ARGS__); \ 206 + } while (0) 207 + 208 + /* Unconditional logger for internal use. */ 209 + #define __TH_LOG(fmt, ...) \ 210 + fprintf(TH_LOG_STREAM, "%s:%d:%s:" fmt "\n", \ 211 + __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__) 212 + 213 + /* Defines the test function and creates the registration stub. */ 214 + #define _TEST(test_name) __TEST_IMPL(test_name, -1) 215 + 216 + #define _TEST_SIGNAL(test_name, signal) __TEST_IMPL(test_name, signal) 217 + 218 + #define __TEST_IMPL(test_name, _signal) \ 219 + static void test_name(struct __test_metadata *_metadata); \ 220 + static struct __test_metadata _##test_name##_object = \ 221 + { name: "global." #test_name, \ 222 + fn: &test_name, termsig: _signal }; \ 223 + static void __attribute__((constructor)) _register_##test_name(void) \ 224 + { \ 225 + __register_test(&_##test_name##_object); \ 226 + } \ 227 + static void test_name( \ 228 + struct __test_metadata __attribute__((unused)) *_metadata) 229 + 230 + /* Wraps the struct name so we have one less argument to pass around. */ 231 + #define _FIXTURE_DATA(fixture_name) struct _test_data_##fixture_name 232 + 233 + /* Called once per fixture to setup the data and register. */ 234 + #define _FIXTURE(fixture_name) \ 235 + static void __attribute__((constructor)) \ 236 + _register_##fixture_name##_data(void) \ 237 + { \ 238 + __fixture_count++; \ 239 + } \ 240 + _FIXTURE_DATA(fixture_name) 241 + 242 + /* Prepares the setup function for the fixture. |_metadata| is included 243 + * so that ASSERT_* work as a convenience. 244 + */ 245 + #define _FIXTURE_SETUP(fixture_name) \ 246 + void fixture_name##_setup( \ 247 + struct __test_metadata __attribute__((unused)) *_metadata, \ 248 + _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) 249 + #define _FIXTURE_TEARDOWN(fixture_name) \ 250 + void fixture_name##_teardown( \ 251 + struct __test_metadata __attribute__((unused)) *_metadata, \ 252 + _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) 253 + 254 + /* Emits test registration and helpers for fixture-based test 255 + * cases. 256 + * TODO(wad) register fixtures on dedicated test lists. 257 + */ 258 + #define _TEST_F(fixture_name, test_name) \ 259 + __TEST_F_IMPL(fixture_name, test_name, -1) 260 + 261 + #define _TEST_F_SIGNAL(fixture_name, test_name, signal) \ 262 + __TEST_F_IMPL(fixture_name, test_name, signal) 263 + 264 + #define __TEST_F_IMPL(fixture_name, test_name, signal) \ 265 + static void fixture_name##_##test_name( \ 266 + struct __test_metadata *_metadata, \ 267 + _FIXTURE_DATA(fixture_name) *self); \ 268 + static inline void wrapper_##fixture_name##_##test_name( \ 269 + struct __test_metadata *_metadata) \ 270 + { \ 271 + /* fixture data is alloced, setup, and torn down per call. */ \ 272 + _FIXTURE_DATA(fixture_name) self; \ 273 + memset(&self, 0, sizeof(_FIXTURE_DATA(fixture_name))); \ 274 + fixture_name##_setup(_metadata, &self); \ 275 + /* Let setup failure terminate early. */ \ 276 + if (!_metadata->passed) \ 277 + return; \ 278 + fixture_name##_##test_name(_metadata, &self); \ 279 + fixture_name##_teardown(_metadata, &self); \ 280 + } \ 281 + static struct __test_metadata \ 282 + _##fixture_name##_##test_name##_object = { \ 283 + name: #fixture_name "." #test_name, \ 284 + fn: &wrapper_##fixture_name##_##test_name, \ 285 + termsig: signal, \ 286 + }; \ 287 + static void __attribute__((constructor)) \ 288 + _register_##fixture_name##_##test_name(void) \ 289 + { \ 290 + __register_test(&_##fixture_name##_##test_name##_object); \ 291 + } \ 292 + static void fixture_name##_##test_name( \ 293 + struct __test_metadata __attribute__((unused)) *_metadata, \ 294 + _FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) 295 + 296 + /* Exports a simple wrapper to run the test harness. */ 297 + #define _TEST_HARNESS_MAIN \ 298 + static void __attribute__((constructor)) \ 299 + __constructor_order_last(void) \ 300 + { \ 301 + if (!__constructor_order) \ 302 + __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD; \ 303 + } \ 304 + int main(int argc, char **argv) { \ 305 + return test_harness_run(argc, argv); \ 306 + } 307 + 308 + #define _ASSERT_EQ(_expected, _seen) \ 309 + __EXPECT(_expected, _seen, ==, 1) 310 + #define _ASSERT_NE(_expected, _seen) \ 311 + __EXPECT(_expected, _seen, !=, 1) 312 + #define _ASSERT_LT(_expected, _seen) \ 313 + __EXPECT(_expected, _seen, <, 1) 314 + #define _ASSERT_LE(_expected, _seen) \ 315 + __EXPECT(_expected, _seen, <=, 1) 316 + #define _ASSERT_GT(_expected, _seen) \ 317 + __EXPECT(_expected, _seen, >, 1) 318 + #define _ASSERT_GE(_expected, _seen) \ 319 + __EXPECT(_expected, _seen, >=, 1) 320 + #define _ASSERT_NULL(_seen) \ 321 + __EXPECT(NULL, _seen, ==, 1) 322 + 323 + #define _ASSERT_TRUE(_seen) \ 324 + _ASSERT_NE(0, _seen) 325 + #define _ASSERT_FALSE(_seen) \ 326 + _ASSERT_EQ(0, _seen) 327 + #define _ASSERT_STREQ(_expected, _seen) \ 328 + __EXPECT_STR(_expected, _seen, ==, 1) 329 + #define _ASSERT_STRNE(_expected, _seen) \ 330 + __EXPECT_STR(_expected, _seen, !=, 1) 331 + 332 + #define _EXPECT_EQ(_expected, _seen) \ 333 + __EXPECT(_expected, _seen, ==, 0) 334 + #define _EXPECT_NE(_expected, _seen) \ 335 + __EXPECT(_expected, _seen, !=, 0) 336 + #define _EXPECT_LT(_expected, _seen) \ 337 + __EXPECT(_expected, _seen, <, 0) 338 + #define _EXPECT_LE(_expected, _seen) \ 339 + __EXPECT(_expected, _seen, <=, 0) 340 + #define _EXPECT_GT(_expected, _seen) \ 341 + __EXPECT(_expected, _seen, >, 0) 342 + #define _EXPECT_GE(_expected, _seen) \ 343 + __EXPECT(_expected, _seen, >=, 0) 344 + 345 + #define _EXPECT_NULL(_seen) \ 346 + __EXPECT(NULL, _seen, ==, 0) 347 + #define _EXPECT_TRUE(_seen) \ 348 + _EXPECT_NE(0, _seen) 349 + #define _EXPECT_FALSE(_seen) \ 350 + _EXPECT_EQ(0, _seen) 351 + 352 + #define _EXPECT_STREQ(_expected, _seen) \ 353 + __EXPECT_STR(_expected, _seen, ==, 0) 354 + #define _EXPECT_STRNE(_expected, _seen) \ 355 + __EXPECT_STR(_expected, _seen, !=, 0) 356 + 357 + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 358 + 359 + /* Support an optional handler after and ASSERT_* or EXPECT_*. The approach is 360 + * not thread-safe, but it should be fine in most sane test scenarios. 361 + * 362 + * Using __bail(), which optionally abort()s, is the easiest way to early 363 + * return while still providing an optional block to the API consumer. 364 + */ 365 + #define OPTIONAL_HANDLER(_assert) \ 366 + for (; _metadata->trigger; _metadata->trigger = __bail(_assert)) 367 + 368 + #define __EXPECT(_expected, _seen, _t, _assert) do { \ 369 + /* Avoid multiple evaluation of the cases */ \ 370 + __typeof__(_expected) __exp = (_expected); \ 371 + __typeof__(_seen) __seen = (_seen); \ 372 + if (!(__exp _t __seen)) { \ 373 + unsigned long long __exp_print = 0; \ 374 + unsigned long long __seen_print = 0; \ 375 + /* Avoid casting complaints the scariest way we can. */ \ 376 + memcpy(&__exp_print, &__exp, sizeof(__exp)); \ 377 + memcpy(&__seen_print, &__seen, sizeof(__seen)); \ 378 + __TH_LOG("Expected %s (%llu) %s %s (%llu)", \ 379 + #_expected, __exp_print, #_t, \ 380 + #_seen, __seen_print); \ 381 + _metadata->passed = 0; \ 382 + /* Ensure the optional handler is triggered */ \ 383 + _metadata->trigger = 1; \ 384 + } \ 385 + } while (0); OPTIONAL_HANDLER(_assert) 386 + 387 + #define __EXPECT_STR(_expected, _seen, _t, _assert) do { \ 388 + const char *__exp = (_expected); \ 389 + const char *__seen = (_seen); \ 390 + if (!(strcmp(__exp, __seen) _t 0)) { \ 391 + __TH_LOG("Expected '%s' %s '%s'.", __exp, #_t, __seen); \ 392 + _metadata->passed = 0; \ 393 + _metadata->trigger = 1; \ 394 + } \ 395 + } while (0); OPTIONAL_HANDLER(_assert) 396 + 397 + /* Contains all the information for test execution and status checking. */ 398 + struct __test_metadata { 399 + const char *name; 400 + void (*fn)(struct __test_metadata *); 401 + int termsig; 402 + int passed; 403 + int trigger; /* extra handler after the evaluation */ 404 + struct __test_metadata *prev, *next; 405 + }; 406 + 407 + /* Storage for the (global) tests to be run. */ 408 + static struct __test_metadata *__test_list; 409 + static unsigned int __test_count; 410 + static unsigned int __fixture_count; 411 + static int __constructor_order; 412 + 413 + #define _CONSTRUCTOR_ORDER_FORWARD 1 414 + #define _CONSTRUCTOR_ORDER_BACKWARD -1 415 + 416 + /* 417 + * Since constructors are called in reverse order, reverse the test 418 + * list so tests are run in source declaration order. 419 + * https://gcc.gnu.org/onlinedocs/gccint/Initialization.html 420 + * However, it seems not all toolchains do this correctly, so use 421 + * __constructor_order to detect which direction is called first 422 + * and adjust list building logic to get things running in the right 423 + * direction. 424 + */ 425 + static inline void __register_test(struct __test_metadata *t) 426 + { 427 + __test_count++; 428 + /* Circular linked list where only prev is circular. */ 429 + if (__test_list == NULL) { 430 + __test_list = t; 431 + t->next = NULL; 432 + t->prev = t; 433 + return; 434 + } 435 + if (__constructor_order == _CONSTRUCTOR_ORDER_FORWARD) { 436 + t->next = NULL; 437 + t->prev = __test_list->prev; 438 + t->prev->next = t; 439 + __test_list->prev = t; 440 + } else { 441 + t->next = __test_list; 442 + t->next->prev = t; 443 + t->prev = t; 444 + __test_list = t; 445 + } 446 + } 447 + 448 + static inline int __bail(int for_realz) 449 + { 450 + if (for_realz) 451 + abort(); 452 + return 0; 453 + } 454 + 455 + void __run_test(struct __test_metadata *t) 456 + { 457 + pid_t child_pid; 458 + int status; 459 + 460 + t->passed = 1; 461 + t->trigger = 0; 462 + printf("[ RUN ] %s\n", t->name); 463 + child_pid = fork(); 464 + if (child_pid < 0) { 465 + printf("ERROR SPAWNING TEST CHILD\n"); 466 + t->passed = 0; 467 + } else if (child_pid == 0) { 468 + t->fn(t); 469 + _exit(t->passed); 470 + } else { 471 + /* TODO(wad) add timeout support. */ 472 + waitpid(child_pid, &status, 0); 473 + if (WIFEXITED(status)) { 474 + t->passed = t->termsig == -1 ? WEXITSTATUS(status) : 0; 475 + if (t->termsig != -1) { 476 + fprintf(TH_LOG_STREAM, 477 + "%s: Test exited normally " 478 + "instead of by signal (code: %d)\n", 479 + t->name, 480 + WEXITSTATUS(status)); 481 + } 482 + } else if (WIFSIGNALED(status)) { 483 + t->passed = 0; 484 + if (WTERMSIG(status) == SIGABRT) { 485 + fprintf(TH_LOG_STREAM, 486 + "%s: Test terminated by assertion\n", 487 + t->name); 488 + } else if (WTERMSIG(status) == t->termsig) { 489 + t->passed = 1; 490 + } else { 491 + fprintf(TH_LOG_STREAM, 492 + "%s: Test terminated unexpectedly " 493 + "by signal %d\n", 494 + t->name, 495 + WTERMSIG(status)); 496 + } 497 + } else { 498 + fprintf(TH_LOG_STREAM, 499 + "%s: Test ended in some other way [%u]\n", 500 + t->name, 501 + status); 502 + } 503 + } 504 + printf("[ %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name); 505 + } 506 + 507 + static int test_harness_run(int __attribute__((unused)) argc, 508 + char __attribute__((unused)) **argv) 509 + { 510 + struct __test_metadata *t; 511 + int ret = 0; 512 + unsigned int count = 0; 513 + unsigned int pass_count = 0; 514 + 515 + /* TODO(wad) add optional arguments similar to gtest. */ 516 + printf("[==========] Running %u tests from %u test cases.\n", 517 + __test_count, __fixture_count + 1); 518 + for (t = __test_list; t; t = t->next) { 519 + count++; 520 + __run_test(t); 521 + if (t->passed) 522 + pass_count++; 523 + else 524 + ret = 1; 525 + } 526 + printf("[==========] %u / %u tests passed.\n", pass_count, count); 527 + printf("[ %s ]\n", (ret ? "FAILED" : "PASSED")); 528 + return ret; 529 + } 530 + 531 + static void __attribute__((constructor)) __constructor_order_first(void) 532 + { 533 + if (!__constructor_order) 534 + __constructor_order = _CONSTRUCTOR_ORDER_FORWARD; 535 + } 536 + 537 + #endif /* TEST_HARNESS_H_ */
+18
tools/testing/selftests/timers/.gitignore
··· 1 + alarmtimer-suspend 2 + change_skew 3 + clocksource-switch 4 + inconsistency-check 5 + leap-a-day 6 + leapcrash 7 + mqueue-lat 8 + nanosleep 9 + nsleep-lat 10 + posix_timers 11 + raw_skew 12 + rtctest 13 + set-2038 14 + set-tai 15 + set-timer-lat 16 + skew_consistency 17 + threadtest 18 + valid-adjtimex
+7 -3
tools/testing/selftests/timers/alarmtimer-suspend.c
··· 57 57 58 58 59 59 #define NSEC_PER_SEC 1000000000ULL 60 - #define UNREASONABLE_LAT (NSEC_PER_SEC * 4) /* hopefully we resume in 4secs */ 60 + #define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */ 61 61 62 62 #define SUSPEND_SECS 15 63 63 int alarmcount; ··· 152 152 alarm_clock_id++) { 153 153 154 154 alarmcount = 0; 155 - timer_create(alarm_clock_id, &se, &tm1); 155 + if (timer_create(alarm_clock_id, &se, &tm1) == -1) { 156 + printf("timer_create failled, %s unspported?\n", 157 + clockstring(alarm_clock_id)); 158 + break; 159 + } 156 160 157 161 clock_gettime(alarm_clock_id, &start_time); 158 162 printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id), ··· 176 172 while (alarmcount < 10) { 177 173 int ret; 178 174 179 - sleep(1); 175 + sleep(3); 180 176 ret = system("echo mem > /sys/power/state"); 181 177 if (ret) 182 178 break;
+6 -1
tools/testing/selftests/vm/Makefile
··· 1 1 # Makefile for vm selftests 2 2 3 3 CFLAGS = -Wall 4 - BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest 4 + BINARIES = compaction_test 5 + BINARIES += hugepage-mmap 6 + BINARIES += hugepage-shm 7 + BINARIES += hugetlbfstest 8 + BINARIES += map_hugetlb 9 + BINARIES += thuge-gen 5 10 BINARIES += transhuge-stress 6 11 7 12 all: $(BINARIES)
+225
tools/testing/selftests/vm/compaction_test.c
··· 1 + /* 2 + * 3 + * A test for the patch "Allow compaction of unevictable pages". 4 + * With this patch we should be able to allocate at least 1/4 5 + * of RAM in huge pages. Without the patch much less is 6 + * allocated. 7 + */ 8 + 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <sys/mman.h> 12 + #include <sys/resource.h> 13 + #include <fcntl.h> 14 + #include <errno.h> 15 + #include <unistd.h> 16 + #include <string.h> 17 + 18 + #define MAP_SIZE 1048576 19 + 20 + struct map_list { 21 + void *map; 22 + struct map_list *next; 23 + }; 24 + 25 + int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize) 26 + { 27 + char buffer[256] = {0}; 28 + char *cmd = "cat /proc/meminfo | grep -i memfree | grep -o '[0-9]*'"; 29 + FILE *cmdfile = popen(cmd, "r"); 30 + 31 + if (!(fgets(buffer, sizeof(buffer), cmdfile))) { 32 + perror("Failed to read meminfo\n"); 33 + return -1; 34 + } 35 + 36 + pclose(cmdfile); 37 + 38 + *memfree = atoll(buffer); 39 + cmd = "cat /proc/meminfo | grep -i hugepagesize | grep -o '[0-9]*'"; 40 + cmdfile = popen(cmd, "r"); 41 + 42 + if (!(fgets(buffer, sizeof(buffer), cmdfile))) { 43 + perror("Failed to read meminfo\n"); 44 + return -1; 45 + } 46 + 47 + pclose(cmdfile); 48 + *hugepagesize = atoll(buffer); 49 + 50 + return 0; 51 + } 52 + 53 + int prereq(void) 54 + { 55 + char allowed; 56 + int fd; 57 + 58 + fd = open("/proc/sys/vm/compact_unevictable_allowed", 59 + O_RDONLY | O_NONBLOCK); 60 + if (fd < 0) { 61 + perror("Failed to open\n" 62 + "/proc/sys/vm/compact_unevictable_allowed\n"); 63 + return -1; 64 + } 65 + 66 + if (read(fd, &allowed, sizeof(char)) != sizeof(char)) { 67 + perror("Failed to read from\n" 68 + "/proc/sys/vm/compact_unevictable_allowed\n"); 69 + close(fd); 70 + return -1; 71 + } 72 + 73 + close(fd); 74 + if (allowed == '1') 75 + return 0; 76 + 77 + return -1; 78 + } 79 + 80 + int check_compaction(unsigned long mem_free, unsigned int hugepage_size) 81 + { 82 + int fd; 83 + int compaction_index = 0; 84 + char initial_nr_hugepages[10] = {0}; 85 + char nr_hugepages[10] = {0}; 86 + 87 + /* We want to test with 80% of available memory. Else, OOM killer comes 88 + in to play */ 89 + mem_free = mem_free * 0.8; 90 + 91 + fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK); 92 + if (fd < 0) { 93 + perror("Failed to open /proc/sys/vm/nr_hugepages"); 94 + return -1; 95 + } 96 + 97 + if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) { 98 + perror("Failed to read from /proc/sys/vm/nr_hugepages"); 99 + goto close_fd; 100 + } 101 + 102 + /* Start with the initial condition of 0 huge pages*/ 103 + if (write(fd, "0", sizeof(char)) != sizeof(char)) { 104 + perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); 105 + goto close_fd; 106 + } 107 + 108 + lseek(fd, 0, SEEK_SET); 109 + 110 + /* Request a large number of huge pages. The Kernel will allocate 111 + as much as it can */ 112 + if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { 113 + perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); 114 + goto close_fd; 115 + } 116 + 117 + lseek(fd, 0, SEEK_SET); 118 + 119 + if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) { 120 + perror("Failed to read from /proc/sys/vm/nr_hugepages\n"); 121 + goto close_fd; 122 + } 123 + 124 + /* We should have been able to request at least 1/3 rd of the memory in 125 + huge pages */ 126 + compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size); 127 + 128 + if (compaction_index > 3) { 129 + printf("No of huge pages allocated = %d\n", 130 + (atoi(nr_hugepages))); 131 + fprintf(stderr, "ERROR: Less that 1/%d of memory is available\n" 132 + "as huge pages\n", compaction_index); 133 + goto close_fd; 134 + } 135 + 136 + printf("No of huge pages allocated = %d\n", 137 + (atoi(nr_hugepages))); 138 + 139 + if (write(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) 140 + != strlen(initial_nr_hugepages)) { 141 + perror("Failed to write to /proc/sys/vm/nr_hugepages\n"); 142 + goto close_fd; 143 + } 144 + 145 + close(fd); 146 + return 0; 147 + 148 + close_fd: 149 + close(fd); 150 + printf("Not OK. Compaction test failed."); 151 + return -1; 152 + } 153 + 154 + 155 + int main(int argc, char **argv) 156 + { 157 + struct rlimit lim; 158 + struct map_list *list, *entry; 159 + size_t page_size, i; 160 + void *map = NULL; 161 + unsigned long mem_free = 0; 162 + unsigned long hugepage_size = 0; 163 + unsigned long mem_fragmentable = 0; 164 + 165 + if (prereq() != 0) { 166 + printf("Either the sysctl compact_unevictable_allowed is not\n" 167 + "set to 1 or couldn't read the proc file.\n" 168 + "Skipping the test\n"); 169 + return 0; 170 + } 171 + 172 + lim.rlim_cur = RLIM_INFINITY; 173 + lim.rlim_max = RLIM_INFINITY; 174 + if (setrlimit(RLIMIT_MEMLOCK, &lim)) { 175 + perror("Failed to set rlimit:\n"); 176 + return -1; 177 + } 178 + 179 + page_size = getpagesize(); 180 + 181 + list = NULL; 182 + 183 + if (read_memory_info(&mem_free, &hugepage_size) != 0) { 184 + printf("ERROR: Cannot read meminfo\n"); 185 + return -1; 186 + } 187 + 188 + mem_fragmentable = mem_free * 0.8 / 1024; 189 + 190 + while (mem_fragmentable > 0) { 191 + map = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, 192 + MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0); 193 + if (map == MAP_FAILED) 194 + break; 195 + 196 + entry = malloc(sizeof(struct map_list)); 197 + if (!entry) { 198 + munmap(map, MAP_SIZE); 199 + break; 200 + } 201 + entry->map = map; 202 + entry->next = list; 203 + list = entry; 204 + 205 + /* Write something (in this case the address of the map) to 206 + * ensure that KSM can't merge the mapped pages 207 + */ 208 + for (i = 0; i < MAP_SIZE; i += page_size) 209 + *(unsigned long *)(map + i) = (unsigned long)map + i; 210 + 211 + mem_fragmentable--; 212 + } 213 + 214 + for (entry = list; entry != NULL; entry = entry->next) { 215 + munmap(entry->map, MAP_SIZE); 216 + if (!entry->next) 217 + break; 218 + entry = entry->next; 219 + } 220 + 221 + if (check_compaction(mem_free, hugepage_size) == 0) 222 + return 0; 223 + 224 + return -1; 225 + }
+12
tools/testing/selftests/vm/run_vmtests
··· 90 90 umount $mnt 91 91 rm -rf $mnt 92 92 echo $nr_hugepgs > /proc/sys/vm/nr_hugepages 93 + 94 + echo "-----------------------" 95 + echo "running compaction_test" 96 + echo "-----------------------" 97 + ./compaction_test 98 + if [ $? -ne 0 ]; then 99 + echo "[FAIL]" 100 + exitcode=1 101 + else 102 + echo "[PASS]" 103 + fi 104 + 93 105 exit $exitcode
+1 -1
tools/testing/selftests/x86/trivial_64bit_program.c
··· 1 1 /* 2 - * Trivial program to check that we have a valid 32-bit build environment. 2 + * Trivial program to check that we have a valid 64-bit build environment. 3 3 * Copyright (c) 2015 Andy Lutomirski 4 4 * GPL v2 5 5 */