blob: 09e98f6c48a6eadefbb7da3dee92de0750325060 [file] [log] [blame]
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -04001// syscall_filter_unittest.cpp
2// Copyright (C) 2016 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// Test syscall filtering using gtest.
17
18#include <asm/unistd.h>
19#include <errno.h>
20#include <fcntl.h> /* For O_WRONLY. */
21
22#include <gtest/gtest.h>
23
24#include "bpf.h"
25#include "syscall_filter.h"
26#include "syscall_filter_unittest_macros.h"
27#include "util.h"
28
29/* Test that setting one BPF instruction works. */
30TEST(bpf, set_bpf_instr) {
31 struct sock_filter instr;
32 unsigned char code = BPF_LD + BPF_W + BPF_ABS;
33 unsigned int k = 4;
34 unsigned char jt = 1, jf = 2;
35
36 size_t len = set_bpf_instr(&instr, code, k, jt, jf);
37
38 EXPECT_EQ(len, 1U);
39 EXPECT_EQ_BLOCK(&instr, code, k, jt, jf);
40}
41
42TEST(bpf, bpf_load_arg) {
43 struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
44 int argidx = 1;
45 size_t len = bpf_load_arg(load_arg, argidx);
46
47 EXPECT_EQ(len, BPF_LOAD_ARG_LEN);
48
49#if defined(BITS32)
50 EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
51#elif defined(BITS64)
52 EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
53 EXPECT_EQ_STMT(&load_arg[1], BPF_ST, 0);
54 EXPECT_EQ_STMT(&load_arg[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
55 EXPECT_EQ_STMT(&load_arg[3], BPF_ST, 1);
56#endif
57}
58
59TEST(bpf, bpf_comp_jeq) {
60 struct sock_filter comp_jeq[BPF_COMP_LEN];
61 unsigned long c = 1;
62 unsigned char jt = 1;
63 unsigned char jf = 2;
64
65 size_t len = bpf_comp_jeq(comp_jeq, c, jt, jf);
66
67 EXPECT_EQ(len, BPF_COMP_LEN);
68
69#if defined(BITS32)
70 EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
71#elif defined(BITS64)
72 EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, jf + 2);
73 EXPECT_EQ_STMT(&comp_jeq[1], BPF_LD + BPF_MEM, 0);
74 EXPECT_EQ_BLOCK(&comp_jeq[2], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
75#endif
76}
77
78TEST(bpf, bpf_comp_jset) {
79 struct sock_filter comp_jset[BPF_COMP_LEN];
80 unsigned long mask = O_WRONLY;
81 unsigned char jt = 1;
82 unsigned char jf = 2;
83
84 size_t len = bpf_comp_jset(comp_jset, mask, jt, jf);
85
86 EXPECT_EQ(len, BPF_COMP_LEN);
87
88#if defined(BITS32)
89 EXPECT_EQ_BLOCK(&comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, mask, jt, jf);
90#elif defined(BITS64)
91 EXPECT_EQ_BLOCK(&comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, 0, jt + 2, 0);
92 EXPECT_EQ_STMT(&comp_jset[1], BPF_LD + BPF_MEM, 0);
93 EXPECT_EQ_BLOCK(&comp_jset[2], BPF_JMP + BPF_JSET + BPF_K, mask, jt, jf);
94#endif
95}
96
97TEST(bpf, bpf_arg_comp) {
98 struct sock_filter *arg_comp;
99 int op = EQ;
100 int argidx = 1;
101 unsigned long c = 3;
102 unsigned int label_id = 0;
103
104 size_t len = bpf_arg_comp(&arg_comp, op, argidx, c, label_id);
105
106 EXPECT_EQ(len, BPF_ARG_COMP_LEN + 1);
107
108#if defined(BITS32)
109 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
110 EXPECT_EQ_BLOCK(&arg_comp[1], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
111 EXPECT_JUMP_LBL(&arg_comp[2]);
112#elif defined(BITS64)
113 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
114 EXPECT_EQ_STMT(&arg_comp[1], BPF_ST, 0);
115 EXPECT_EQ_STMT(&arg_comp[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
116 EXPECT_EQ_STMT(&arg_comp[3], BPF_ST, 1);
117
118 EXPECT_EQ_BLOCK(&arg_comp[4], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2);
119 EXPECT_EQ_STMT(&arg_comp[5], BPF_LD + BPF_MEM, 0);
120 EXPECT_EQ_BLOCK(&arg_comp[6], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
121 EXPECT_JUMP_LBL(&arg_comp[7]);
122#endif
123 free(arg_comp);
124}
125
126TEST(bpf, bpf_validate_arch) {
127 struct sock_filter validate_arch[ARCH_VALIDATION_LEN];
128
129 size_t len = bpf_validate_arch(validate_arch);
130
131 EXPECT_EQ(len, ARCH_VALIDATION_LEN);
132 EXPECT_ARCH_VALIDATION(validate_arch);
133}
134
135TEST(bpf, bpf_allow_syscall) {
136 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
137 int nr = 1;
138
139 size_t len = bpf_allow_syscall(allow_syscall, nr);
140
141 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
142 EXPECT_ALLOW_SYSCALL(allow_syscall, nr);
143}
144
145TEST(bpf, bpf_allow_syscall_args) {
146 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
147 int nr = 1;
148 unsigned int id = 1024;
149
150 size_t len = bpf_allow_syscall_args(allow_syscall, nr, id);
151
152 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
153 EXPECT_ALLOW_SYSCALL_ARGS(allow_syscall, nr, id, JUMP_JT, JUMP_JF);
154}
155
156class ArgFilterTest : public ::testing::Test {
157 protected:
158 virtual void TearDown() { free_label_strings(&labels_); }
159 struct bpf_labels labels_;
160};
161
162TEST_F(ArgFilterTest, arg0_equals) {
163 const char *fragment = "arg0 == 0";
164 int nr = 1;
165 unsigned int id = 0;
166 struct filter_block *block =
167 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
168
169 ASSERT_TRUE(block != NULL);
170 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
171 EXPECT_EQ(block->total_len, exp_total_len);
172
173 /* First block is a label. */
174 struct filter_block *curr_block = block;
175 ASSERT_TRUE(curr_block != NULL);
176 EXPECT_EQ(block->len, 1U);
177 EXPECT_LBL(curr_block->instrs);
178
179 /* Second block is a comparison. */
180 curr_block = block->next;
181 EXPECT_COMP(curr_block);
182
183 /* Third block is a jump and a label (end of AND group). */
184 curr_block = curr_block->next;
185 ASSERT_TRUE(curr_block != NULL);
186 EXPECT_GROUP_END(curr_block);
187
188 /* Fourth block is SECCOMP_RET_KILL. */
189 curr_block = curr_block->next;
190 ASSERT_TRUE(curr_block != NULL);
191 EXPECT_KILL(curr_block);
192
193 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
194 curr_block = curr_block->next;
195 ASSERT_TRUE(curr_block != NULL);
196 EXPECT_ALLOW(curr_block);
197
198 EXPECT_TRUE(curr_block->next == NULL);
199
200 free_block_list(block);
201}
202
203TEST_F(ArgFilterTest, arg0_mask) {
204 const char *fragment = "arg1 & O_RDWR";
205 int nr = 1;
206 unsigned int id = 0;
207 struct filter_block *block =
208 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
209
210 ASSERT_TRUE(block != NULL);
211 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
212 EXPECT_EQ(block->total_len, exp_total_len);
213
214 /* First block is a label. */
215 struct filter_block *curr_block = block;
216 ASSERT_TRUE(curr_block != NULL);
217 EXPECT_EQ(block->len, 1U);
218 EXPECT_LBL(curr_block->instrs);
219
220 /* Second block is a comparison. */
221 curr_block = block->next;
222 EXPECT_COMP(curr_block);
223
224 /* Third block is a jump and a label (end of AND group). */
225 curr_block = curr_block->next;
226 ASSERT_TRUE(curr_block != NULL);
227 EXPECT_GROUP_END(curr_block);
228
229 /* Fourth block is SECCOMP_RET_KILL. */
230 curr_block = curr_block->next;
231 ASSERT_TRUE(curr_block != NULL);
232 EXPECT_KILL(curr_block);
233
234 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
235 curr_block = curr_block->next;
236 ASSERT_TRUE(curr_block != NULL);
237 EXPECT_ALLOW(curr_block);
238
239 EXPECT_TRUE(curr_block->next == NULL);
240
241 free_block_list(block);
242}
243
244TEST_F(ArgFilterTest, arg0_eq_mask) {
245 const char *fragment = "arg1 == O_WRONLY|O_CREAT";
246 int nr = 1;
247 unsigned int id = 0;
248
249 struct filter_block *block =
250 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
251
252 ASSERT_TRUE(block != NULL);
253 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
254 EXPECT_EQ(block->total_len, exp_total_len);
255
256 /* First block is a label. */
257 struct filter_block *curr_block = block;
258 ASSERT_TRUE(curr_block != NULL);
259 EXPECT_EQ(block->len, 1U);
260 EXPECT_LBL(curr_block->instrs);
261
262 /* Second block is a comparison. */
263 curr_block = block->next;
264 ASSERT_TRUE(curr_block != NULL);
265 EXPECT_COMP(curr_block);
266 EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
267 (unsigned int)(O_WRONLY | O_CREAT));
268
269 /* Third block is a jump and a label (end of AND group). */
270 curr_block = curr_block->next;
271 ASSERT_TRUE(curr_block != NULL);
272 EXPECT_GROUP_END(curr_block);
273
274 /* Fourth block is SECCOMP_RET_KILL. */
275 curr_block = curr_block->next;
276 ASSERT_TRUE(curr_block != NULL);
277 EXPECT_KILL(curr_block);
278
279 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
280 curr_block = curr_block->next;
281 ASSERT_TRUE(curr_block != NULL);
282 EXPECT_ALLOW(curr_block);
283
284 EXPECT_TRUE(curr_block->next == NULL);
285
286 free_block_list(block);
287}
288
289TEST_F(ArgFilterTest, and_or) {
290 const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
291 int nr = 1;
292 unsigned int id = 0;
293
294 struct filter_block *block =
295 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
296 ASSERT_TRUE(block != NULL);
297 size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
298 EXPECT_EQ(block->total_len, exp_total_len);
299
300 /* First block is a label. */
301 struct filter_block *curr_block = block;
302 ASSERT_TRUE(curr_block != NULL);
303 EXPECT_EQ(block->len, 1U);
304 EXPECT_LBL(curr_block->instrs);
305
306 /* Second block is a comparison ("arg0 == 0"). */
307 curr_block = curr_block->next;
308 ASSERT_TRUE(curr_block != NULL);
309 EXPECT_COMP(curr_block);
310
311 /* Third block is a comparison ("arg1 == 0"). */
312 curr_block = curr_block->next;
313 ASSERT_TRUE(curr_block != NULL);
314 EXPECT_COMP(curr_block);
315
316 /* Fourth block is a jump and a label (end of AND group). */
317 curr_block = curr_block->next;
318 ASSERT_TRUE(curr_block != NULL);
319 EXPECT_GROUP_END(curr_block);
320
321 /* Fifth block is a comparison ("arg0 == 1"). */
322 curr_block = curr_block->next;
323 ASSERT_TRUE(curr_block != NULL);
324 EXPECT_COMP(curr_block);
325
326 /* Sixth block is a jump and a label (end of AND group). */
327 curr_block = curr_block->next;
328 ASSERT_TRUE(curr_block != NULL);
329 EXPECT_GROUP_END(curr_block);
330
331 /* Seventh block is SECCOMP_RET_KILL. */
332 curr_block = curr_block->next;
333 ASSERT_TRUE(curr_block != NULL);
334 EXPECT_KILL(curr_block);
335
336 /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
337 curr_block = curr_block->next;
338 ASSERT_TRUE(curr_block != NULL);
339 EXPECT_ALLOW(curr_block);
340
341 EXPECT_TRUE(curr_block->next == NULL);
342
343 free_block_list(block);
344}
345
346TEST_F(ArgFilterTest, ret_errno) {
347 const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
348 int nr = 1;
349 unsigned int id = 0;
350
351 struct filter_block *block =
352 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
353 ASSERT_TRUE(block != NULL);
354 size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
355 EXPECT_EQ(block->total_len, exp_total_len);
356
357 /* First block is a label. */
358 struct filter_block *curr_block = block;
359 ASSERT_TRUE(curr_block != NULL);
360 EXPECT_EQ(block->len, 1U);
361 EXPECT_LBL(curr_block->instrs);
362
363 /* Second block is a comparison ("arg0 == 0"). */
364 curr_block = curr_block->next;
365 ASSERT_TRUE(curr_block != NULL);
366 EXPECT_COMP(curr_block);
367
368 /* Third block is a jump and a label (end of AND group). */
369 curr_block = curr_block->next;
370 ASSERT_TRUE(curr_block != NULL);
371 EXPECT_GROUP_END(curr_block);
372
373 /* Fourth block is a comparison ("arg0 == 1"). */
374 curr_block = curr_block->next;
375 ASSERT_TRUE(curr_block != NULL);
376 EXPECT_COMP(curr_block);
377
378 /* Fifth block is a jump and a label (end of AND group). */
379 curr_block = curr_block->next;
380 ASSERT_TRUE(curr_block != NULL);
381 EXPECT_GROUP_END(curr_block);
382
383 /* Sixth block is SECCOMP_RET_ERRNO. */
384 curr_block = curr_block->next;
385 ASSERT_TRUE(curr_block != NULL);
386 EXPECT_EQ(curr_block->len, 1U);
387 EXPECT_EQ_STMT(curr_block->instrs,
388 BPF_RET + BPF_K,
389 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
390
391 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
392 curr_block = curr_block->next;
393 ASSERT_TRUE(curr_block != NULL);
394 EXPECT_ALLOW(curr_block);
395
396 EXPECT_TRUE(curr_block->next == NULL);
397
398 free_block_list(block);
399}
400
401TEST_F(ArgFilterTest, unconditional_errno) {
402 const char *fragment = "return 1";
403 int nr = 1;
404 unsigned int id = 0;
405
406 struct filter_block *block =
407 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
408 ASSERT_TRUE(block != NULL);
409 size_t exp_total_len = 2;
410 EXPECT_EQ(block->total_len, exp_total_len);
411
412 /* First block is a label. */
413 struct filter_block *curr_block = block;
414 ASSERT_TRUE(curr_block != NULL);
415 EXPECT_EQ(block->len, 1U);
416 EXPECT_LBL(curr_block->instrs);
417
418 /* Second block is SECCOMP_RET_ERRNO. */
419 curr_block = curr_block->next;
420 ASSERT_TRUE(curr_block != NULL);
421 EXPECT_EQ(curr_block->len, 1U);
422 EXPECT_EQ_STMT(curr_block->instrs,
423 BPF_RET + BPF_K,
424 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
425
426 EXPECT_TRUE(curr_block->next == NULL);
427
428 free_block_list(block);
429}
430
431TEST_F(ArgFilterTest, invalid) {
432 const char *fragment = "argnn == 0";
433 int nr = 1;
434 unsigned int id = 0;
435
436 struct filter_block *block =
437 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
438 ASSERT_TRUE(block == NULL);
439
440 fragment = "arg0 == 0 && arg1 == 1; return errno";
441 block = compile_section(nr, fragment, id, &labels_, NO_LOGGING);
442 ASSERT_TRUE(block == NULL);
443}
444
445TEST_F(ArgFilterTest, log_no_ret_error) {
446 const char *fragment = "arg0 == 0";
447 int nr = 1;
448 unsigned int id = 0;
449 struct filter_block *block =
450 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
451
452 ASSERT_TRUE(block != NULL);
453 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
454 EXPECT_EQ(block->total_len, exp_total_len);
455
456 /* First block is a label. */
457 struct filter_block *curr_block = block;
458 ASSERT_TRUE(curr_block != NULL);
459 EXPECT_EQ(block->len, 1U);
460 EXPECT_LBL(curr_block->instrs);
461
462 /* Second block is a comparison. */
463 curr_block = block->next;
464 ASSERT_TRUE(curr_block != NULL);
465 EXPECT_COMP(curr_block);
466
467 /* Third block is a jump and a label (end of AND group). */
468 curr_block = curr_block->next;
469 ASSERT_TRUE(curr_block != NULL);
470 EXPECT_GROUP_END(curr_block);
471
472 /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
473 curr_block = curr_block->next;
474 ASSERT_TRUE(curr_block != NULL);
475 EXPECT_TRAP(curr_block);
476
477 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
478 curr_block = curr_block->next;
479 ASSERT_TRUE(curr_block != NULL);
480 EXPECT_ALLOW(curr_block);
481
482 EXPECT_TRUE(curr_block->next == NULL);
483
484 free_block_list(block);
485}
486
487TEST_F(ArgFilterTest, log_bad_ret_error) {
488 const char *fragment = "arg0 == 0; return";
489 int nr = 1;
490 unsigned int id = 0;
491
492 struct filter_block *block =
493 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
494 ASSERT_TRUE(block != NULL);
495 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
496 EXPECT_EQ(block->total_len, exp_total_len);
497
498 /* First block is a label. */
499 struct filter_block *curr_block = block;
500 ASSERT_TRUE(curr_block != NULL);
501 EXPECT_EQ(block->len, 1U);
502 EXPECT_LBL(curr_block->instrs);
503
504 /* Second block is a comparison ("arg0 == 0"). */
505 curr_block = curr_block->next;
506 ASSERT_TRUE(curr_block != NULL);
507 EXPECT_COMP(curr_block);
508
509 /* Third block is a jump and a label (end of AND group). */
510 curr_block = curr_block->next;
511 ASSERT_TRUE(curr_block != NULL);
512 EXPECT_GROUP_END(curr_block);
513
514 /*
515 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
516 */
517 curr_block = curr_block->next;
518 ASSERT_TRUE(curr_block != NULL);
519 EXPECT_KILL(curr_block);
520
521 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
522 curr_block = curr_block->next;
523 ASSERT_TRUE(curr_block != NULL);
524 EXPECT_ALLOW(curr_block);
525
526 EXPECT_TRUE(curr_block->next == NULL);
527
528 free_block_list(block);
529}
530
531TEST_F(ArgFilterTest, no_log_bad_ret_error) {
532 const char *fragment = "arg0 == 0; return";
533 int nr = 1;
534 unsigned int id = 0;
535
536 struct filter_block *block =
537 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
538 ASSERT_TRUE(block != NULL);
539 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
540 EXPECT_EQ(block->total_len, exp_total_len);
541
542 /* First block is a label. */
543 struct filter_block *curr_block = block;
544 ASSERT_TRUE(curr_block != NULL);
545 EXPECT_EQ(block->len, 1U);
546 EXPECT_LBL(curr_block->instrs);
547
548 /* Second block is a comparison ("arg0 == 0"). */
549 curr_block = curr_block->next;
550 ASSERT_TRUE(curr_block != NULL);
551 EXPECT_COMP(curr_block);
552
553 /* Third block is a jump and a label (end of AND group). */
554 curr_block = curr_block->next;
555 ASSERT_TRUE(curr_block != NULL);
556 EXPECT_GROUP_END(curr_block);
557
558 /*
559 * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
560 * SECCOMP_RET_TRAP.
561 */
562 curr_block = curr_block->next;
563 ASSERT_TRUE(curr_block != NULL);
564 EXPECT_TRAP(curr_block);
565
566 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
567 curr_block = curr_block->next;
568 ASSERT_TRUE(curr_block != NULL);
569 EXPECT_ALLOW(curr_block);
570
571 EXPECT_TRUE(curr_block->next == NULL);
572
573 free_block_list(block);
574}
575
576FILE *write_policy_to_pipe(const char *policy, size_t len) {
577 int pipefd[2];
578 if (pipe(pipefd) == -1) {
579 pwarn("pipe(pipefd) failed");
580 return NULL;
581 }
582
583 size_t i = 0;
584 unsigned int attempts = 0;
585 ssize_t ret;
586 while (i < len) {
587 ret = write(pipefd[1], &policy[i], len - i);
588 if (ret == -1) {
589 close(pipefd[0]);
590 close(pipefd[1]);
591 return NULL;
592 }
593
594 /* If we write 0 bytes three times in a row, fail. */
595 if (ret == 0) {
596 if (++attempts >= 3) {
597 close(pipefd[0]);
598 close(pipefd[1]);
599 warn("write() returned 0 three times in a row");
600 return NULL;
601 }
602 continue;
603 }
604
605 attempts = 0;
606 i += (size_t)ret;
607 }
608
609 close(pipefd[1]);
610 return fdopen(pipefd[0], "r");
611}
612
613TEST(FilterTest, seccomp_mode1) {
614 struct sock_fprog actual;
615 const char *policy =
616 "read: 1\n"
617 "write: 1\n"
618 "rt_sigreturn: 1\n"
619 "exit: 1\n";
620
621 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
622 ASSERT_TRUE(policy_file != NULL);
623
624 int res = compile_filter(policy_file, &actual, NO_LOGGING);
625 fclose(policy_file);
626
627 /*
628 * Checks return value, filter length, and that the filter
629 * validates arch, loads syscall number, and
630 * only allows expected syscalls.
631 */
632 ASSERT_EQ(res, 0);
633 EXPECT_EQ(actual.len, 13);
634 EXPECT_ARCH_VALIDATION(actual.filter);
635 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
636 BPF_LD + BPF_W + BPF_ABS,
637 syscall_nr);
638 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
639 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
640 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
641 __NR_rt_sigreturn);
642 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
643 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
644 BPF_RET + BPF_K,
645 SECCOMP_RET_KILL);
646
647 free(actual.filter);
648}
649
650TEST(FilterTest, seccomp_read_write) {
651 struct sock_fprog actual;
652 const char *policy =
653 "read: arg0 == 0\n"
654 "write: arg0 == 1 || arg0 == 2\n"
655 "rt_sigreturn: 1\n"
656 "exit: 1\n";
657
658 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
659 ASSERT_TRUE(policy_file != NULL);
660
661 int res = compile_filter(policy_file, &actual, NO_LOGGING);
662 fclose(policy_file);
663
664 /*
665 * Checks return value, filter length, and that the filter
666 * validates arch, loads syscall number, and
667 * only allows expected syscalls, jumping to correct arg filter
668 * offsets.
669 */
670 ASSERT_EQ(res, 0);
671 size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
672 EXPECT_EQ(actual.len, exp_total_len);
673
674 EXPECT_ARCH_VALIDATION(actual.filter);
675 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
676 BPF_LD + BPF_W + BPF_ABS,
677 syscall_nr);
678 EXPECT_ALLOW_SYSCALL_ARGS(
679 actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
680 EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
681 __NR_write,
682 12 + BPF_ARG_COMP_LEN,
683 0,
684 0);
685 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
686 __NR_rt_sigreturn);
687 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
688 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
689 BPF_RET + BPF_K,
690 SECCOMP_RET_KILL);
691
692 free(actual.filter);
693}
694
695TEST(FilterTest, invalid_name) {
696 struct sock_fprog actual;
697 const char *policy = "notasyscall: 1\n";
698
699 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
700 ASSERT_TRUE(policy_file != NULL);
701
702 int res = compile_filter(policy_file, &actual, NO_LOGGING);
703 fclose(policy_file);
704 ASSERT_NE(res, 0);
705}
706
707TEST(FilterTest, invalid_arg) {
708 struct sock_fprog actual;
709 const char *policy = "open: argnn ==\n";
710
711 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
712 ASSERT_TRUE(policy_file != NULL);
713
714 int res = compile_filter(policy_file, &actual, NO_LOGGING);
715 fclose(policy_file);
716 ASSERT_NE(res, 0);
717}
718
719TEST(FilterTest, nonexistent) {
720 struct sock_fprog actual;
721 int res = compile_filter(NULL, &actual, NO_LOGGING);
722 ASSERT_NE(res, 0);
723}
724
725TEST(FilterTest, log) {
726 struct sock_fprog actual;
727 const char *policy =
728 "read: 1\n"
729 "write: 1\n"
730 "rt_sigreturn: 1\n"
731 "exit: 1\n";
732
733 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
734 ASSERT_TRUE(policy_file != NULL);
735
736 int res = compile_filter(policy_file, &actual, USE_LOGGING);
737 fclose(policy_file);
738
739 size_t i;
740 size_t index = 0;
741 /*
742 * Checks return value, filter length, and that the filter
743 * validates arch, loads syscall number, only allows expected syscalls,
744 * and returns TRAP on failure.
745 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
746 * for logging.
747 */
748 ASSERT_EQ(res, 0);
749 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
750 EXPECT_ARCH_VALIDATION(actual.filter);
751 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
752 BPF_LD + BPF_W + BPF_ABS,
753 syscall_nr);
754
755 index = ARCH_VALIDATION_LEN + 1;
756 for (i = 0; i < log_syscalls_len; i++)
757 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
758 lookup_syscall(log_syscalls[i]));
759
760 index += 2 * log_syscalls_len;
761
762 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
763 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
764 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
765 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
766 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
767
768 free(actual.filter);
769}