blob: ce2e0192730f7653c59c6b2eb37b90befc217ce4 [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
Jorge Lucangeli Obes8cc9d4a2016-10-03 10:00:57 -0400156class BpfLabelTest : public ::testing::Test {
157 protected:
158 virtual void TearDown() { free_label_strings(&labels_); }
159 struct bpf_labels labels_;
160};
161
162TEST_F(BpfLabelTest, zero_length_filter) {
163 int res = bpf_resolve_jumps(&labels_, NULL, 0);
164
165 EXPECT_EQ(res, 0);
166 EXPECT_EQ(labels_.count, 0U);
167}
168
169TEST_F(BpfLabelTest, single_label) {
170 struct sock_filter test_label[1];
171
172 int id = bpf_label_id(&labels_, "test");
173 set_bpf_lbl(test_label, id);
174 int res = bpf_resolve_jumps(&labels_, test_label, 1);
175
176 EXPECT_EQ(res, 0);
177 EXPECT_EQ(labels_.count, 1U);
178}
179
180TEST_F(BpfLabelTest, repeated_label) {
181 struct sock_filter test_label[2];
182
183 int id = bpf_label_id(&labels_, "test");
184 set_bpf_lbl(&test_label[0], id);
185 set_bpf_lbl(&test_label[1], id);
186 int res = bpf_resolve_jumps(&labels_, test_label, 2);
187
188 EXPECT_EQ(res, -1);
189}
190
191TEST_F(BpfLabelTest, jump_with_no_label) {
192 struct sock_filter test_jump[1];
193
194 set_bpf_jump_lbl(test_jump, 14831);
195 int res = bpf_resolve_jumps(&labels_, test_jump, 1);
196
197 EXPECT_EQ(res, -1);
198}
199
200TEST_F(BpfLabelTest, jump_to_valid_label) {
201 struct sock_filter test_jump[2];
202
203 int id = bpf_label_id(&labels_, "test");
204 set_bpf_jump_lbl(&test_jump[0], id);
205 set_bpf_lbl(&test_jump[1], id);
206
207 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
208 EXPECT_EQ(res, 0);
209 EXPECT_EQ(labels_.count, 1U);
210}
211
212TEST_F(BpfLabelTest, jump_to_invalid_label) {
213 struct sock_filter test_jump[2];
214
215 int id = bpf_label_id(&labels_, "test");
216 set_bpf_jump_lbl(&test_jump[0], id + 1);
217 set_bpf_lbl(&test_jump[1], id);
218
219 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
220 EXPECT_EQ(res, -1);
221}
222
223TEST_F(BpfLabelTest, jump_to_unresolved_label) {
224 struct sock_filter test_jump[2];
225
226 int id = bpf_label_id(&labels_, "test");
227 /* Notice the order of the instructions is reversed. */
228 set_bpf_lbl(&test_jump[0], id);
229 set_bpf_jump_lbl(&test_jump[1], id);
230
231 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
232 EXPECT_EQ(res, -1);
233}
234
235TEST_F(BpfLabelTest, too_many_labels) {
236 unsigned int i;
237 char label[20];
238
239 for (i = 0; i < BPF_LABELS_MAX; i++) {
240 snprintf(label, 20, "test%u", i);
241 (void) bpf_label_id(&labels_, label);
242 }
243 int id = bpf_label_id(&labels_, "test");
244
245 /* Insertion failed... */
246 EXPECT_EQ(id, -1);
247 /* ... because the label lookup table is full. */
248 EXPECT_EQ(labels_.count, BPF_LABELS_MAX);
249}
250
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400251class ArgFilterTest : public ::testing::Test {
252 protected:
253 virtual void TearDown() { free_label_strings(&labels_); }
254 struct bpf_labels labels_;
255};
256
257TEST_F(ArgFilterTest, arg0_equals) {
258 const char *fragment = "arg0 == 0";
259 int nr = 1;
260 unsigned int id = 0;
261 struct filter_block *block =
262 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
263
264 ASSERT_TRUE(block != NULL);
265 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
266 EXPECT_EQ(block->total_len, exp_total_len);
267
268 /* First block is a label. */
269 struct filter_block *curr_block = block;
270 ASSERT_TRUE(curr_block != NULL);
271 EXPECT_EQ(block->len, 1U);
272 EXPECT_LBL(curr_block->instrs);
273
274 /* Second block is a comparison. */
275 curr_block = block->next;
276 EXPECT_COMP(curr_block);
277
278 /* Third block is a jump and a label (end of AND group). */
279 curr_block = curr_block->next;
280 ASSERT_TRUE(curr_block != NULL);
281 EXPECT_GROUP_END(curr_block);
282
283 /* Fourth block is SECCOMP_RET_KILL. */
284 curr_block = curr_block->next;
285 ASSERT_TRUE(curr_block != NULL);
286 EXPECT_KILL(curr_block);
287
288 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
289 curr_block = curr_block->next;
290 ASSERT_TRUE(curr_block != NULL);
291 EXPECT_ALLOW(curr_block);
292
293 EXPECT_TRUE(curr_block->next == NULL);
294
295 free_block_list(block);
296}
297
298TEST_F(ArgFilterTest, arg0_mask) {
299 const char *fragment = "arg1 & O_RDWR";
300 int nr = 1;
301 unsigned int id = 0;
302 struct filter_block *block =
303 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
304
305 ASSERT_TRUE(block != NULL);
306 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
307 EXPECT_EQ(block->total_len, exp_total_len);
308
309 /* First block is a label. */
310 struct filter_block *curr_block = block;
311 ASSERT_TRUE(curr_block != NULL);
312 EXPECT_EQ(block->len, 1U);
313 EXPECT_LBL(curr_block->instrs);
314
315 /* Second block is a comparison. */
316 curr_block = block->next;
317 EXPECT_COMP(curr_block);
318
319 /* Third block is a jump and a label (end of AND group). */
320 curr_block = curr_block->next;
321 ASSERT_TRUE(curr_block != NULL);
322 EXPECT_GROUP_END(curr_block);
323
324 /* Fourth block is SECCOMP_RET_KILL. */
325 curr_block = curr_block->next;
326 ASSERT_TRUE(curr_block != NULL);
327 EXPECT_KILL(curr_block);
328
329 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
330 curr_block = curr_block->next;
331 ASSERT_TRUE(curr_block != NULL);
332 EXPECT_ALLOW(curr_block);
333
334 EXPECT_TRUE(curr_block->next == NULL);
335
336 free_block_list(block);
337}
338
339TEST_F(ArgFilterTest, arg0_eq_mask) {
340 const char *fragment = "arg1 == O_WRONLY|O_CREAT";
341 int nr = 1;
342 unsigned int id = 0;
343
344 struct filter_block *block =
345 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
346
347 ASSERT_TRUE(block != NULL);
348 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
349 EXPECT_EQ(block->total_len, exp_total_len);
350
351 /* First block is a label. */
352 struct filter_block *curr_block = block;
353 ASSERT_TRUE(curr_block != NULL);
354 EXPECT_EQ(block->len, 1U);
355 EXPECT_LBL(curr_block->instrs);
356
357 /* Second block is a comparison. */
358 curr_block = block->next;
359 ASSERT_TRUE(curr_block != NULL);
360 EXPECT_COMP(curr_block);
361 EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
362 (unsigned int)(O_WRONLY | O_CREAT));
363
364 /* Third block is a jump and a label (end of AND group). */
365 curr_block = curr_block->next;
366 ASSERT_TRUE(curr_block != NULL);
367 EXPECT_GROUP_END(curr_block);
368
369 /* Fourth block is SECCOMP_RET_KILL. */
370 curr_block = curr_block->next;
371 ASSERT_TRUE(curr_block != NULL);
372 EXPECT_KILL(curr_block);
373
374 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
375 curr_block = curr_block->next;
376 ASSERT_TRUE(curr_block != NULL);
377 EXPECT_ALLOW(curr_block);
378
379 EXPECT_TRUE(curr_block->next == NULL);
380
381 free_block_list(block);
382}
383
384TEST_F(ArgFilterTest, and_or) {
385 const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
386 int nr = 1;
387 unsigned int id = 0;
388
389 struct filter_block *block =
390 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
391 ASSERT_TRUE(block != NULL);
392 size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
393 EXPECT_EQ(block->total_len, exp_total_len);
394
395 /* First block is a label. */
396 struct filter_block *curr_block = block;
397 ASSERT_TRUE(curr_block != NULL);
398 EXPECT_EQ(block->len, 1U);
399 EXPECT_LBL(curr_block->instrs);
400
401 /* Second block is a comparison ("arg0 == 0"). */
402 curr_block = curr_block->next;
403 ASSERT_TRUE(curr_block != NULL);
404 EXPECT_COMP(curr_block);
405
406 /* Third block is a comparison ("arg1 == 0"). */
407 curr_block = curr_block->next;
408 ASSERT_TRUE(curr_block != NULL);
409 EXPECT_COMP(curr_block);
410
411 /* Fourth block is a jump and a label (end of AND group). */
412 curr_block = curr_block->next;
413 ASSERT_TRUE(curr_block != NULL);
414 EXPECT_GROUP_END(curr_block);
415
416 /* Fifth block is a comparison ("arg0 == 1"). */
417 curr_block = curr_block->next;
418 ASSERT_TRUE(curr_block != NULL);
419 EXPECT_COMP(curr_block);
420
421 /* Sixth block is a jump and a label (end of AND group). */
422 curr_block = curr_block->next;
423 ASSERT_TRUE(curr_block != NULL);
424 EXPECT_GROUP_END(curr_block);
425
426 /* Seventh block is SECCOMP_RET_KILL. */
427 curr_block = curr_block->next;
428 ASSERT_TRUE(curr_block != NULL);
429 EXPECT_KILL(curr_block);
430
431 /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
432 curr_block = curr_block->next;
433 ASSERT_TRUE(curr_block != NULL);
434 EXPECT_ALLOW(curr_block);
435
436 EXPECT_TRUE(curr_block->next == NULL);
437
438 free_block_list(block);
439}
440
441TEST_F(ArgFilterTest, ret_errno) {
442 const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
443 int nr = 1;
444 unsigned int id = 0;
445
446 struct filter_block *block =
447 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
448 ASSERT_TRUE(block != NULL);
449 size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
450 EXPECT_EQ(block->total_len, exp_total_len);
451
452 /* First block is a label. */
453 struct filter_block *curr_block = block;
454 ASSERT_TRUE(curr_block != NULL);
455 EXPECT_EQ(block->len, 1U);
456 EXPECT_LBL(curr_block->instrs);
457
458 /* Second block is a comparison ("arg0 == 0"). */
459 curr_block = curr_block->next;
460 ASSERT_TRUE(curr_block != NULL);
461 EXPECT_COMP(curr_block);
462
463 /* Third block is a jump and a label (end of AND group). */
464 curr_block = curr_block->next;
465 ASSERT_TRUE(curr_block != NULL);
466 EXPECT_GROUP_END(curr_block);
467
468 /* Fourth block is a comparison ("arg0 == 1"). */
469 curr_block = curr_block->next;
470 ASSERT_TRUE(curr_block != NULL);
471 EXPECT_COMP(curr_block);
472
473 /* Fifth block is a jump and a label (end of AND group). */
474 curr_block = curr_block->next;
475 ASSERT_TRUE(curr_block != NULL);
476 EXPECT_GROUP_END(curr_block);
477
478 /* Sixth block is SECCOMP_RET_ERRNO. */
479 curr_block = curr_block->next;
480 ASSERT_TRUE(curr_block != NULL);
481 EXPECT_EQ(curr_block->len, 1U);
482 EXPECT_EQ_STMT(curr_block->instrs,
483 BPF_RET + BPF_K,
484 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
485
486 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
487 curr_block = curr_block->next;
488 ASSERT_TRUE(curr_block != NULL);
489 EXPECT_ALLOW(curr_block);
490
491 EXPECT_TRUE(curr_block->next == NULL);
492
493 free_block_list(block);
494}
495
496TEST_F(ArgFilterTest, unconditional_errno) {
497 const char *fragment = "return 1";
498 int nr = 1;
499 unsigned int id = 0;
500
501 struct filter_block *block =
502 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
503 ASSERT_TRUE(block != NULL);
504 size_t exp_total_len = 2;
505 EXPECT_EQ(block->total_len, exp_total_len);
506
507 /* First block is a label. */
508 struct filter_block *curr_block = block;
509 ASSERT_TRUE(curr_block != NULL);
510 EXPECT_EQ(block->len, 1U);
511 EXPECT_LBL(curr_block->instrs);
512
513 /* Second block is SECCOMP_RET_ERRNO. */
514 curr_block = curr_block->next;
515 ASSERT_TRUE(curr_block != NULL);
516 EXPECT_EQ(curr_block->len, 1U);
517 EXPECT_EQ_STMT(curr_block->instrs,
518 BPF_RET + BPF_K,
519 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
520
521 EXPECT_TRUE(curr_block->next == NULL);
522
523 free_block_list(block);
524}
525
526TEST_F(ArgFilterTest, invalid) {
527 const char *fragment = "argnn == 0";
528 int nr = 1;
529 unsigned int id = 0;
530
531 struct filter_block *block =
532 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
533 ASSERT_TRUE(block == NULL);
534
535 fragment = "arg0 == 0 && arg1 == 1; return errno";
536 block = compile_section(nr, fragment, id, &labels_, NO_LOGGING);
537 ASSERT_TRUE(block == NULL);
538}
539
540TEST_F(ArgFilterTest, log_no_ret_error) {
541 const char *fragment = "arg0 == 0";
542 int nr = 1;
543 unsigned int id = 0;
544 struct filter_block *block =
545 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
546
547 ASSERT_TRUE(block != NULL);
548 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
549 EXPECT_EQ(block->total_len, exp_total_len);
550
551 /* First block is a label. */
552 struct filter_block *curr_block = block;
553 ASSERT_TRUE(curr_block != NULL);
554 EXPECT_EQ(block->len, 1U);
555 EXPECT_LBL(curr_block->instrs);
556
557 /* Second block is a comparison. */
558 curr_block = block->next;
559 ASSERT_TRUE(curr_block != NULL);
560 EXPECT_COMP(curr_block);
561
562 /* Third block is a jump and a label (end of AND group). */
563 curr_block = curr_block->next;
564 ASSERT_TRUE(curr_block != NULL);
565 EXPECT_GROUP_END(curr_block);
566
567 /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
568 curr_block = curr_block->next;
569 ASSERT_TRUE(curr_block != NULL);
570 EXPECT_TRAP(curr_block);
571
572 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
573 curr_block = curr_block->next;
574 ASSERT_TRUE(curr_block != NULL);
575 EXPECT_ALLOW(curr_block);
576
577 EXPECT_TRUE(curr_block->next == NULL);
578
579 free_block_list(block);
580}
581
582TEST_F(ArgFilterTest, log_bad_ret_error) {
583 const char *fragment = "arg0 == 0; return";
584 int nr = 1;
585 unsigned int id = 0;
586
587 struct filter_block *block =
588 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
589 ASSERT_TRUE(block != NULL);
590 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
591 EXPECT_EQ(block->total_len, exp_total_len);
592
593 /* First block is a label. */
594 struct filter_block *curr_block = block;
595 ASSERT_TRUE(curr_block != NULL);
596 EXPECT_EQ(block->len, 1U);
597 EXPECT_LBL(curr_block->instrs);
598
599 /* Second block is a comparison ("arg0 == 0"). */
600 curr_block = curr_block->next;
601 ASSERT_TRUE(curr_block != NULL);
602 EXPECT_COMP(curr_block);
603
604 /* Third block is a jump and a label (end of AND group). */
605 curr_block = curr_block->next;
606 ASSERT_TRUE(curr_block != NULL);
607 EXPECT_GROUP_END(curr_block);
608
609 /*
610 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
611 */
612 curr_block = curr_block->next;
613 ASSERT_TRUE(curr_block != NULL);
614 EXPECT_KILL(curr_block);
615
616 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
617 curr_block = curr_block->next;
618 ASSERT_TRUE(curr_block != NULL);
619 EXPECT_ALLOW(curr_block);
620
621 EXPECT_TRUE(curr_block->next == NULL);
622
623 free_block_list(block);
624}
625
626TEST_F(ArgFilterTest, no_log_bad_ret_error) {
627 const char *fragment = "arg0 == 0; return";
628 int nr = 1;
629 unsigned int id = 0;
630
631 struct filter_block *block =
632 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
633 ASSERT_TRUE(block != NULL);
634 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
635 EXPECT_EQ(block->total_len, exp_total_len);
636
637 /* First block is a label. */
638 struct filter_block *curr_block = block;
639 ASSERT_TRUE(curr_block != NULL);
640 EXPECT_EQ(block->len, 1U);
641 EXPECT_LBL(curr_block->instrs);
642
643 /* Second block is a comparison ("arg0 == 0"). */
644 curr_block = curr_block->next;
645 ASSERT_TRUE(curr_block != NULL);
646 EXPECT_COMP(curr_block);
647
648 /* Third block is a jump and a label (end of AND group). */
649 curr_block = curr_block->next;
650 ASSERT_TRUE(curr_block != NULL);
651 EXPECT_GROUP_END(curr_block);
652
653 /*
654 * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
655 * SECCOMP_RET_TRAP.
656 */
657 curr_block = curr_block->next;
658 ASSERT_TRUE(curr_block != NULL);
659 EXPECT_TRAP(curr_block);
660
661 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
662 curr_block = curr_block->next;
663 ASSERT_TRUE(curr_block != NULL);
664 EXPECT_ALLOW(curr_block);
665
666 EXPECT_TRUE(curr_block->next == NULL);
667
668 free_block_list(block);
669}
670
671FILE *write_policy_to_pipe(const char *policy, size_t len) {
672 int pipefd[2];
673 if (pipe(pipefd) == -1) {
674 pwarn("pipe(pipefd) failed");
675 return NULL;
676 }
677
678 size_t i = 0;
679 unsigned int attempts = 0;
680 ssize_t ret;
681 while (i < len) {
682 ret = write(pipefd[1], &policy[i], len - i);
683 if (ret == -1) {
684 close(pipefd[0]);
685 close(pipefd[1]);
686 return NULL;
687 }
688
689 /* If we write 0 bytes three times in a row, fail. */
690 if (ret == 0) {
691 if (++attempts >= 3) {
692 close(pipefd[0]);
693 close(pipefd[1]);
694 warn("write() returned 0 three times in a row");
695 return NULL;
696 }
697 continue;
698 }
699
700 attempts = 0;
701 i += (size_t)ret;
702 }
703
704 close(pipefd[1]);
705 return fdopen(pipefd[0], "r");
706}
707
708TEST(FilterTest, seccomp_mode1) {
709 struct sock_fprog actual;
710 const char *policy =
711 "read: 1\n"
712 "write: 1\n"
713 "rt_sigreturn: 1\n"
714 "exit: 1\n";
715
716 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
717 ASSERT_TRUE(policy_file != NULL);
718
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400719 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400720 fclose(policy_file);
721
722 /*
723 * Checks return value, filter length, and that the filter
724 * validates arch, loads syscall number, and
725 * only allows expected syscalls.
726 */
727 ASSERT_EQ(res, 0);
728 EXPECT_EQ(actual.len, 13);
729 EXPECT_ARCH_VALIDATION(actual.filter);
730 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
731 BPF_LD + BPF_W + BPF_ABS,
732 syscall_nr);
733 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
734 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
735 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
736 __NR_rt_sigreturn);
737 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
738 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
739 BPF_RET + BPF_K,
740 SECCOMP_RET_KILL);
741
742 free(actual.filter);
743}
744
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400745TEST(FilterTest, seccomp_mode1_trap) {
746 struct sock_fprog actual;
747 const char *policy =
748 "read: 1\n"
749 "write: 1\n"
750 "rt_sigreturn: 1\n"
751 "exit: 1\n";
752
753 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
754 ASSERT_TRUE(policy_file != NULL);
755
756 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
757 fclose(policy_file);
758
759 /*
760 * Checks return value, filter length, and that the filter
761 * validates arch, loads syscall number, and
762 * only allows expected syscalls.
763 */
764 ASSERT_EQ(res, 0);
765 EXPECT_EQ(actual.len, 13);
766 EXPECT_ARCH_VALIDATION(actual.filter);
767 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
768 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
769 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1,
770 __NR_read);
771 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3,
772 __NR_write);
773 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
774 __NR_rt_sigreturn);
775 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
776 __NR_exit);
777 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
778 SECCOMP_RET_TRAP);
779
780 free(actual.filter);
781}
782
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400783TEST(FilterTest, seccomp_read_write) {
784 struct sock_fprog actual;
785 const char *policy =
786 "read: arg0 == 0\n"
787 "write: arg0 == 1 || arg0 == 2\n"
788 "rt_sigreturn: 1\n"
789 "exit: 1\n";
790
791 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
792 ASSERT_TRUE(policy_file != NULL);
793
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400794 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400795 fclose(policy_file);
796
797 /*
798 * Checks return value, filter length, and that the filter
799 * validates arch, loads syscall number, and
800 * only allows expected syscalls, jumping to correct arg filter
801 * offsets.
802 */
803 ASSERT_EQ(res, 0);
804 size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
805 EXPECT_EQ(actual.len, exp_total_len);
806
807 EXPECT_ARCH_VALIDATION(actual.filter);
808 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
809 BPF_LD + BPF_W + BPF_ABS,
810 syscall_nr);
811 EXPECT_ALLOW_SYSCALL_ARGS(
812 actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
813 EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
814 __NR_write,
815 12 + BPF_ARG_COMP_LEN,
816 0,
817 0);
818 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
819 __NR_rt_sigreturn);
820 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
821 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
822 BPF_RET + BPF_K,
823 SECCOMP_RET_KILL);
824
825 free(actual.filter);
826}
827
828TEST(FilterTest, invalid_name) {
829 struct sock_fprog actual;
830 const char *policy = "notasyscall: 1\n";
831
832 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
833 ASSERT_TRUE(policy_file != NULL);
834
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400835 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400836 fclose(policy_file);
837 ASSERT_NE(res, 0);
838}
839
840TEST(FilterTest, invalid_arg) {
841 struct sock_fprog actual;
842 const char *policy = "open: argnn ==\n";
843
844 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
845 ASSERT_TRUE(policy_file != NULL);
846
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400847 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400848 fclose(policy_file);
849 ASSERT_NE(res, 0);
850}
851
852TEST(FilterTest, nonexistent) {
853 struct sock_fprog actual;
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400854 int res = compile_filter(NULL, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400855 ASSERT_NE(res, 0);
856}
857
858TEST(FilterTest, log) {
859 struct sock_fprog actual;
860 const char *policy =
861 "read: 1\n"
862 "write: 1\n"
863 "rt_sigreturn: 1\n"
864 "exit: 1\n";
865
866 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
867 ASSERT_TRUE(policy_file != NULL);
868
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400869 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400870 fclose(policy_file);
871
872 size_t i;
873 size_t index = 0;
874 /*
875 * Checks return value, filter length, and that the filter
876 * validates arch, loads syscall number, only allows expected syscalls,
877 * and returns TRAP on failure.
878 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
879 * for logging.
880 */
881 ASSERT_EQ(res, 0);
882 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
883 EXPECT_ARCH_VALIDATION(actual.filter);
884 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
885 BPF_LD + BPF_W + BPF_ABS,
886 syscall_nr);
887
888 index = ARCH_VALIDATION_LEN + 1;
889 for (i = 0; i < log_syscalls_len; i++)
890 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
891 lookup_syscall(log_syscalls[i]));
892
893 index += 2 * log_syscalls_len;
894
895 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
896 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
897 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
898 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
899 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
900
901 free(actual.filter);
902}
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400903
904TEST(FilterTest, allow_log_but_kill) {
905 struct sock_fprog actual;
906 const char *policy =
907 "read: 1\n"
908 "write: 1\n"
909 "rt_sigreturn: 1\n"
910 "exit: 1\n";
911
912 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
913 ASSERT_TRUE(policy_file != NULL);
914
915 int res = compile_filter(policy_file, &actual, USE_RET_KILL, USE_LOGGING);
916 fclose(policy_file);
917
918 size_t i;
919 size_t index = 0;
920 /*
921 * Checks return value, filter length, and that the filter
922 * validates arch, loads syscall number, only allows expected syscalls,
923 * and returns TRAP on failure.
924 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
925 * for logging.
926 */
927 ASSERT_EQ(res, 0);
928 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
929 EXPECT_ARCH_VALIDATION(actual.filter);
930 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
931 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
932
933 index = ARCH_VALIDATION_LEN + 1;
934 for (i = 0; i < log_syscalls_len; i++)
935 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
936 lookup_syscall(log_syscalls[i]));
937
938 index += 2 * log_syscalls_len;
939
940 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
941 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
942 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
943 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
944 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET+BPF_K,
945 SECCOMP_RET_KILL);
946
947 free(actual.filter);
948}