blob: 2445f0a81eb7fa5be34da31e20d74b53c1b5f3f1 [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];
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -040080 unsigned long mask = (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -040081 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)
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -040091 EXPECT_EQ_BLOCK(
92 &comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, 0x80000000, jt + 2, 0);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -040093 EXPECT_EQ_STMT(&comp_jset[1], BPF_LD + BPF_MEM, 0);
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -040094 EXPECT_EQ_BLOCK(&comp_jset[2], BPF_JMP + BPF_JSET + BPF_K, O_WRONLY, jt, jf);
95#endif
96}
97
98TEST(bpf, bpf_comp_jin) {
99 struct sock_filter comp_jin[BPF_COMP_LEN];
100 unsigned long mask = (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
101 unsigned char jt = 10;
102 unsigned char jf = 20;
103
104 size_t len = bpf_comp_jin(comp_jin, mask, jt, jf);
105
106 EXPECT_EQ(len, BPF_COMP_LEN);
107
108#if defined(BITS32)
109 EXPECT_EQ_BLOCK(&comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, ~mask, jf, jt);
110#elif defined(BITS64)
111 EXPECT_EQ_BLOCK(
112 &comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, 0x7FFFFFFF, jf + 2, 0);
113 EXPECT_EQ_STMT(&comp_jin[1], BPF_LD + BPF_MEM, 0);
114 EXPECT_EQ_BLOCK(&comp_jin[2], BPF_JMP + BPF_JSET + BPF_K, ~O_WRONLY, jf, jt);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400115#endif
116}
117
118TEST(bpf, bpf_arg_comp) {
119 struct sock_filter *arg_comp;
120 int op = EQ;
121 int argidx = 1;
122 unsigned long c = 3;
123 unsigned int label_id = 0;
124
125 size_t len = bpf_arg_comp(&arg_comp, op, argidx, c, label_id);
126
127 EXPECT_EQ(len, BPF_ARG_COMP_LEN + 1);
128
129#if defined(BITS32)
130 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
131 EXPECT_EQ_BLOCK(&arg_comp[1], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
132 EXPECT_JUMP_LBL(&arg_comp[2]);
133#elif defined(BITS64)
134 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
135 EXPECT_EQ_STMT(&arg_comp[1], BPF_ST, 0);
136 EXPECT_EQ_STMT(&arg_comp[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
137 EXPECT_EQ_STMT(&arg_comp[3], BPF_ST, 1);
138
139 EXPECT_EQ_BLOCK(&arg_comp[4], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2);
140 EXPECT_EQ_STMT(&arg_comp[5], BPF_LD + BPF_MEM, 0);
141 EXPECT_EQ_BLOCK(&arg_comp[6], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
142 EXPECT_JUMP_LBL(&arg_comp[7]);
143#endif
144 free(arg_comp);
145}
146
147TEST(bpf, bpf_validate_arch) {
148 struct sock_filter validate_arch[ARCH_VALIDATION_LEN];
149
150 size_t len = bpf_validate_arch(validate_arch);
151
152 EXPECT_EQ(len, ARCH_VALIDATION_LEN);
153 EXPECT_ARCH_VALIDATION(validate_arch);
154}
155
156TEST(bpf, bpf_allow_syscall) {
157 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
158 int nr = 1;
159
160 size_t len = bpf_allow_syscall(allow_syscall, nr);
161
162 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
163 EXPECT_ALLOW_SYSCALL(allow_syscall, nr);
164}
165
166TEST(bpf, bpf_allow_syscall_args) {
167 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
168 int nr = 1;
169 unsigned int id = 1024;
170
171 size_t len = bpf_allow_syscall_args(allow_syscall, nr, id);
172
173 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
174 EXPECT_ALLOW_SYSCALL_ARGS(allow_syscall, nr, id, JUMP_JT, JUMP_JF);
175}
176
Jorge Lucangeli Obes8cc9d4a2016-10-03 10:00:57 -0400177class BpfLabelTest : public ::testing::Test {
178 protected:
179 virtual void TearDown() { free_label_strings(&labels_); }
180 struct bpf_labels labels_;
181};
182
183TEST_F(BpfLabelTest, zero_length_filter) {
184 int res = bpf_resolve_jumps(&labels_, NULL, 0);
185
186 EXPECT_EQ(res, 0);
187 EXPECT_EQ(labels_.count, 0U);
188}
189
190TEST_F(BpfLabelTest, single_label) {
191 struct sock_filter test_label[1];
192
193 int id = bpf_label_id(&labels_, "test");
194 set_bpf_lbl(test_label, id);
195 int res = bpf_resolve_jumps(&labels_, test_label, 1);
196
197 EXPECT_EQ(res, 0);
198 EXPECT_EQ(labels_.count, 1U);
199}
200
201TEST_F(BpfLabelTest, repeated_label) {
202 struct sock_filter test_label[2];
203
204 int id = bpf_label_id(&labels_, "test");
205 set_bpf_lbl(&test_label[0], id);
206 set_bpf_lbl(&test_label[1], id);
207 int res = bpf_resolve_jumps(&labels_, test_label, 2);
208
209 EXPECT_EQ(res, -1);
210}
211
212TEST_F(BpfLabelTest, jump_with_no_label) {
213 struct sock_filter test_jump[1];
214
215 set_bpf_jump_lbl(test_jump, 14831);
216 int res = bpf_resolve_jumps(&labels_, test_jump, 1);
217
218 EXPECT_EQ(res, -1);
219}
220
221TEST_F(BpfLabelTest, jump_to_valid_label) {
222 struct sock_filter test_jump[2];
223
224 int id = bpf_label_id(&labels_, "test");
225 set_bpf_jump_lbl(&test_jump[0], id);
226 set_bpf_lbl(&test_jump[1], id);
227
228 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
229 EXPECT_EQ(res, 0);
230 EXPECT_EQ(labels_.count, 1U);
231}
232
233TEST_F(BpfLabelTest, jump_to_invalid_label) {
234 struct sock_filter test_jump[2];
235
236 int id = bpf_label_id(&labels_, "test");
237 set_bpf_jump_lbl(&test_jump[0], id + 1);
238 set_bpf_lbl(&test_jump[1], id);
239
240 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
241 EXPECT_EQ(res, -1);
242}
243
244TEST_F(BpfLabelTest, jump_to_unresolved_label) {
245 struct sock_filter test_jump[2];
246
247 int id = bpf_label_id(&labels_, "test");
248 /* Notice the order of the instructions is reversed. */
249 set_bpf_lbl(&test_jump[0], id);
250 set_bpf_jump_lbl(&test_jump[1], id);
251
252 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
253 EXPECT_EQ(res, -1);
254}
255
256TEST_F(BpfLabelTest, too_many_labels) {
257 unsigned int i;
258 char label[20];
259
260 for (i = 0; i < BPF_LABELS_MAX; i++) {
261 snprintf(label, 20, "test%u", i);
262 (void) bpf_label_id(&labels_, label);
263 }
264 int id = bpf_label_id(&labels_, "test");
265
266 /* Insertion failed... */
267 EXPECT_EQ(id, -1);
268 /* ... because the label lookup table is full. */
269 EXPECT_EQ(labels_.count, BPF_LABELS_MAX);
270}
271
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400272class ArgFilterTest : public ::testing::Test {
273 protected:
274 virtual void TearDown() { free_label_strings(&labels_); }
275 struct bpf_labels labels_;
276};
277
278TEST_F(ArgFilterTest, arg0_equals) {
279 const char *fragment = "arg0 == 0";
280 int nr = 1;
281 unsigned int id = 0;
282 struct filter_block *block =
283 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
284
285 ASSERT_TRUE(block != NULL);
286 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
287 EXPECT_EQ(block->total_len, exp_total_len);
288
289 /* First block is a label. */
290 struct filter_block *curr_block = block;
291 ASSERT_TRUE(curr_block != NULL);
292 EXPECT_EQ(block->len, 1U);
293 EXPECT_LBL(curr_block->instrs);
294
295 /* Second block is a comparison. */
296 curr_block = block->next;
297 EXPECT_COMP(curr_block);
298
299 /* Third block is a jump and a label (end of AND group). */
300 curr_block = curr_block->next;
301 ASSERT_TRUE(curr_block != NULL);
302 EXPECT_GROUP_END(curr_block);
303
304 /* Fourth block is SECCOMP_RET_KILL. */
305 curr_block = curr_block->next;
306 ASSERT_TRUE(curr_block != NULL);
307 EXPECT_KILL(curr_block);
308
309 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
310 curr_block = curr_block->next;
311 ASSERT_TRUE(curr_block != NULL);
312 EXPECT_ALLOW(curr_block);
313
314 EXPECT_TRUE(curr_block->next == NULL);
315
316 free_block_list(block);
317}
318
319TEST_F(ArgFilterTest, arg0_mask) {
320 const char *fragment = "arg1 & O_RDWR";
321 int nr = 1;
322 unsigned int id = 0;
323 struct filter_block *block =
324 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
325
326 ASSERT_TRUE(block != NULL);
327 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
328 EXPECT_EQ(block->total_len, exp_total_len);
329
330 /* First block is a label. */
331 struct filter_block *curr_block = block;
332 ASSERT_TRUE(curr_block != NULL);
333 EXPECT_EQ(block->len, 1U);
334 EXPECT_LBL(curr_block->instrs);
335
336 /* Second block is a comparison. */
337 curr_block = block->next;
338 EXPECT_COMP(curr_block);
339
340 /* Third block is a jump and a label (end of AND group). */
341 curr_block = curr_block->next;
342 ASSERT_TRUE(curr_block != NULL);
343 EXPECT_GROUP_END(curr_block);
344
345 /* Fourth block is SECCOMP_RET_KILL. */
346 curr_block = curr_block->next;
347 ASSERT_TRUE(curr_block != NULL);
348 EXPECT_KILL(curr_block);
349
350 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
351 curr_block = curr_block->next;
352 ASSERT_TRUE(curr_block != NULL);
353 EXPECT_ALLOW(curr_block);
354
355 EXPECT_TRUE(curr_block->next == NULL);
356
357 free_block_list(block);
358}
359
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400360TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
361 const char *fragment = "arg0 in O_RDONLY|O_CREAT";
362 int nr = 1;
363 unsigned int id = 0;
364 struct filter_block *block =
365 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
366
367 ASSERT_NE(block, nullptr);
368 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
369 EXPECT_EQ(block->total_len, exp_total_len);
370
371 /* First block is a label. */
372 struct filter_block *curr_block = block;
373 ASSERT_NE(curr_block, nullptr);
374 EXPECT_EQ(block->len, 1U);
375 EXPECT_LBL(curr_block->instrs);
376
377 /* Second block is a comparison. */
378 curr_block = block->next;
379 ASSERT_NE(curr_block, nullptr);
380 EXPECT_COMP(curr_block);
381
382 /* Third block is a jump and a label (end of AND group). */
383 curr_block = curr_block->next;
384 ASSERT_NE(curr_block, nullptr);
385 EXPECT_GROUP_END(curr_block);
386
387 /* Fourth block is SECCOMP_RET_KILL. */
388 curr_block = curr_block->next;
389 ASSERT_NE(curr_block, nullptr);
390 EXPECT_KILL(curr_block);
391
392 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
393 curr_block = curr_block->next;
394 ASSERT_NE(curr_block, nullptr);
395 EXPECT_ALLOW(curr_block);
396
397 EXPECT_EQ(curr_block->next, nullptr);
398
399 free_block_list(block);
400}
401
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400402TEST_F(ArgFilterTest, arg0_eq_mask) {
403 const char *fragment = "arg1 == O_WRONLY|O_CREAT";
404 int nr = 1;
405 unsigned int id = 0;
406
407 struct filter_block *block =
408 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
409
410 ASSERT_TRUE(block != NULL);
411 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
412 EXPECT_EQ(block->total_len, exp_total_len);
413
414 /* First block is a label. */
415 struct filter_block *curr_block = block;
416 ASSERT_TRUE(curr_block != NULL);
417 EXPECT_EQ(block->len, 1U);
418 EXPECT_LBL(curr_block->instrs);
419
420 /* Second block is a comparison. */
421 curr_block = block->next;
422 ASSERT_TRUE(curr_block != NULL);
423 EXPECT_COMP(curr_block);
424 EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
425 (unsigned int)(O_WRONLY | O_CREAT));
426
427 /* Third block is a jump and a label (end of AND group). */
428 curr_block = curr_block->next;
429 ASSERT_TRUE(curr_block != NULL);
430 EXPECT_GROUP_END(curr_block);
431
432 /* Fourth block is SECCOMP_RET_KILL. */
433 curr_block = curr_block->next;
434 ASSERT_TRUE(curr_block != NULL);
435 EXPECT_KILL(curr_block);
436
437 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
438 curr_block = curr_block->next;
439 ASSERT_TRUE(curr_block != NULL);
440 EXPECT_ALLOW(curr_block);
441
442 EXPECT_TRUE(curr_block->next == NULL);
443
444 free_block_list(block);
445}
446
447TEST_F(ArgFilterTest, and_or) {
448 const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
449 int nr = 1;
450 unsigned int id = 0;
451
452 struct filter_block *block =
453 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
454 ASSERT_TRUE(block != NULL);
455 size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
456 EXPECT_EQ(block->total_len, exp_total_len);
457
458 /* First block is a label. */
459 struct filter_block *curr_block = block;
460 ASSERT_TRUE(curr_block != NULL);
461 EXPECT_EQ(block->len, 1U);
462 EXPECT_LBL(curr_block->instrs);
463
464 /* Second block is a comparison ("arg0 == 0"). */
465 curr_block = curr_block->next;
466 ASSERT_TRUE(curr_block != NULL);
467 EXPECT_COMP(curr_block);
468
469 /* Third block is a comparison ("arg1 == 0"). */
470 curr_block = curr_block->next;
471 ASSERT_TRUE(curr_block != NULL);
472 EXPECT_COMP(curr_block);
473
474 /* Fourth block is a jump and a label (end of AND group). */
475 curr_block = curr_block->next;
476 ASSERT_TRUE(curr_block != NULL);
477 EXPECT_GROUP_END(curr_block);
478
479 /* Fifth block is a comparison ("arg0 == 1"). */
480 curr_block = curr_block->next;
481 ASSERT_TRUE(curr_block != NULL);
482 EXPECT_COMP(curr_block);
483
484 /* Sixth block is a jump and a label (end of AND group). */
485 curr_block = curr_block->next;
486 ASSERT_TRUE(curr_block != NULL);
487 EXPECT_GROUP_END(curr_block);
488
489 /* Seventh block is SECCOMP_RET_KILL. */
490 curr_block = curr_block->next;
491 ASSERT_TRUE(curr_block != NULL);
492 EXPECT_KILL(curr_block);
493
494 /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
495 curr_block = curr_block->next;
496 ASSERT_TRUE(curr_block != NULL);
497 EXPECT_ALLOW(curr_block);
498
499 EXPECT_TRUE(curr_block->next == NULL);
500
501 free_block_list(block);
502}
503
504TEST_F(ArgFilterTest, ret_errno) {
505 const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
506 int nr = 1;
507 unsigned int id = 0;
508
509 struct filter_block *block =
510 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
511 ASSERT_TRUE(block != NULL);
512 size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
513 EXPECT_EQ(block->total_len, exp_total_len);
514
515 /* First block is a label. */
516 struct filter_block *curr_block = block;
517 ASSERT_TRUE(curr_block != NULL);
518 EXPECT_EQ(block->len, 1U);
519 EXPECT_LBL(curr_block->instrs);
520
521 /* Second block is a comparison ("arg0 == 0"). */
522 curr_block = curr_block->next;
523 ASSERT_TRUE(curr_block != NULL);
524 EXPECT_COMP(curr_block);
525
526 /* Third block is a jump and a label (end of AND group). */
527 curr_block = curr_block->next;
528 ASSERT_TRUE(curr_block != NULL);
529 EXPECT_GROUP_END(curr_block);
530
531 /* Fourth block is a comparison ("arg0 == 1"). */
532 curr_block = curr_block->next;
533 ASSERT_TRUE(curr_block != NULL);
534 EXPECT_COMP(curr_block);
535
536 /* Fifth block is a jump and a label (end of AND group). */
537 curr_block = curr_block->next;
538 ASSERT_TRUE(curr_block != NULL);
539 EXPECT_GROUP_END(curr_block);
540
541 /* Sixth block is SECCOMP_RET_ERRNO. */
542 curr_block = curr_block->next;
543 ASSERT_TRUE(curr_block != NULL);
544 EXPECT_EQ(curr_block->len, 1U);
545 EXPECT_EQ_STMT(curr_block->instrs,
546 BPF_RET + BPF_K,
547 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
548
549 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
550 curr_block = curr_block->next;
551 ASSERT_TRUE(curr_block != NULL);
552 EXPECT_ALLOW(curr_block);
553
554 EXPECT_TRUE(curr_block->next == NULL);
555
556 free_block_list(block);
557}
558
559TEST_F(ArgFilterTest, unconditional_errno) {
560 const char *fragment = "return 1";
561 int nr = 1;
562 unsigned int id = 0;
563
564 struct filter_block *block =
565 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
566 ASSERT_TRUE(block != NULL);
567 size_t exp_total_len = 2;
568 EXPECT_EQ(block->total_len, exp_total_len);
569
570 /* First block is a label. */
571 struct filter_block *curr_block = block;
572 ASSERT_TRUE(curr_block != NULL);
573 EXPECT_EQ(block->len, 1U);
574 EXPECT_LBL(curr_block->instrs);
575
576 /* Second block is SECCOMP_RET_ERRNO. */
577 curr_block = curr_block->next;
578 ASSERT_TRUE(curr_block != NULL);
579 EXPECT_EQ(curr_block->len, 1U);
580 EXPECT_EQ_STMT(curr_block->instrs,
581 BPF_RET + BPF_K,
582 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
583
584 EXPECT_TRUE(curr_block->next == NULL);
585
586 free_block_list(block);
587}
588
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400589TEST_F(ArgFilterTest, invalid_arg_number) {
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400590 const char *fragment = "argnn == 0";
591 int nr = 1;
592 unsigned int id = 0;
593
594 struct filter_block *block =
595 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400596 ASSERT_EQ(block, nullptr);
597}
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400598
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400599TEST_F(ArgFilterTest, invalid_constant) {
600 const char *fragment = "arg0 == INVALIDCONSTANT";
601 int nr = 1;
602 unsigned int id = 0;
603
604 struct filter_block* block =
605 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
606 ASSERT_EQ(block, nullptr);
607}
608
609TEST_F(ArgFilterTest, invalid_errno) {
610 const char *fragment = "arg0 == 0 && arg1 == 1; return errno";
611 int nr = 1;
612 unsigned int id = 0;
613
614 struct filter_block *block =
615 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
616 ASSERT_EQ(block, nullptr);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400617}
618
619TEST_F(ArgFilterTest, log_no_ret_error) {
620 const char *fragment = "arg0 == 0";
621 int nr = 1;
622 unsigned int id = 0;
623 struct filter_block *block =
624 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
625
626 ASSERT_TRUE(block != NULL);
627 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
628 EXPECT_EQ(block->total_len, exp_total_len);
629
630 /* First block is a label. */
631 struct filter_block *curr_block = block;
632 ASSERT_TRUE(curr_block != NULL);
633 EXPECT_EQ(block->len, 1U);
634 EXPECT_LBL(curr_block->instrs);
635
636 /* Second block is a comparison. */
637 curr_block = block->next;
638 ASSERT_TRUE(curr_block != NULL);
639 EXPECT_COMP(curr_block);
640
641 /* Third block is a jump and a label (end of AND group). */
642 curr_block = curr_block->next;
643 ASSERT_TRUE(curr_block != NULL);
644 EXPECT_GROUP_END(curr_block);
645
646 /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
647 curr_block = curr_block->next;
648 ASSERT_TRUE(curr_block != NULL);
649 EXPECT_TRAP(curr_block);
650
651 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
652 curr_block = curr_block->next;
653 ASSERT_TRUE(curr_block != NULL);
654 EXPECT_ALLOW(curr_block);
655
656 EXPECT_TRUE(curr_block->next == NULL);
657
658 free_block_list(block);
659}
660
661TEST_F(ArgFilterTest, log_bad_ret_error) {
662 const char *fragment = "arg0 == 0; return";
663 int nr = 1;
664 unsigned int id = 0;
665
666 struct filter_block *block =
667 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
668 ASSERT_TRUE(block != NULL);
669 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
670 EXPECT_EQ(block->total_len, exp_total_len);
671
672 /* First block is a label. */
673 struct filter_block *curr_block = block;
674 ASSERT_TRUE(curr_block != NULL);
675 EXPECT_EQ(block->len, 1U);
676 EXPECT_LBL(curr_block->instrs);
677
678 /* Second block is a comparison ("arg0 == 0"). */
679 curr_block = curr_block->next;
680 ASSERT_TRUE(curr_block != NULL);
681 EXPECT_COMP(curr_block);
682
683 /* Third block is a jump and a label (end of AND group). */
684 curr_block = curr_block->next;
685 ASSERT_TRUE(curr_block != NULL);
686 EXPECT_GROUP_END(curr_block);
687
688 /*
689 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
690 */
691 curr_block = curr_block->next;
692 ASSERT_TRUE(curr_block != NULL);
693 EXPECT_KILL(curr_block);
694
695 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
696 curr_block = curr_block->next;
697 ASSERT_TRUE(curr_block != NULL);
698 EXPECT_ALLOW(curr_block);
699
700 EXPECT_TRUE(curr_block->next == NULL);
701
702 free_block_list(block);
703}
704
705TEST_F(ArgFilterTest, no_log_bad_ret_error) {
706 const char *fragment = "arg0 == 0; return";
707 int nr = 1;
708 unsigned int id = 0;
709
710 struct filter_block *block =
711 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
712 ASSERT_TRUE(block != NULL);
713 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
714 EXPECT_EQ(block->total_len, exp_total_len);
715
716 /* First block is a label. */
717 struct filter_block *curr_block = block;
718 ASSERT_TRUE(curr_block != NULL);
719 EXPECT_EQ(block->len, 1U);
720 EXPECT_LBL(curr_block->instrs);
721
722 /* Second block is a comparison ("arg0 == 0"). */
723 curr_block = curr_block->next;
724 ASSERT_TRUE(curr_block != NULL);
725 EXPECT_COMP(curr_block);
726
727 /* Third block is a jump and a label (end of AND group). */
728 curr_block = curr_block->next;
729 ASSERT_TRUE(curr_block != NULL);
730 EXPECT_GROUP_END(curr_block);
731
732 /*
733 * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
734 * SECCOMP_RET_TRAP.
735 */
736 curr_block = curr_block->next;
737 ASSERT_TRUE(curr_block != NULL);
738 EXPECT_TRAP(curr_block);
739
740 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
741 curr_block = curr_block->next;
742 ASSERT_TRUE(curr_block != NULL);
743 EXPECT_ALLOW(curr_block);
744
745 EXPECT_TRUE(curr_block->next == NULL);
746
747 free_block_list(block);
748}
749
750FILE *write_policy_to_pipe(const char *policy, size_t len) {
751 int pipefd[2];
752 if (pipe(pipefd) == -1) {
753 pwarn("pipe(pipefd) failed");
754 return NULL;
755 }
756
757 size_t i = 0;
758 unsigned int attempts = 0;
759 ssize_t ret;
760 while (i < len) {
761 ret = write(pipefd[1], &policy[i], len - i);
762 if (ret == -1) {
763 close(pipefd[0]);
764 close(pipefd[1]);
765 return NULL;
766 }
767
768 /* If we write 0 bytes three times in a row, fail. */
769 if (ret == 0) {
770 if (++attempts >= 3) {
771 close(pipefd[0]);
772 close(pipefd[1]);
773 warn("write() returned 0 three times in a row");
774 return NULL;
775 }
776 continue;
777 }
778
779 attempts = 0;
780 i += (size_t)ret;
781 }
782
783 close(pipefd[1]);
784 return fdopen(pipefd[0], "r");
785}
786
787TEST(FilterTest, seccomp_mode1) {
788 struct sock_fprog actual;
789 const char *policy =
790 "read: 1\n"
791 "write: 1\n"
792 "rt_sigreturn: 1\n"
793 "exit: 1\n";
794
795 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
796 ASSERT_TRUE(policy_file != NULL);
797
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400798 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400799 fclose(policy_file);
800
801 /*
802 * Checks return value, filter length, and that the filter
803 * validates arch, loads syscall number, and
804 * only allows expected syscalls.
805 */
806 ASSERT_EQ(res, 0);
807 EXPECT_EQ(actual.len, 13);
808 EXPECT_ARCH_VALIDATION(actual.filter);
809 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
810 BPF_LD + BPF_W + BPF_ABS,
811 syscall_nr);
812 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
813 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
814 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
815 __NR_rt_sigreturn);
816 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
817 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
818 BPF_RET + BPF_K,
819 SECCOMP_RET_KILL);
820
821 free(actual.filter);
822}
823
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400824TEST(FilterTest, seccomp_mode1_trap) {
825 struct sock_fprog actual;
826 const char *policy =
827 "read: 1\n"
828 "write: 1\n"
829 "rt_sigreturn: 1\n"
830 "exit: 1\n";
831
832 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
833 ASSERT_TRUE(policy_file != NULL);
834
835 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
836 fclose(policy_file);
837
838 /*
839 * Checks return value, filter length, and that the filter
840 * validates arch, loads syscall number, and
841 * only allows expected syscalls.
842 */
843 ASSERT_EQ(res, 0);
844 EXPECT_EQ(actual.len, 13);
845 EXPECT_ARCH_VALIDATION(actual.filter);
846 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
847 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
848 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1,
849 __NR_read);
850 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3,
851 __NR_write);
852 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
853 __NR_rt_sigreturn);
854 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
855 __NR_exit);
856 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
857 SECCOMP_RET_TRAP);
858
859 free(actual.filter);
860}
861
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400862TEST(FilterTest, seccomp_read_write) {
863 struct sock_fprog actual;
864 const char *policy =
865 "read: arg0 == 0\n"
866 "write: arg0 == 1 || arg0 == 2\n"
867 "rt_sigreturn: 1\n"
868 "exit: 1\n";
869
870 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
871 ASSERT_TRUE(policy_file != NULL);
872
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400873 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400874 fclose(policy_file);
875
876 /*
877 * Checks return value, filter length, and that the filter
878 * validates arch, loads syscall number, and
879 * only allows expected syscalls, jumping to correct arg filter
880 * offsets.
881 */
882 ASSERT_EQ(res, 0);
883 size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
884 EXPECT_EQ(actual.len, exp_total_len);
885
886 EXPECT_ARCH_VALIDATION(actual.filter);
887 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
888 BPF_LD + BPF_W + BPF_ABS,
889 syscall_nr);
890 EXPECT_ALLOW_SYSCALL_ARGS(
891 actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
892 EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
893 __NR_write,
894 12 + BPF_ARG_COMP_LEN,
895 0,
896 0);
897 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
898 __NR_rt_sigreturn);
899 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
900 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
901 BPF_RET + BPF_K,
902 SECCOMP_RET_KILL);
903
904 free(actual.filter);
905}
906
907TEST(FilterTest, invalid_name) {
908 struct sock_fprog actual;
909 const char *policy = "notasyscall: 1\n";
910
911 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
912 ASSERT_TRUE(policy_file != NULL);
913
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400914 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400915 fclose(policy_file);
916 ASSERT_NE(res, 0);
917}
918
919TEST(FilterTest, invalid_arg) {
920 struct sock_fprog actual;
921 const char *policy = "open: argnn ==\n";
922
923 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
924 ASSERT_TRUE(policy_file != NULL);
925
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400926 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400927 fclose(policy_file);
928 ASSERT_NE(res, 0);
929}
930
931TEST(FilterTest, nonexistent) {
932 struct sock_fprog actual;
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400933 int res = compile_filter(NULL, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400934 ASSERT_NE(res, 0);
935}
936
937TEST(FilterTest, log) {
938 struct sock_fprog actual;
939 const char *policy =
940 "read: 1\n"
941 "write: 1\n"
942 "rt_sigreturn: 1\n"
943 "exit: 1\n";
944
945 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
946 ASSERT_TRUE(policy_file != NULL);
947
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400948 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400949 fclose(policy_file);
950
951 size_t i;
952 size_t index = 0;
953 /*
954 * Checks return value, filter length, and that the filter
955 * validates arch, loads syscall number, only allows expected syscalls,
956 * and returns TRAP on failure.
957 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
958 * for logging.
959 */
960 ASSERT_EQ(res, 0);
961 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
962 EXPECT_ARCH_VALIDATION(actual.filter);
963 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
964 BPF_LD + BPF_W + BPF_ABS,
965 syscall_nr);
966
967 index = ARCH_VALIDATION_LEN + 1;
968 for (i = 0; i < log_syscalls_len; i++)
969 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
970 lookup_syscall(log_syscalls[i]));
971
972 index += 2 * log_syscalls_len;
973
974 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
975 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
976 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
977 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
978 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
979
980 free(actual.filter);
981}
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400982
983TEST(FilterTest, allow_log_but_kill) {
984 struct sock_fprog actual;
985 const char *policy =
986 "read: 1\n"
987 "write: 1\n"
988 "rt_sigreturn: 1\n"
989 "exit: 1\n";
990
991 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
992 ASSERT_TRUE(policy_file != NULL);
993
994 int res = compile_filter(policy_file, &actual, USE_RET_KILL, USE_LOGGING);
995 fclose(policy_file);
996
997 size_t i;
998 size_t index = 0;
999 /*
1000 * Checks return value, filter length, and that the filter
1001 * validates arch, loads syscall number, only allows expected syscalls,
1002 * and returns TRAP on failure.
1003 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
1004 * for logging.
1005 */
1006 ASSERT_EQ(res, 0);
1007 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
1008 EXPECT_ARCH_VALIDATION(actual.filter);
1009 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1010 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
1011
1012 index = ARCH_VALIDATION_LEN + 1;
1013 for (i = 0; i < log_syscalls_len; i++)
1014 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
1015 lookup_syscall(log_syscalls[i]));
1016
1017 index += 2 * log_syscalls_len;
1018
1019 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
1020 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
1021 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
1022 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
1023 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET+BPF_K,
1024 SECCOMP_RET_KILL);
1025
1026 free(actual.filter);
1027}