aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-29 12:11:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-29 12:11:10 -0400
commitd93a74a91b847b8098ebae749891c6f4fe563da0 (patch)
treefb1ef1b9f496a3ad492ce076ae8f41d716964c63
parentc63f887bdae80858c7cebf914f45f69bbaa88e8d (diff)
parent2278e5ed9f36baca7c972ed17aae7467ca91b2b9 (diff)
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
-rw-r--r--MAINTAINERS1
-rw-r--r--tools/testing/selftests/Makefile8
-rw-r--r--tools/testing/selftests/exec/Makefile2
-rw-r--r--tools/testing/selftests/ftrace/Makefile1
-rw-r--r--tools/testing/selftests/futex/Makefile29
-rw-r--r--tools/testing/selftests/futex/README62
-rw-r--r--tools/testing/selftests/futex/functional/.gitignore7
-rw-r--r--tools/testing/selftests/futex/functional/Makefile25
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi.c409
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c135
-rw-r--r--tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c223
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c125
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_timeout.c86
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c124
-rw-r--r--tools/testing/selftests/futex/functional/futex_wait_wouldblock.c79
-rwxr-xr-xtools/testing/selftests/futex/functional/run.sh79
-rw-r--r--tools/testing/selftests/futex/include/atomic.h83
-rw-r--r--tools/testing/selftests/futex/include/futextest.h266
-rw-r--r--tools/testing/selftests/futex/include/logging.h153
-rwxr-xr-xtools/testing/selftests/futex/run.sh33
-rw-r--r--tools/testing/selftests/kselftest.h17
-rw-r--r--tools/testing/selftests/lib.mk3
-rw-r--r--tools/testing/selftests/mount/Makefile7
-rw-r--r--tools/testing/selftests/seccomp/.gitignore1
-rw-r--r--tools/testing/selftests/seccomp/Makefile10
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c2109
-rw-r--r--tools/testing/selftests/seccomp/test_harness.h537
-rw-r--r--tools/testing/selftests/timers/.gitignore18
-rw-r--r--tools/testing/selftests/timers/alarmtimer-suspend.c10
-rw-r--r--tools/testing/selftests/vm/Makefile7
-rw-r--r--tools/testing/selftests/vm/compaction_test.c225
-rwxr-xr-xtools/testing/selftests/vm/run_vmtests12
-rw-r--r--tools/testing/selftests/x86/trivial_64bit_program.c2
33 files changed, 4875 insertions, 13 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 329d05a1ebec..abd7a4949319 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8986,6 +8986,7 @@ S: Supported
8986F: kernel/seccomp.c 8986F: kernel/seccomp.c
8987F: include/uapi/linux/seccomp.h 8987F: include/uapi/linux/seccomp.h
8988F: include/linux/seccomp.h 8988F: include/linux/seccomp.h
8989F: tools/testing/selftests/seccomp/*
8989K: \bsecure_computing 8990K: \bsecure_computing
8990K: \bTIF_SECCOMP\b 8991K: \bTIF_SECCOMP\b
8991 8992
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 95abddcd7839..24ae9e829e9a 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -4,6 +4,7 @@ TARGETS += efivarfs
4TARGETS += exec 4TARGETS += exec
5TARGETS += firmware 5TARGETS += firmware
6TARGETS += ftrace 6TARGETS += ftrace
7TARGETS += futex
7TARGETS += kcmp 8TARGETS += kcmp
8TARGETS += memfd 9TARGETS += memfd
9TARGETS += memory-hotplug 10TARGETS += memory-hotplug
@@ -12,13 +13,18 @@ TARGETS += mqueue
12TARGETS += net 13TARGETS += net
13TARGETS += powerpc 14TARGETS += powerpc
14TARGETS += ptrace 15TARGETS += ptrace
16TARGETS += seccomp
15TARGETS += size 17TARGETS += size
16TARGETS += sysctl 18TARGETS += sysctl
19ifneq (1, $(quicktest))
17TARGETS += timers 20TARGETS += timers
21endif
18TARGETS += user 22TARGETS += user
19TARGETS += vm 23TARGETS += vm
20TARGETS += x86 24TARGETS += x86
21#Please keep the TARGETS list alphabetically sorted 25#Please keep the TARGETS list alphabetically sorted
26# Run "make quicktest=1 run_tests" or
27# "make quicktest=1 kselftest from top level Makefile
22 28
23TARGETS_HOTPLUG = cpu-hotplug 29TARGETS_HOTPLUG = cpu-hotplug
24TARGETS_HOTPLUG += memory-hotplug 30TARGETS_HOTPLUG += memory-hotplug
@@ -27,7 +33,7 @@ TARGETS_HOTPLUG += memory-hotplug
27# Makefile to avoid test build failures when test 33# Makefile to avoid test build failures when test
28# Makefile doesn't have explicit build rules. 34# Makefile doesn't have explicit build rules.
29ifeq (1,$(MAKELEVEL)) 35ifeq (1,$(MAKELEVEL))
30undefine LDFLAGS 36override LDFLAGS =
31override MAKEFLAGS = 37override MAKEFLAGS =
32endif 38endif
33 39
diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile
index 4edb7d0da29b..6b76bfdc847e 100644
--- a/tools/testing/selftests/exec/Makefile
+++ b/tools/testing/selftests/exec/Makefile
@@ -1,6 +1,6 @@
1CFLAGS = -Wall 1CFLAGS = -Wall
2BINARIES = execveat 2BINARIES = execveat
3DEPS = execveat.symlink execveat.denatured script subdir 3DEPS = execveat.symlink execveat.denatured script
4all: $(BINARIES) $(DEPS) 4all: $(BINARIES) $(DEPS)
5 5
6subdir: 6subdir:
diff --git a/tools/testing/selftests/ftrace/Makefile b/tools/testing/selftests/ftrace/Makefile
index 346720639d1d..0acbeca47225 100644
--- a/tools/testing/selftests/ftrace/Makefile
+++ b/tools/testing/selftests/ftrace/Makefile
@@ -1,6 +1,7 @@
1all: 1all:
2 2
3TEST_PROGS := ftracetest 3TEST_PROGS := ftracetest
4TEST_DIRS := test.d/
4 5
5include ../lib.mk 6include ../lib.mk
6 7
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
new file mode 100644
index 000000000000..6a1752956283
--- /dev/null
+++ b/tools/testing/selftests/futex/Makefile
@@ -0,0 +1,29 @@
1SUBDIRS := functional
2
3TEST_PROGS := run.sh
4
5.PHONY: all clean
6all:
7 for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
8
9include ../lib.mk
10
11override define RUN_TESTS
12 ./run.sh
13endef
14
15override 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;
22endef
23
24override define EMIT_TESTS
25 echo "./run.sh"
26endef
27
28clean:
29 for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README
new file mode 100644
index 000000000000..3224a049b196
--- /dev/null
+++ b/tools/testing/selftests/futex/README
@@ -0,0 +1,62 @@
1Futex Test
2==========
3Futex Test is intended to thoroughly test the Linux kernel futex system call
4API.
5
6Functional tests shall test the documented behavior of the futex operation
7code under test. This includes checking for proper behavior under normal use,
8odd corner cases, regression tests, and abject abuse and misuse.
9
10Futextest will also provide example implementation of mutual exclusion
11primitives. These can be used as is in user applications or can serve as
12examples for system libraries. These will likely be added to either a new lib/
13directory or purely as header files under include/, I'm leaning toward the
14latter.
15
16Quick Start
17-----------
18# make
19# ./run.sh
20
21Design and Implementation Goals
22-------------------------------
23o 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.
25o The build system shall remain as simple as possible, avoiding any archive or
26 shared object building and linking.
27o 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.
30o External dependendencies shall remain as minimal as possible. Currently gcc
31 and glibc are the only dependencies.
32o Tests return 0 for success and < 0 for failure.
33
34Output Formatting
35-----------------
36Test output shall be easily parsable by both human and machine. Title and
37results are printed to stdout, while intermediate ERROR or FAIL messages are
38sent to stderr. Tests shall support the -c option to print PASS, FAIL, and
39ERROR strings in color for easy visual parsing. Output shall conform to the
40following format:
41
42test_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
49Result: (PASS|FAIL|ERROR)
50
51Naming
52------
53o 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
59Coding Style
60------------
61o The Futex Test project adheres to the coding standards set forth by Linux
62 kernel as defined in the Linux source Documentation/CodingStyle.
diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
new file mode 100644
index 000000000000..a09f57061902
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/.gitignore
@@ -0,0 +1,7 @@
1futex_requeue_pi
2futex_requeue_pi_mismatched_ops
3futex_requeue_pi_signal_restart
4futex_wait_private_mapped_file
5futex_wait_timeout
6futex_wait_uninitialized_heap
7futex_wait_wouldblock
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
new file mode 100644
index 000000000000..9d6b75ef7b5d
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -0,0 +1,25 @@
1INCLUDES := -I../include -I../../
2CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES)
3LDFLAGS := $(LDFLAGS) -pthread -lrt
4
5HEADERS := ../include/futextest.h
6TARGETS := \
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
15TEST_PROGS := $(TARGETS) run.sh
16
17.PHONY: all clean
18all: $(TARGETS)
19
20$(TARGETS): $(HEADERS)
21
22include ../../lib.mk
23
24clean:
25 rm -f $(TARGETS)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
new file mode 100644
index 000000000000..3da06ad23996
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
@@ -0,0 +1,409 @@
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
39atomic_t waiters_blocked = ATOMIC_INITIALIZER;
40atomic_t waiters_woken = ATOMIC_INITIALIZER;
41
42futex_t f1 = FUTEX_INITIALIZER;
43futex_t f2 = FUTEX_INITIALIZER;
44futex_t wake_complete = FUTEX_INITIALIZER;
45
46/* Test option defaults */
47static long timeout_ns;
48static int broadcast;
49static int owner;
50static int locked;
51
52struct 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
60void 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
73int 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
111void *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
147void *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
195void *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
260void *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
281int 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
349out:
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
362int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
new file mode 100644
index 000000000000..d5e4f2c4da2a
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
@@ -0,0 +1,135 @@
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
33futex_t f1 = FUTEX_INITIALIZER;
34futex_t f2 = FUTEX_INITIALIZER;
35int child_ret = 0;
36
37void 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
46void *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
56int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
new file mode 100644
index 000000000000..7f0c756993af
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
@@ -0,0 +1,223 @@
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
37futex_t f1 = FUTEX_INITIALIZER;
38futex_t f2 = FUTEX_INITIALIZER;
39atomic_t requeued = ATOMIC_INITIALIZER;
40
41int waiter_ret = 0;
42
43void 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
52int 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
89void handle_signal(int signo)
90{
91 info("signal received %s requeue\n",
92 requeued.val ? "after" : "prior to");
93}
94
95void *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
121int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
new file mode 100644
index 000000000000..5f687f247454
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
@@ -0,0 +1,125 @@
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
39char pad[PAGE_SZ] = {1};
40futex_t val = 1;
41char pad2[PAGE_SZ] = {1};
42
43#define WAKE_WAIT_US 3000000
44struct timespec wait_timeout = { .tv_sec = 5, .tv_nsec = 0};
45
46void 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
55void *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
75int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
new file mode 100644
index 000000000000..ab428ca894de
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
@@ -0,0 +1,86 @@
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
30static long timeout_ns = 100000; /* 100us default timeout */
31
32void 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
42int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
new file mode 100644
index 000000000000..fe7aee96844b
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
@@ -0,0 +1,124 @@
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
41static int child_blocked = 1;
42static int child_ret;
43void *buf;
44
45void 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
54void *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
69int 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}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
new file mode 100644
index 000000000000..b6b027448825
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
@@ -0,0 +1,79 @@
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
33void 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
42int 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}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
new file mode 100755
index 000000000000..e87dbe2a0b0d
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -0,0 +1,79 @@
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
26if [ -z "$USE_COLOR" ]; then
27 tput setf 7
28 if [ $? -eq 0 ]; then
29 USE_COLOR=1
30 tput sgr0
31 fi
32fi
33if [ "$USE_COLOR" -eq 1 ]; then
34 COLOR="-c"
35fi
36
37
38echo
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
65echo
66./futex_requeue_pi_mismatched_ops $COLOR
67
68echo
69./futex_requeue_pi_signal_restart $COLOR
70
71echo
72./futex_wait_timeout $COLOR
73
74echo
75./futex_wait_wouldblock $COLOR
76
77echo
78./futex_wait_uninitialized_heap $COLOR
79./futex_wait_private_mapped_file $COLOR
diff --git a/tools/testing/selftests/futex/include/atomic.h b/tools/testing/selftests/futex/include/atomic.h
new file mode 100644
index 000000000000..f861da3e31ab
--- /dev/null
+++ b/tools/testing/selftests/futex/include/atomic.h
@@ -0,0 +1,83 @@
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
25typedef 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 */
39static inline int
40atomic_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 */
51static inline int
52atomic_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 */
63static inline int
64atomic_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 */
76static inline int
77atomic_set(atomic_t *addr, int newval)
78{
79 addr->val = newval;
80 return newval;
81}
82
83#endif
diff --git a/tools/testing/selftests/futex/include/futextest.h b/tools/testing/selftests/futex/include/futextest.h
new file mode 100644
index 000000000000..b98c3aba7102
--- /dev/null
+++ b/tools/testing/selftests/futex/include/futextest.h
@@ -0,0 +1,266 @@
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
29typedef 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 */
81static inline int
82futex_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 */
91static inline int
92futex_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 */
101static inline int
102futex_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 */
113static inline int
114futex_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 */
124static inline int
125futex_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 */
134static inline int
135futex_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 */
143static inline int
144futex_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 */
159static inline int
160futex_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 */
172static inline int
173futex_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 */
188static inline int
189futex_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 */
203static inline int
204futex_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 */
222static inline u_int32_t
223futex_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 */
234static inline u_int32_t
235futex_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 */
246static inline u_int32_t
247futex_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 */
259static inline u_int32_t
260futex_set(futex_t *uaddr, u_int32_t newval)
261{
262 *uaddr = newval;
263 return newval;
264}
265
266#endif
diff --git a/tools/testing/selftests/futex/include/logging.h b/tools/testing/selftests/futex/include/logging.h
new file mode 100644
index 000000000000..014aa01197af
--- /dev/null
+++ b/tools/testing/selftests/futex/include/logging.h
@@ -0,0 +1,153 @@
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'
43static const char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S',
44 RESET_COLOR, 0};
45static const char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R',
46 RESET_COLOR, 0};
47static const char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L',
48 RESET_COLOR, 0};
49static const char INFO_NORMAL[] = " INFO";
50static const char PASS_NORMAL[] = " PASS";
51static const char ERROR_NORMAL[] = "ERROR";
52static const char FAIL_NORMAL[] = " FAIL";
53const char *INFO = INFO_NORMAL;
54const char *PASS = PASS_NORMAL;
55const char *ERROR = ERROR_NORMAL;
56const 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
63int _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 */
74void 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 */
94void 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 */
109void 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...) \
131do { \
132 if (_verbose >= VINFO) \
133 fprintf(stderr, "\t%s: "message, INFO, ##vargs); \
134} while (0)
135
136#define error(message, err, args...) \
137do { \
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...) \
148do { \
149 if (_verbose >= VCRITICAL) \
150 fprintf(stderr, "\t%s: "message, FAIL, ##args); \
151} while (0)
152
153#endif
diff --git a/tools/testing/selftests/futex/run.sh b/tools/testing/selftests/futex/run.sh
new file mode 100755
index 000000000000..4126312ad64e
--- /dev/null
+++ b/tools/testing/selftests/futex/run.sh
@@ -0,0 +1,33 @@
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
25USE_COLOR=0
26tput setf 7
27if [ $? -eq 0 ]; then
28 USE_COLOR=1
29 tput sgr0
30fi
31export USE_COLOR
32
33(cd functional; ./run.sh)
diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h
index 572c8888167a..ef1c80d67ac7 100644
--- a/tools/testing/selftests/kselftest.h
+++ b/tools/testing/selftests/kselftest.h
@@ -13,6 +13,13 @@
13#include <stdlib.h> 13#include <stdlib.h>
14#include <unistd.h> 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/* counters */ 23/* counters */
17struct ksft_count { 24struct ksft_count {
18 unsigned int ksft_pass; 25 unsigned int ksft_pass;
@@ -40,23 +47,23 @@ static inline void ksft_print_cnts(void)
40 47
41static inline int ksft_exit_pass(void) 48static inline int ksft_exit_pass(void)
42{ 49{
43 exit(0); 50 exit(KSFT_PASS);
44} 51}
45static inline int ksft_exit_fail(void) 52static inline int ksft_exit_fail(void)
46{ 53{
47 exit(1); 54 exit(KSFT_FAIL);
48} 55}
49static inline int ksft_exit_xfail(void) 56static inline int ksft_exit_xfail(void)
50{ 57{
51 exit(2); 58 exit(KSFT_XFAIL);
52} 59}
53static inline int ksft_exit_xpass(void) 60static inline int ksft_exit_xpass(void)
54{ 61{
55 exit(3); 62 exit(KSFT_XPASS);
56} 63}
57static inline int ksft_exit_skip(void) 64static inline int ksft_exit_skip(void)
58{ 65{
59 exit(4); 66 exit(KSFT_SKIP);
60} 67}
61 68
62#endif /* __KSELFTEST_H */ 69#endif /* __KSELFTEST_H */
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index 2194155ae62a..ee412bab7ed4 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -13,6 +13,9 @@ run_tests: all
13 13
14define INSTALL_RULE 14define INSTALL_RULE
15 mkdir -p $(INSTALL_PATH) 15 mkdir -p $(INSTALL_PATH)
16 @for TEST_DIR in $(TEST_DIRS); do\
17 cp -r $$TEST_DIR $(INSTALL_PATH); \
18 done;
16 install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) 19 install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)
17endef 20endef
18 21
diff --git a/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile
index 95580a97326e..5e35c9c50b72 100644
--- a/tools/testing/selftests/mount/Makefile
+++ b/tools/testing/selftests/mount/Makefile
@@ -9,7 +9,12 @@ unprivileged-remount-test: unprivileged-remount-test.c
9include ../lib.mk 9include ../lib.mk
10 10
11TEST_PROGS := unprivileged-remount-test 11TEST_PROGS := unprivileged-remount-test
12override RUN_TESTS := if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi 12override 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
13override EMIT_TESTS := echo "$(RUN_TESTS)" 18override EMIT_TESTS := echo "$(RUN_TESTS)"
14 19
15clean: 20clean:
diff --git a/tools/testing/selftests/seccomp/.gitignore b/tools/testing/selftests/seccomp/.gitignore
new file mode 100644
index 000000000000..346d83ca8069
--- /dev/null
+++ b/tools/testing/selftests/seccomp/.gitignore
@@ -0,0 +1 @@
seccomp_bpf
diff --git a/tools/testing/selftests/seccomp/Makefile b/tools/testing/selftests/seccomp/Makefile
new file mode 100644
index 000000000000..8401e87e34e1
--- /dev/null
+++ b/tools/testing/selftests/seccomp/Makefile
@@ -0,0 +1,10 @@
1TEST_PROGS := seccomp_bpf
2CFLAGS += -Wl,-no-as-needed -Wall
3LDFLAGS += -lpthread
4
5all: $(TEST_PROGS)
6
7include ../lib.mk
8
9clean:
10 $(RM) $(TEST_PROGS)
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
new file mode 100644
index 000000000000..c5abe7fd7590
--- /dev/null
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -0,0 +1,2109 @@
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
77struct 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
91TEST(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
102TEST_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 */
118TEST(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. */
129TEST(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
144TEST(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
173TEST(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
210TEST(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
250TEST(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
273TEST(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
298TEST(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
316TEST(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
334TEST_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. */
356TEST_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
377TEST_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
395TEST_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
422TEST_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
455TEST_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. */
489TEST(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
509TEST(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
536TEST(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
563TEST(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
590FIXTURE_DATA(TRAP) {
591 struct sock_fprog prog;
592};
593
594FIXTURE_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
611FIXTURE_TEARDOWN(TRAP)
612{
613 if (self->prog.filter)
614 free(self->prog.filter);
615}
616
617TEST_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 */
630TEST_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
644static struct siginfo TRAP_info;
645static volatile int TRAP_nr;
646static 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
652TEST_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
701FIXTURE_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
709FIXTURE_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
756FIXTURE_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
766TEST_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
790TEST_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
817TEST_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
842TEST_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
865TEST_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
888TEST_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
908TEST_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
928TEST_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
947TEST_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)
980bool tracer_running;
981void tracer_stop(int sig)
982{
983 tracer_running = false;
984}
985
986typedef void tracer_func_t(struct __test_metadata *_metadata,
987 pid_t tracee, int status, void *args);
988
989void 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. */
1044void cont_handler(int num)
1045{ }
1046pid_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}
1073void 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. */
1090struct tracer_args_poke_t {
1091 unsigned long poke_addr;
1092};
1093
1094void 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
1116FIXTURE_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
1123FIXTURE_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
1148FIXTURE_TEARDOWN(TRACE_poke)
1149{
1150 teardown_trace_fixture(_metadata, self->tracer);
1151 if (self->prog.filter)
1152 free(self->prog.filter);
1153}
1154
1155TEST_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
1171TEST_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. */
1207int 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. */
1223void 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
1263void 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
1294FIXTURE_DATA(TRACE_syscall) {
1295 struct sock_fprog prog;
1296 pid_t tracer, mytid, mypid, parent;
1297};
1298
1299FIXTURE_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
1338FIXTURE_TEARDOWN(TRACE_syscall)
1339{
1340 teardown_trace_fixture(_metadata, self->tracer);
1341 if (self->prog.filter)
1342 free(self->prog.filter);
1343}
1344
1345TEST_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
1360TEST_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
1375TEST_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
1418int 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
1425TEST(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
1474TEST(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
1507TEST(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
1531struct 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
1543FIXTURE_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
1552FIXTURE_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
1600FIXTURE_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
1625void *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
1657void tsync_start_sibling(struct tsync_sibling *sibling)
1658{
1659 pthread_create(&sibling->tid, NULL, tsync_sibling, (void *)sibling);
1660}
1661
1662TEST_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
1711TEST_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
1750TEST_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
1776TEST_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
1813TEST_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
1855TEST_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". */
1942TEST(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
2109TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/seccomp/test_harness.h b/tools/testing/selftests/seccomp/test_harness.h
new file mode 100644
index 000000000000..977a6afc4489
--- /dev/null
+++ b/tools/testing/selftests/seccomp/test_harness.h
@@ -0,0 +1,537 @@
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. */
398struct __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. */
408static struct __test_metadata *__test_list;
409static unsigned int __test_count;
410static unsigned int __fixture_count;
411static 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 */
425static 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
448static inline int __bail(int for_realz)
449{
450 if (for_realz)
451 abort();
452 return 0;
453}
454
455void __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
507static 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
531static 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_ */
diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
new file mode 100644
index 000000000000..ced998151bc4
--- /dev/null
+++ b/tools/testing/selftests/timers/.gitignore
@@ -0,0 +1,18 @@
1alarmtimer-suspend
2change_skew
3clocksource-switch
4inconsistency-check
5leap-a-day
6leapcrash
7mqueue-lat
8nanosleep
9nsleep-lat
10posix_timers
11raw_skew
12rtctest
13set-2038
14set-tai
15set-timer-lat
16skew_consistency
17threadtest
18valid-adjtimex
diff --git a/tools/testing/selftests/timers/alarmtimer-suspend.c b/tools/testing/selftests/timers/alarmtimer-suspend.c
index aaffbde1d5ee..72cacf5383dd 100644
--- a/tools/testing/selftests/timers/alarmtimer-suspend.c
+++ b/tools/testing/selftests/timers/alarmtimer-suspend.c
@@ -57,7 +57,7 @@ static inline int ksft_exit_fail(void)
57 57
58 58
59#define NSEC_PER_SEC 1000000000ULL 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#define SUSPEND_SECS 15 62#define SUSPEND_SECS 15
63int alarmcount; 63int alarmcount;
@@ -152,7 +152,11 @@ int main(void)
152 alarm_clock_id++) { 152 alarm_clock_id++) {
153 153
154 alarmcount = 0; 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 clock_gettime(alarm_clock_id, &start_time); 161 clock_gettime(alarm_clock_id, &start_time);
158 printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id), 162 printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id),
@@ -172,7 +176,7 @@ int main(void)
172 while (alarmcount < 10) { 176 while (alarmcount < 10) {
173 int ret; 177 int ret;
174 178
175 sleep(1); 179 sleep(3);
176 ret = system("echo mem > /sys/power/state"); 180 ret = system("echo mem > /sys/power/state");
177 if (ret) 181 if (ret)
178 break; 182 break;
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index a5ce9534eb15..231b9a031f6a 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -1,7 +1,12 @@
1# Makefile for vm selftests 1# Makefile for vm selftests
2 2
3CFLAGS = -Wall 3CFLAGS = -Wall
4BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest 4BINARIES = compaction_test
5BINARIES += hugepage-mmap
6BINARIES += hugepage-shm
7BINARIES += hugetlbfstest
8BINARIES += map_hugetlb
9BINARIES += thuge-gen
5BINARIES += transhuge-stress 10BINARIES += transhuge-stress
6 11
7all: $(BINARIES) 12all: $(BINARIES)
diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c
new file mode 100644
index 000000000000..932ff577ffc0
--- /dev/null
+++ b/tools/testing/selftests/vm/compaction_test.c
@@ -0,0 +1,225 @@
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
20struct map_list {
21 void *map;
22 struct map_list *next;
23};
24
25int 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
53int 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
80int 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
155int 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}
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index c87b6812300d..49ece11ff7fd 100755
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -90,4 +90,16 @@ fi
90umount $mnt 90umount $mnt
91rm -rf $mnt 91rm -rf $mnt
92echo $nr_hugepgs > /proc/sys/vm/nr_hugepages 92echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
93
94echo "-----------------------"
95echo "running compaction_test"
96echo "-----------------------"
97./compaction_test
98if [ $? -ne 0 ]; then
99 echo "[FAIL]"
100 exitcode=1
101else
102 echo "[PASS]"
103fi
104
93exit $exitcode 105exit $exitcode
diff --git a/tools/testing/selftests/x86/trivial_64bit_program.c b/tools/testing/selftests/x86/trivial_64bit_program.c
index b994946c40fb..05c6a41b3671 100644
--- a/tools/testing/selftests/x86/trivial_64bit_program.c
+++ b/tools/testing/selftests/x86/trivial_64bit_program.c
@@ -1,5 +1,5 @@
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 * Copyright (c) 2015 Andy Lutomirski 3 * Copyright (c) 2015 Andy Lutomirski
4 * GPL v2 4 * GPL v2
5 */ 5 */