File: seccomp_syscall_test1.c

package info (click to toggle)
runc 1.3.3%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,000 kB
  • sloc: sh: 2,298; ansic: 1,125; makefile: 229
file content (79 lines) | stat: -rw-r--r-- 2,809 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>

static int exit_code = 0;

/*
 * We need raw wrappers around each syscall so that glibc won't rewrite the
 * errno value when it is returned from the seccomp filter (glibc has a habit
 * of hiding -ENOSYS if possible -- which counters what we're trying to test).
 */
#define raw(name, ...) \
	syscall(SYS_ ## name, ##__VA_ARGS__)

#define syscall_assert(sval, rval)					\
	do {								\
		int L = (sval), R = (rval);				\
		if (L < 0)						\
			L = -errno;					\
		if (L != R) {						\
			printf("syscall_assert(%s == %s) failed: %d != %d\n", #sval, #rval, L, R); \
			exit_code = 32;					\
		}							\
	} while (0)

int main(void)
{
	// Basic permitted syscalls.
	syscall_assert(write(-1, NULL, 0), -EBADF);

	// Basic syscall with masked rules.
	syscall_assert(raw(socket, AF_UNIX, SOCK_STREAM, 0x000), 3);
	syscall_assert(raw(socket, AF_UNIX, SOCK_STREAM, 0x0FF), -EPROTONOSUPPORT);
	syscall_assert(raw(socket, AF_UNIX, SOCK_STREAM, 0x001), 4);
	syscall_assert(raw(socket, AF_UNIX, SOCK_STREAM, 0x100), -EPERM);
	syscall_assert(raw(socket, AF_UNIX, SOCK_STREAM, 0xC00), -EPERM);

	// Multiple arguments with OR rules.
	syscall_assert(raw(process_vm_readv, 100, NULL, 0, NULL, 0, ~0), -EINVAL);
	syscall_assert(raw(process_vm_readv, 9001, NULL, 0, NULL, 0, ~0), -EINVAL);
	syscall_assert(raw(process_vm_readv, 0, NULL, 0, NULL, 0, ~0), -EPERM);
	syscall_assert(raw(process_vm_readv, 0, NULL, 0, NULL, 0, ~0), -EPERM);

	// Multiple arguments with OR rules -- rule is ERRNO(-ENOANO).
	syscall_assert(raw(process_vm_writev, 1337, NULL, 0, NULL, 0, ~0), -ENOANO);
	syscall_assert(raw(process_vm_writev, 2020, NULL, 0, NULL, 0, ~0), -ENOANO);
	syscall_assert(raw(process_vm_writev, 0, NULL, 0, NULL, 0, ~0), -EPERM);
	syscall_assert(raw(process_vm_writev, 0, NULL, 0, NULL, 0, ~0), -EPERM);

	// Multiple arguments with AND rules.
	syscall_assert(raw(ftruncate, 123456789, 1337), -EBADF);
	syscall_assert(raw(ftruncate, 123456789, 0), -EPERM);
	syscall_assert(raw(ftruncate, 500, 1337), -EPERM);
	syscall_assert(raw(ftruncate, 500, 500), -EPERM);

	// Multiple rules for the same syscall.
	syscall_assert(raw(dup3, 0, -100, 0xFFFF), -EPERM);
	syscall_assert(raw(dup3, 1, -100, 0xFFFF), -EINVAL);
	syscall_assert(raw(dup3, 2, -100, 0xFFFF), -EPERM);
	syscall_assert(raw(dup3, 3, -100, 0xFFFF), -EINVAL);

	// Explicitly denied syscalls (those in Linux 3.0) get -EPERM.
	syscall_assert(raw(unshare, 0), -EPERM);
	syscall_assert(raw(setns, 0, 0), -EPERM);

	// Out-of-bounds fake syscall.
	syscall_assert(syscall(1000, 0xDEADBEEF, 0xCAFEFEED, 0x1337), -ENOSYS);

	return exit_code;
}