1 /* seccomp_bpf_tests.c
2  * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  *
6  * Test code for seccomp bpf.
7  */
8 
9 #include <asm/siginfo.h>
10 #define __have_siginfo_t 1
11 #define __have_sigval_t 1
12 #define __have_sigevent_t 1
13 
14 #include <linux/filter.h>
15 #include <sys/prctl.h>
16 #include <linux/prctl.h>
17 #include <linux/seccomp.h>
18 #include <stddef.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <syscall.h>
22 #define __USE_GNU 1
23 #include <sys/ucontext.h>
24 #include <sys/mman.h>
25 
26 #include "test_harness.h"
27 
28 #ifndef PR_SET_NO_NEW_PRIVS
29 #define PR_SET_NO_NEW_PRIVS 38
30 #define PR_GET_NO_NEW_PRIVS 39
31 #endif
32 
33 #if defined(__i386__)
34 #define REG_IP	REG_EIP
35 #define REG_SP	REG_ESP
36 #define REG_RESULT	REG_EAX
37 #define REG_SYSCALL	REG_EAX
38 #define REG_ARG0	REG_EBX
39 #define REG_ARG1	REG_ECX
40 #define REG_ARG2	REG_EDX
41 #define REG_ARG3	REG_ESI
42 #define REG_ARG4	REG_EDI
43 #define REG_ARG5	REG_EBP
44 #elif defined(__x86_64__)
45 #define REG_IP	REG_RIP
46 #define REG_SP	REG_RSP
47 #define REG_RESULT	REG_RAX
48 #define REG_SYSCALL	REG_RAX
49 #define REG_ARG0	REG_RDI
50 #define REG_ARG1	REG_RSI
51 #define REG_ARG2	REG_RDX
52 #define REG_ARG3	REG_R10
53 #define REG_ARG4	REG_R8
54 #define REG_ARG5	REG_R9
55 #endif
56 
FIXTURE_DATA(TRAP)57 FIXTURE_DATA(TRAP) {
58 	struct sock_fprog prog;
59 };
60 
61 /* XXX: will need one per arch, etc.
62  *      thankfully _arch can tell us the calling convention!
63  */
64 extern void *thunk_ip;	/* label for the instruction _after_ syscall */
syscall_thunk(void)65 static void syscall_thunk(void)
66 {
67 	asm("syscall; thunk_ip:");
68 }
69 
vsyscall_time(time_t * p)70 static time_t vsyscall_time(time_t *p)
71 {
72 	register time_t t asm ("rax");
73 	__attribute__((unused)) register time_t *p1 asm ("rdi") = p;
74 	__asm__("call 0xffffffffff600400 \n");
75 	return t;
76 }
77 
78 
79 #if 0
80 /* For instance, we could jump here instead. */
81 static void compat_thunk(void)
82 {
83 	asm("int 0x80");
84 }
85 #endif
86 
FIXTURE_SETUP(TRAP)87 FIXTURE_SETUP(TRAP) {
88 	/* instruction after the syscall. Will be arch specific, of course. */
89 	unsigned long thunk_addr = (unsigned long)&thunk_ip;
90 	TH_LOG("Thunk: 0x%lX\n", thunk_addr);
91 	{
92 		struct sock_filter filter[] = {
93 			BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
94 				offsetof(struct seccomp_data, nr)),
95 			/* Whitelist anything you might need in the sigaction */
96 #ifdef __NR_sigreturn
97 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 3, 0),
98 #endif
99 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 2, 0),
100 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 1, 0),
101 			/* Allow __NR_write so easy logging. */
102 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 0, 1),
103 			BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
104 			/* Check if we're within the thunk. */
105 			BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
106 				offsetof(struct seccomp_data, instruction_pointer)),
107 			/* XXX: make this 32-bit friendly. */
108 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ((__u32*)&thunk_addr)[0], 0, 3),
109 			BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
110 				offsetof(struct seccomp_data, instruction_pointer)+sizeof(int)),
111 			BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ((__u32*)&thunk_addr)[1], 0, 1),
112 			BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
113 			BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP),
114 		};
115 		memset(&self->prog, 0, sizeof(self->prog));
116 		self->prog.filter = malloc(sizeof(filter));
117 		ASSERT_NE(NULL, self->prog.filter);
118 		memcpy(self->prog.filter, filter, sizeof(filter));
119 		self->prog.len = (unsigned short)(sizeof(filter)/sizeof(filter[0]));
120 	}
121 }
122 
FIXTURE_TEARDOWN(TRAP)123 FIXTURE_TEARDOWN(TRAP) {
124 	if (self->prog.filter)
125 		free(self->prog.filter);
126 };
127 
128 struct arch_sigsys {
129 		void *_call_addr; /* calling user insn */
130 		int _syscall;	/* triggering system call number */
131 		unsigned int _arch;	/* AUDIT_ARCH_* of syscall */
132 };
133 
TRAP_action(int nr,siginfo_t * info,void * void_context)134 static void TRAP_action(int nr, siginfo_t *info, void *void_context)
135 {
136 	ucontext_t *ctx = (ucontext_t *)void_context;
137 	char buf[256];
138 	int len;
139 	int do_ret = 1;
140 	struct arch_sigsys *sys = (struct arch_sigsys *)
141 #ifdef si_syscall
142 		&(info->si_call_addr);
143 #else
144 		&(info->si_pid);
145 #endif
146 
147 	if (info->si_code != SYS_SECCOMP)
148 		return;
149 	if (!ctx)
150 		return;
151 	len = snprintf(buf, sizeof(buf),
152 			"@0x%lX:%X:%d:0x%lX:0x%lX:0x%lX:0x%lX:0x%lX:0x%lX\n",
153 			(unsigned long)sys->_call_addr,
154 			sys->_arch,
155 			sys->_syscall,
156 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG0],
157 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG1],
158 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG2],
159 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG3],
160 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG4],
161 			(unsigned long)ctx->uc_mcontext.gregs[REG_ARG5]);
162 	/* Send the soft-fail to our "listener" */
163 	syscall(__NR_write, STDOUT_FILENO, buf, len);
164 	if (ctx->uc_mcontext.gregs[REG_IP] >= 0xffffffffff600000ULL &&
165 	    ctx->uc_mcontext.gregs[REG_IP] < 0xffffffffff601000ULL)
166 		do_ret = 0;
167 	if (do_ret) {
168 		/* push [REG_IP] */
169 		ctx->uc_mcontext.gregs[REG_SP] -= sizeof(unsigned long);
170 		*((unsigned long *)ctx->uc_mcontext.gregs[REG_SP]) =
171 		    ctx->uc_mcontext.gregs[REG_IP];
172 	}
173 	/* jmp syscall_thunk */
174 	ctx->uc_mcontext.gregs[REG_IP] = (unsigned long)syscall_thunk;
175 	return;
176 }
177 
TEST_F(TRAP,handler)178 TEST_F(TRAP, handler) {
179 	int ret;
180 	struct sigaction act;
181 	pid_t pid;
182 	sigset_t mask;
183 	memset(&act, 0, sizeof(act));
184 	sigemptyset(&mask);
185 	sigaddset(&mask, SIGSYS);
186 
187 	act.sa_sigaction = &TRAP_action;
188 	act.sa_flags = SA_SIGINFO;
189 	ret = sigaction(SIGSYS, &act, NULL);
190 	ASSERT_EQ(0, ret) {
191 		TH_LOG("sigaction failed");
192 	}
193 	ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
194 	ASSERT_EQ(0, ret) {
195 		TH_LOG("sigprocmask failed");
196 	}
197 
198 	/* Get the pid to compare against. */
199 	pid = getpid();
200 
201 	ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
202 	ASSERT_EQ(0, ret);
203 	ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog);
204 	ASSERT_EQ(0, ret);
205 
206 	/* Call anything! */
207 	ret = syscall(__NR_getpid);
208 	ASSERT_EQ(pid, ret);
209 	ret = syscall(__NR_close, 0);
210 	ASSERT_EQ(0, ret);
211 	ret = syscall(__NR_close, 0);
212 	ASSERT_EQ(-1, ret);
213 	printf("The time is %ld\n", vsyscall_time(NULL));
214 	ASSERT_LT(0, vsyscall_time(NULL));
215 }
216 
217 TEST_HARNESS_MAIN
218