Bundle libseccomp 2.3.1
[linux-seccomp.git] / libseccomp / tools / scmp_bpf_sim.c
CommitLineData
8befd5cc
MG
1/**
2 * BPF Simulator
3 *
4 * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
5 * Author: Paul Moore <paul@paul-moore.com>
6 */
7
8/*
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of version 2.1 of the GNU Lesser General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses>.
20 */
21
22#include <elf.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <inttypes.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <unistd.h>
30#include <linux/audit.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33
34#include "bpf.h"
35#include "util.h"
36
37#define BPF_PRG_MAX_LEN 4096
38
39/**
40 * BPF simulator machine state
41 */
42struct sim_state {
43 uint32_t acc;
44 uint32_t temp[BPF_SCRATCH_SIZE];
45};
46
47struct bpf_program {
48 size_t i_cnt;
49 bpf_instr_raw *i;
50};
51
52static unsigned int opt_verbose = 0;
53
54/**
55 * Print the usage information to stderr and exit
56 * @param program the name of the current program being invoked
57 *
58 * Print the usage information and exit with EINVAL.
59 *
60 */
61static void exit_usage(const char *program)
62{
63 fprintf(stderr,
64 "usage: %s -f <bpf_file> [-v] [-h]"
65 " -a <arch> -s <syscall_num> [-0 <a0>] ... [-5 <a5>]\n",
66 program);
67 exit(EINVAL);
68}
69
70/**
71 * Handle a simulator fault
72 * @param rc the error or return code
73 *
74 * Print a "FAULT" to stderr to indicate a simulator fault, and an errno value
75 * if the simulator is running in verbose mode, then exit with EFAULT.
76 *
77 */
78static void exit_fault(unsigned int rc)
79{
80 if (opt_verbose)
81 fprintf(stderr, "FAULT: errno = %d\n", rc);
82 else
83 fprintf(stderr, "FAULT\n");
84 exit(EFAULT);
85}
86
87/**
88 * Handle a BPF program error
89 * @param rc the error or return code
90 * @param line the line number
91 *
92 * Print an "ERROR" to stderr to indicate a program error, and an errno value
93 * if the simulator is running in verbose mode, then exit with ENOEXEC.
94 *
95 */
96static void exit_error(unsigned int rc, unsigned int line)
97{
98 if (opt_verbose)
99 fprintf(stderr, "ERROR: errno = %d, line = %d\n", rc, line);
100 else
101 fprintf(stderr, "ERROR\n");
102 exit(ENOEXEC);
103}
104
105/**
106 * Handle a simulator return/action
107 * @param action the return value
108 * @param line the line number
109 *
110 * Display the action to stdout and exit with 0.
111 *
112 */
113static void end_action(uint32_t action, unsigned int line)
114{
115 uint32_t act = action & SECCOMP_RET_ACTION;
116 uint32_t data = action & SECCOMP_RET_DATA;
117
118 switch (act) {
119 case SECCOMP_RET_KILL:
120 fprintf(stdout, "KILL\n");
121 break;
122 case SECCOMP_RET_TRAP:
123 fprintf(stdout, "TRAP\n");
124 break;
125 case SECCOMP_RET_ERRNO:
126 fprintf(stdout, "ERRNO(%u)\n", data);
127 break;
128 case SECCOMP_RET_TRACE:
129 fprintf(stdout, "TRACE(%u)\n", data);
130 break;
131 case SECCOMP_RET_ALLOW:
132 fprintf(stdout, "ALLOW\n");
133 break;
134 default:
135 exit_error(EDOM, line);
136 }
137
138 exit(0);
139}
140
141/**
142 * Execute a BPF program
143 * @param prg the loaded BPF program
144 * @param sys_data the syscall record being tested
145 *
146 * Simulate the BPF program with the given syscall record.
147 *
148 */
149static void bpf_execute(const struct bpf_program *prg,
150 const struct seccomp_data *sys_data)
151{
152 unsigned int ip, ip_c;
153 struct sim_state state;
154 bpf_instr_raw *bpf;
155 unsigned char *sys_data_b = (unsigned char *)sys_data;
156 uint16_t code;
157 uint8_t jt;
158 uint8_t jf;
159 uint32_t k;
160
161 /* initialize the machine state */
162 ip_c = 0;
163 ip = 0;
164 memset(&state, 0, sizeof(state));
165
166 while (ip < prg->i_cnt) {
167 /* get the instruction and bump the ip */
168 ip_c = ip;
169 bpf = &prg->i[ip++];
170
171 code = ttoh16(arch, bpf->code);
172 jt = bpf->jt;
173 jf = bpf->jf;
174 k = ttoh32(arch, bpf->k);
175
176 switch (code) {
177 case BPF_LD+BPF_W+BPF_ABS:
178 if (k < BPF_SYSCALL_MAX) {
179 uint32_t val = *((uint32_t *)&sys_data_b[k]);
180 state.acc = ttoh32(arch, val);
181 } else
182 exit_error(ERANGE, ip_c);
183 break;
184 case BPF_ALU+BPF_OR+BPF_K:
185 state.acc |= k;
186 break;
187 case BPF_ALU+BPF_AND+BPF_K:
188 state.acc &= k;
189 break;
190 case BPF_JMP+BPF_JA:
191 ip += k;
192 break;
193 case BPF_JMP+BPF_JEQ+BPF_K:
194 if (state.acc == k)
195 ip += jt;
196 else
197 ip += jf;
198 break;
199 case BPF_JMP+BPF_JGT+BPF_K:
200 if (state.acc > k)
201 ip += jt;
202 else
203 ip += jf;
204 break;
205 case BPF_JMP+BPF_JGE+BPF_K:
206 if (state.acc >= k)
207 ip += jt;
208 else
209 ip += jf;
210 break;
211 case BPF_RET+BPF_K:
212 end_action(k, ip_c);
213 break;
214 default:
215 /* since we don't support the full bpf language just
216 * yet, this could be either a fault or an error, we'll
217 * treat it as a fault until we provide full support */
218 exit_fault(EOPNOTSUPP);
219 }
220 }
221
222 /* if we've reached here there is a problem with the program */
223 exit_error(ERANGE, ip_c);
224}
225
226/**
227 * main
228 */
229int main(int argc, char *argv[])
230{
231 int opt;
232 int iter;
233 char *opt_file = NULL;
234 FILE *file;
235 size_t file_read_len;
236 struct seccomp_data sys_data;
237 struct bpf_program bpf_prg;
238
239 /* initialize the syscall record */
240 memset(&sys_data, 0, sizeof(sys_data));
241
242 /* parse the command line */
243 while ((opt = getopt(argc, argv, "a:f:hs:v0:1:2:3:4:5:")) > 0) {
244 switch (opt) {
245 case 'a':
246 if (strcmp(optarg, "x86") == 0)
247 arch = AUDIT_ARCH_I386;
248 else if (strcmp(optarg, "x86_64") == 0)
249 arch = AUDIT_ARCH_X86_64;
250 else if (strcmp(optarg, "x32") == 0)
251 arch = AUDIT_ARCH_X86_64;
252 else if (strcmp(optarg, "arm") == 0)
253 arch = AUDIT_ARCH_ARM;
254 else if (strcmp(optarg, "aarch64") == 0)
255 arch = AUDIT_ARCH_AARCH64;
256 else if (strcmp(optarg, "mips") == 0)
257 arch = AUDIT_ARCH_MIPS;
258 else if (strcmp(optarg, "mipsel") == 0)
259 arch = AUDIT_ARCH_MIPSEL;
260 else if (strcmp(optarg, "mips64") == 0)
261 arch = AUDIT_ARCH_MIPS64;
262 else if (strcmp(optarg, "mipsel64") == 0)
263 arch = AUDIT_ARCH_MIPSEL64;
264 else if (strcmp(optarg, "mips64n32") == 0)
265 arch = AUDIT_ARCH_MIPS64N32;
266 else if (strcmp(optarg, "mipsel64n32") == 0)
267 arch = AUDIT_ARCH_MIPSEL64N32;
268 else if (strcmp(optarg, "ppc") == 0)
269 arch = AUDIT_ARCH_PPC;
270 else if (strcmp(optarg, "ppc64") == 0)
271 arch = AUDIT_ARCH_PPC64;
272 else if (strcmp(optarg, "ppc64le") == 0)
273 arch = AUDIT_ARCH_PPC64LE;
274 else if (strcmp(optarg, "s390") == 0)
275 arch = AUDIT_ARCH_S390;
276 else if (strcmp(optarg, "s390x") == 0)
277 arch = AUDIT_ARCH_S390X;
278 else
279 exit_fault(EINVAL);
280 break;
281 case 'f':
282 opt_file = strdup(optarg);
283 if (opt_file == NULL)
284 exit_fault(ENOMEM);
285 break;
286 case 's':
287 sys_data.nr = strtol(optarg, NULL, 0);
288 break;
289 case 'v':
290 opt_verbose = 1;
291 break;
292 case '0':
293 sys_data.args[0] = strtoull(optarg, NULL, 0);
294 break;
295 case '1':
296 sys_data.args[1] = strtoull(optarg, NULL, 0);
297 break;
298 case '2':
299 sys_data.args[2] = strtoull(optarg, NULL, 0);
300 break;
301 case '3':
302 sys_data.args[3] = strtoull(optarg, NULL, 0);
303 break;
304 case '4':
305 sys_data.args[4] = strtoull(optarg, NULL, 0);
306 break;
307 case '5':
308 sys_data.args[5] = strtoull(optarg, NULL, 0);
309 break;
310 case 'h':
311 default:
312 /* usage information */
313 exit_usage(argv[0]);
314 }
315 }
316
317 /* adjust the endianess of sys_data to match the target */
318 sys_data.nr = htot32(arch, sys_data.nr);
319 sys_data.arch = htot32(arch, arch);
320 sys_data.instruction_pointer = htot64(arch,
321 sys_data.instruction_pointer);
322 for (iter = 0; iter < BPF_SYS_ARG_MAX; iter++)
323 sys_data.args[iter] = htot64(arch, sys_data.args[iter]);
324
325 /* allocate space for the bpf program */
326 /* XXX - we should make this dynamic */
327 bpf_prg.i_cnt = 0;
328 bpf_prg.i = calloc(BPF_PRG_MAX_LEN, sizeof(*bpf_prg.i));
329 if (bpf_prg.i == NULL)
330 exit_fault(ENOMEM);
331
332 /* load the bpf program */
333 file = fopen(opt_file, "r");
334 if (file == NULL)
335 exit_fault(errno);
336 do {
337 file_read_len = fread(&(bpf_prg.i[bpf_prg.i_cnt]),
338 sizeof(*bpf_prg.i), 1, file);
339 if (file_read_len == 1)
340 bpf_prg.i_cnt++;
341
342 /* check the size */
343 if (bpf_prg.i_cnt == BPF_PRG_MAX_LEN)
344 exit_fault(E2BIG);
345 } while (file_read_len > 0);
346 fclose(file);
347
348 /* execute the bpf program */
349 bpf_execute(&bpf_prg, &sys_data);
350
351 /* we should never reach here */
352 exit_fault(EFAULT);
353 return 0;
354}
This page took 0.028153 seconds and 4 git commands to generate.