1 // 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 #include <string>
24
25 #include "bpf.h"
26 #include "syscall_filter.h"
27 #include "syscall_filter_unittest_macros.h"
28 #include "util.h"
29
TEST(util,parse_constant_unsigned)30 TEST(util, parse_constant_unsigned) {
31 char *end;
32 long int c = 0;
33 std::string constant;
34
35 #if defined(BITS32)
36 constant = "0x80000000";
37 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
38 EXPECT_EQ(0x80000000U, static_cast<unsigned long int>(c));
39
40 #elif defined(BITS64)
41 constant = "0x8000000000000000";
42 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
43 EXPECT_EQ(0x8000000000000000UL, static_cast<unsigned long int>(c));
44 #endif
45 }
46
TEST(util,parse_constant_unsigned_toobig)47 TEST(util, parse_constant_unsigned_toobig) {
48 char *end;
49 long int c = 0;
50 std::string constant;
51
52 #if defined(BITS32)
53 constant = "0x100000000"; // Too big for 32-bit unsigned long int.
54 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
55 // Error case should return 0.
56 EXPECT_EQ(0, c);
57
58 #elif defined(BITS64)
59 constant = "0x10000000000000000";
60 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
61 // Error case should return 0.
62 EXPECT_EQ(0, c);
63 #endif
64 }
65
TEST(util,parse_constant_signed)66 TEST(util, parse_constant_signed) {
67 char *end;
68 long int c = 0;
69 std::string constant = "-1";
70 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
71 EXPECT_EQ(-1, c);
72 }
73
TEST(util,parse_constant_signed_toonegative)74 TEST(util, parse_constant_signed_toonegative) {
75 char *end;
76 long int c = 0;
77 std::string constant;
78
79 #if defined(BITS32)
80 constant = "-0x80000001";
81 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
82 // Error case should return 0.
83 EXPECT_EQ(0, c);
84
85 #elif defined(BITS64)
86 constant = "-0x8000000000000001";
87 c = parse_constant(const_cast<char*>(constant.c_str()), &end);
88 // Error case should return 0.
89 EXPECT_EQ(0, c);
90 #endif
91 }
92
93 /* Test that setting one BPF instruction works. */
TEST(bpf,set_bpf_instr)94 TEST(bpf, set_bpf_instr) {
95 struct sock_filter instr;
96 unsigned char code = BPF_LD + BPF_W + BPF_ABS;
97 unsigned int k = 4;
98 unsigned char jt = 1, jf = 2;
99
100 size_t len = set_bpf_instr(&instr, code, k, jt, jf);
101
102 EXPECT_EQ(len, 1U);
103 EXPECT_EQ_BLOCK(&instr, code, k, jt, jf);
104 }
105
TEST(bpf,bpf_load_arg)106 TEST(bpf, bpf_load_arg) {
107 struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
108 const int argidx = 1;
109 size_t len = bpf_load_arg(load_arg, argidx);
110
111 EXPECT_EQ(len, BPF_LOAD_ARG_LEN);
112
113 #if defined(BITS32)
114 EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
115 #elif defined(BITS64)
116 EXPECT_EQ_STMT(&load_arg[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
117 EXPECT_EQ_STMT(&load_arg[1], BPF_ST, 0);
118 EXPECT_EQ_STMT(&load_arg[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
119 EXPECT_EQ_STMT(&load_arg[3], BPF_ST, 1);
120 #endif
121 }
122
TEST(bpf,bpf_comp_jeq)123 TEST(bpf, bpf_comp_jeq) {
124 struct sock_filter comp_jeq[BPF_COMP_LEN];
125 unsigned long c = 1;
126 unsigned char jt = 1;
127 unsigned char jf = 2;
128
129 size_t len = bpf_comp_jeq(comp_jeq, c, jt, jf);
130
131 EXPECT_EQ(len, BPF_COMP_LEN);
132
133 #if defined(BITS32)
134 EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
135 #elif defined(BITS64)
136 EXPECT_EQ_BLOCK(&comp_jeq[0], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, jf + 2);
137 EXPECT_EQ_STMT(&comp_jeq[1], BPF_LD + BPF_MEM, 0);
138 EXPECT_EQ_BLOCK(&comp_jeq[2], BPF_JMP + BPF_JEQ + BPF_K, c, jt, jf);
139 #endif
140 }
141
TEST(bpf,bpf_comp_jset)142 TEST(bpf, bpf_comp_jset) {
143 struct sock_filter comp_jset[BPF_COMP_LEN];
144 unsigned long mask = (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
145 unsigned char jt = 1;
146 unsigned char jf = 2;
147
148 size_t len = bpf_comp_jset(comp_jset, mask, jt, jf);
149
150 EXPECT_EQ(len, BPF_COMP_LEN);
151
152 #if defined(BITS32)
153 EXPECT_EQ_BLOCK(&comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, mask, jt, jf);
154 #elif defined(BITS64)
155 EXPECT_EQ_BLOCK(
156 &comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, 0x80000000, jt + 2, 0);
157 EXPECT_EQ_STMT(&comp_jset[1], BPF_LD + BPF_MEM, 0);
158 EXPECT_EQ_BLOCK(&comp_jset[2], BPF_JMP + BPF_JSET + BPF_K, O_WRONLY, jt, jf);
159 #endif
160 }
161
TEST(bpf,bpf_comp_jin)162 TEST(bpf, bpf_comp_jin) {
163 struct sock_filter comp_jin[BPF_COMP_LEN];
164 unsigned long mask = (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
165 unsigned char jt = 10;
166 unsigned char jf = 20;
167
168 size_t len = bpf_comp_jin(comp_jin, mask, jt, jf);
169
170 EXPECT_EQ(len, BPF_COMP_LEN);
171
172 #if defined(BITS32)
173 EXPECT_EQ_BLOCK(&comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, ~mask, jf, jt);
174 #elif defined(BITS64)
175 EXPECT_EQ_BLOCK(
176 &comp_jin[0], BPF_JMP + BPF_JSET + BPF_K, 0x7FFFFFFF, jf + 2, 0);
177 EXPECT_EQ_STMT(&comp_jin[1], BPF_LD + BPF_MEM, 0);
178 EXPECT_EQ_BLOCK(&comp_jin[2], BPF_JMP + BPF_JSET + BPF_K, ~O_WRONLY, jf, jt);
179 #endif
180 }
181
TEST(bpf,bpf_arg_comp)182 TEST(bpf, bpf_arg_comp) {
183 struct sock_filter *arg_comp;
184 int op = EQ;
185 const int argidx = 1;
186 unsigned long c = 3;
187 unsigned int label_id = 0;
188
189 size_t len = bpf_arg_comp(&arg_comp, op, argidx, c, label_id);
190
191 EXPECT_EQ(len, BPF_ARG_COMP_LEN + 1);
192
193 #if defined(BITS32)
194 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
195 EXPECT_EQ_BLOCK(&arg_comp[1], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
196 EXPECT_JUMP_LBL(&arg_comp[2]);
197 #elif defined(BITS64)
198 EXPECT_EQ_STMT(&arg_comp[0], BPF_LD + BPF_W + BPF_ABS, LO_ARG(argidx));
199 EXPECT_EQ_STMT(&arg_comp[1], BPF_ST, 0);
200 EXPECT_EQ_STMT(&arg_comp[2], BPF_LD + BPF_W + BPF_ABS, HI_ARG(argidx));
201 EXPECT_EQ_STMT(&arg_comp[3], BPF_ST, 1);
202
203 EXPECT_EQ_BLOCK(&arg_comp[4], BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2);
204 EXPECT_EQ_STMT(&arg_comp[5], BPF_LD + BPF_MEM, 0);
205 EXPECT_EQ_BLOCK(&arg_comp[6], BPF_JMP + BPF_JEQ + BPF_K, c, 1, 0);
206 EXPECT_JUMP_LBL(&arg_comp[7]);
207 #endif
208 free(arg_comp);
209 }
210
TEST(bpf,bpf_validate_arch)211 TEST(bpf, bpf_validate_arch) {
212 struct sock_filter validate_arch[ARCH_VALIDATION_LEN];
213
214 size_t len = bpf_validate_arch(validate_arch);
215
216 EXPECT_EQ(len, ARCH_VALIDATION_LEN);
217 EXPECT_ARCH_VALIDATION(validate_arch);
218 }
219
TEST(bpf,bpf_allow_syscall)220 TEST(bpf, bpf_allow_syscall) {
221 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
222 int nr = 1;
223
224 size_t len = bpf_allow_syscall(allow_syscall, nr);
225
226 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
227 EXPECT_ALLOW_SYSCALL(allow_syscall, nr);
228 }
229
TEST(bpf,bpf_allow_syscall_args)230 TEST(bpf, bpf_allow_syscall_args) {
231 struct sock_filter allow_syscall[ALLOW_SYSCALL_LEN];
232 int nr = 1;
233 unsigned int id = 1024;
234
235 size_t len = bpf_allow_syscall_args(allow_syscall, nr, id);
236
237 EXPECT_EQ(len, ALLOW_SYSCALL_LEN);
238 EXPECT_ALLOW_SYSCALL_ARGS(allow_syscall, nr, id, JUMP_JT, JUMP_JF);
239 }
240
241 class BpfLabelTest : public ::testing::Test {
242 protected:
SetUp()243 virtual void SetUp() { labels_.count = 0; }
TearDown()244 virtual void TearDown() { free_label_strings(&labels_); }
245 struct bpf_labels labels_;
246 };
247
TEST_F(BpfLabelTest,zero_length_filter)248 TEST_F(BpfLabelTest, zero_length_filter) {
249 int res = bpf_resolve_jumps(&labels_, NULL, 0);
250
251 EXPECT_EQ(res, 0);
252 EXPECT_EQ(labels_.count, 0U);
253 }
254
TEST_F(BpfLabelTest,single_label)255 TEST_F(BpfLabelTest, single_label) {
256 struct sock_filter test_label[1];
257
258 int id = bpf_label_id(&labels_, "test");
259 set_bpf_lbl(test_label, id);
260 int res = bpf_resolve_jumps(&labels_, test_label, 1);
261
262 EXPECT_EQ(res, 0);
263 EXPECT_EQ(labels_.count, 1U);
264 }
265
TEST_F(BpfLabelTest,repeated_label)266 TEST_F(BpfLabelTest, repeated_label) {
267 struct sock_filter test_label[2];
268
269 int id = bpf_label_id(&labels_, "test");
270 set_bpf_lbl(&test_label[0], id);
271 set_bpf_lbl(&test_label[1], id);
272 int res = bpf_resolve_jumps(&labels_, test_label, 2);
273
274 EXPECT_EQ(res, -1);
275 }
276
TEST_F(BpfLabelTest,jump_with_no_label)277 TEST_F(BpfLabelTest, jump_with_no_label) {
278 struct sock_filter test_jump[1];
279
280 set_bpf_jump_lbl(test_jump, 14831);
281 int res = bpf_resolve_jumps(&labels_, test_jump, 1);
282
283 EXPECT_EQ(res, -1);
284 }
285
TEST_F(BpfLabelTest,jump_to_valid_label)286 TEST_F(BpfLabelTest, jump_to_valid_label) {
287 struct sock_filter test_jump[2];
288
289 int id = bpf_label_id(&labels_, "test");
290 set_bpf_jump_lbl(&test_jump[0], id);
291 set_bpf_lbl(&test_jump[1], id);
292
293 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
294 EXPECT_EQ(res, 0);
295 EXPECT_EQ(labels_.count, 1U);
296 }
297
TEST_F(BpfLabelTest,jump_to_invalid_label)298 TEST_F(BpfLabelTest, jump_to_invalid_label) {
299 struct sock_filter test_jump[2];
300
301 int id = bpf_label_id(&labels_, "test");
302 set_bpf_jump_lbl(&test_jump[0], id + 1);
303 set_bpf_lbl(&test_jump[1], id);
304
305 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
306 EXPECT_EQ(res, -1);
307 }
308
TEST_F(BpfLabelTest,jump_to_unresolved_label)309 TEST_F(BpfLabelTest, jump_to_unresolved_label) {
310 struct sock_filter test_jump[2];
311
312 int id = bpf_label_id(&labels_, "test");
313 /* Notice the order of the instructions is reversed. */
314 set_bpf_lbl(&test_jump[0], id);
315 set_bpf_jump_lbl(&test_jump[1], id);
316
317 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
318 EXPECT_EQ(res, -1);
319 }
320
TEST_F(BpfLabelTest,too_many_labels)321 TEST_F(BpfLabelTest, too_many_labels) {
322 unsigned int i;
323 char label[20];
324
325 for (i = 0; i < BPF_LABELS_MAX; i++) {
326 snprintf(label, 20, "test%u", i);
327 (void) bpf_label_id(&labels_, label);
328 }
329 int id = bpf_label_id(&labels_, "test");
330
331 /* Insertion failed... */
332 EXPECT_EQ(id, -1);
333 /* ... because the label lookup table is full. */
334 EXPECT_EQ(labels_.count, BPF_LABELS_MAX);
335 }
336
337 class ArgFilterTest : public ::testing::Test {
338 protected:
SetUp()339 virtual void SetUp() { labels_.count = 0; }
TearDown()340 virtual void TearDown() { free_label_strings(&labels_); }
341 struct bpf_labels labels_;
342 };
343
TEST_F(ArgFilterTest,empty_atom)344 TEST_F(ArgFilterTest, empty_atom) {
345 const char* fragment = "";
346 int nr = 1;
347 unsigned int id = 0;
348
349 struct filter_block* block =
350 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
351 ASSERT_EQ(block, nullptr);
352 }
353
TEST_F(ArgFilterTest,whitespace_atom)354 TEST_F(ArgFilterTest, whitespace_atom) {
355 const char* fragment = "\t ";
356 int nr = 1;
357 unsigned int id = 0;
358
359 struct filter_block* block =
360 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
361 ASSERT_EQ(block, nullptr);
362 }
363
TEST_F(ArgFilterTest,no_comparison)364 TEST_F(ArgFilterTest, no_comparison) {
365 const char* fragment = "arg0";
366 int nr = 1;
367 unsigned int id = 0;
368
369 struct filter_block* block =
370 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
371 ASSERT_EQ(block, nullptr);
372 }
373
TEST_F(ArgFilterTest,no_constant)374 TEST_F(ArgFilterTest, no_constant) {
375 const char* fragment = "arg0 ==";
376 int nr = 1;
377 unsigned int id = 0;
378
379 struct filter_block* block =
380 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
381 ASSERT_EQ(block, nullptr);
382 }
383
TEST_F(ArgFilterTest,arg0_equals)384 TEST_F(ArgFilterTest, arg0_equals) {
385 const char *fragment = "arg0 == 0";
386 int nr = 1;
387 unsigned int id = 0;
388 struct filter_block *block =
389 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
390
391 ASSERT_NE(block, nullptr);
392 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 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_NE(curr_block, nullptr);
398 EXPECT_EQ(curr_block->len, 1U);
399 EXPECT_LBL(curr_block->instrs);
400
401 /* Second block is a comparison. */
402 curr_block = curr_block->next;
403 EXPECT_COMP(curr_block);
404
405 /* Third block is a jump and a label (end of AND group). */
406 curr_block = curr_block->next;
407 ASSERT_NE(curr_block, nullptr);
408 EXPECT_GROUP_END(curr_block);
409
410 /* Fourth block is SECCOMP_RET_KILL. */
411 curr_block = curr_block->next;
412 ASSERT_NE(curr_block, nullptr);
413 EXPECT_KILL(curr_block);
414
415 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
416 curr_block = curr_block->next;
417 ASSERT_NE(curr_block, nullptr);
418 EXPECT_ALLOW(curr_block);
419
420 EXPECT_EQ(curr_block->next, nullptr);
421
422 free_block_list(block);
423 }
424
TEST_F(ArgFilterTest,arg0_mask)425 TEST_F(ArgFilterTest, arg0_mask) {
426 const char *fragment = "arg1 & O_RDWR";
427 int nr = 1;
428 unsigned int id = 0;
429 struct filter_block *block =
430 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
431
432 ASSERT_NE(block, nullptr);
433 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
434 EXPECT_EQ(block->total_len, exp_total_len);
435
436 /* First block is a label. */
437 struct filter_block *curr_block = block;
438 ASSERT_NE(curr_block, nullptr);
439 EXPECT_EQ(curr_block->len, 1U);
440 EXPECT_LBL(curr_block->instrs);
441
442 /* Second block is a comparison. */
443 curr_block = curr_block->next;
444 EXPECT_COMP(curr_block);
445
446 /* Third block is a jump and a label (end of AND group). */
447 curr_block = curr_block->next;
448 ASSERT_NE(curr_block, nullptr);
449 EXPECT_GROUP_END(curr_block);
450
451 /* Fourth block is SECCOMP_RET_KILL. */
452 curr_block = curr_block->next;
453 ASSERT_NE(curr_block, nullptr);
454 EXPECT_KILL(curr_block);
455
456 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
457 curr_block = curr_block->next;
458 ASSERT_NE(curr_block, nullptr);
459 EXPECT_ALLOW(curr_block);
460
461 EXPECT_EQ(curr_block->next, nullptr);
462
463 free_block_list(block);
464 }
465
TEST_F(ArgFilterTest,arg0_flag_set_inclusion)466 TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
467 const char *fragment = "arg0 in O_RDONLY|O_CREAT";
468 int nr = 1;
469 unsigned int id = 0;
470 struct filter_block *block =
471 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
472
473 ASSERT_NE(block, nullptr);
474 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
475 EXPECT_EQ(block->total_len, exp_total_len);
476
477 /* First block is a label. */
478 struct filter_block *curr_block = block;
479 ASSERT_NE(curr_block, nullptr);
480 EXPECT_EQ(curr_block->len, 1U);
481 EXPECT_LBL(curr_block->instrs);
482
483 /* Second block is a comparison. */
484 curr_block = curr_block->next;
485 ASSERT_NE(curr_block, nullptr);
486 EXPECT_COMP(curr_block);
487
488 /* Third block is a jump and a label (end of AND group). */
489 curr_block = curr_block->next;
490 ASSERT_NE(curr_block, nullptr);
491 EXPECT_GROUP_END(curr_block);
492
493 /* Fourth block is SECCOMP_RET_KILL. */
494 curr_block = curr_block->next;
495 ASSERT_NE(curr_block, nullptr);
496 EXPECT_KILL(curr_block);
497
498 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
499 curr_block = curr_block->next;
500 ASSERT_NE(curr_block, nullptr);
501 EXPECT_ALLOW(curr_block);
502
503 EXPECT_EQ(curr_block->next, nullptr);
504
505 free_block_list(block);
506 }
507
TEST_F(ArgFilterTest,arg0_eq_mask)508 TEST_F(ArgFilterTest, arg0_eq_mask) {
509 const char *fragment = "arg1 == O_WRONLY|O_CREAT";
510 int nr = 1;
511 unsigned int id = 0;
512
513 struct filter_block *block =
514 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
515
516 ASSERT_NE(block, nullptr);
517 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
518 EXPECT_EQ(block->total_len, exp_total_len);
519
520 /* First block is a label. */
521 struct filter_block *curr_block = block;
522 ASSERT_NE(curr_block, nullptr);
523 EXPECT_EQ(curr_block->len, 1U);
524 EXPECT_LBL(curr_block->instrs);
525
526 /* Second block is a comparison. */
527 curr_block = curr_block->next;
528 ASSERT_NE(curr_block, nullptr);
529 EXPECT_COMP(curr_block);
530 EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
531 (unsigned int)(O_WRONLY | O_CREAT));
532
533 /* Third block is a jump and a label (end of AND group). */
534 curr_block = curr_block->next;
535 ASSERT_NE(curr_block, nullptr);
536 EXPECT_GROUP_END(curr_block);
537
538 /* Fourth block is SECCOMP_RET_KILL. */
539 curr_block = curr_block->next;
540 ASSERT_NE(curr_block, nullptr);
541 EXPECT_KILL(curr_block);
542
543 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
544 curr_block = curr_block->next;
545 ASSERT_NE(curr_block, nullptr);
546 EXPECT_ALLOW(curr_block);
547
548 EXPECT_EQ(curr_block->next, nullptr);
549
550 free_block_list(block);
551 }
552
TEST_F(ArgFilterTest,and_or)553 TEST_F(ArgFilterTest, and_or) {
554 const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
555 int nr = 1;
556 unsigned int id = 0;
557
558 struct filter_block *block =
559 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
560 ASSERT_NE(block, nullptr);
561 size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
562 EXPECT_EQ(block->total_len, exp_total_len);
563
564 /* First block is a label. */
565 struct filter_block *curr_block = block;
566 ASSERT_NE(curr_block, nullptr);
567 EXPECT_EQ(curr_block->len, 1U);
568 EXPECT_LBL(curr_block->instrs);
569
570 /* Second block is a comparison ("arg0 == 0"). */
571 curr_block = curr_block->next;
572 ASSERT_NE(curr_block, nullptr);
573 EXPECT_COMP(curr_block);
574
575 /* Third block is a comparison ("arg1 == 0"). */
576 curr_block = curr_block->next;
577 ASSERT_NE(curr_block, nullptr);
578 EXPECT_COMP(curr_block);
579
580 /* Fourth block is a jump and a label (end of AND group). */
581 curr_block = curr_block->next;
582 ASSERT_NE(curr_block, nullptr);
583 EXPECT_GROUP_END(curr_block);
584
585 /* Fifth block is a comparison ("arg0 == 1"). */
586 curr_block = curr_block->next;
587 ASSERT_NE(curr_block, nullptr);
588 EXPECT_COMP(curr_block);
589
590 /* Sixth block is a jump and a label (end of AND group). */
591 curr_block = curr_block->next;
592 ASSERT_NE(curr_block, nullptr);
593 EXPECT_GROUP_END(curr_block);
594
595 /* Seventh block is SECCOMP_RET_KILL. */
596 curr_block = curr_block->next;
597 ASSERT_NE(curr_block, nullptr);
598 EXPECT_KILL(curr_block);
599
600 /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
601 curr_block = curr_block->next;
602 ASSERT_NE(curr_block, nullptr);
603 EXPECT_ALLOW(curr_block);
604
605 EXPECT_EQ(curr_block->next, nullptr);
606
607 free_block_list(block);
608 }
609
TEST_F(ArgFilterTest,ret_errno)610 TEST_F(ArgFilterTest, ret_errno) {
611 const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
612 int nr = 1;
613 unsigned int id = 0;
614
615 struct filter_block *block =
616 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
617 ASSERT_NE(block, nullptr);
618 size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
619 EXPECT_EQ(block->total_len, exp_total_len);
620
621 /* First block is a label. */
622 struct filter_block *curr_block = block;
623 ASSERT_NE(curr_block, nullptr);
624 EXPECT_EQ(curr_block->len, 1U);
625 EXPECT_LBL(curr_block->instrs);
626
627 /* Second block is a comparison ("arg0 == 0"). */
628 curr_block = curr_block->next;
629 ASSERT_NE(curr_block, nullptr);
630 EXPECT_COMP(curr_block);
631
632 /* Third block is a jump and a label (end of AND group). */
633 curr_block = curr_block->next;
634 ASSERT_NE(curr_block, nullptr);
635 EXPECT_GROUP_END(curr_block);
636
637 /* Fourth block is a comparison ("arg0 == 1"). */
638 curr_block = curr_block->next;
639 ASSERT_NE(curr_block, nullptr);
640 EXPECT_COMP(curr_block);
641
642 /* Fifth block is a jump and a label (end of AND group). */
643 curr_block = curr_block->next;
644 ASSERT_NE(curr_block, nullptr);
645 EXPECT_GROUP_END(curr_block);
646
647 /* Sixth block is SECCOMP_RET_ERRNO. */
648 curr_block = curr_block->next;
649 ASSERT_NE(curr_block, nullptr);
650 EXPECT_EQ(curr_block->len, 1U);
651 EXPECT_EQ_STMT(curr_block->instrs,
652 BPF_RET + BPF_K,
653 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
654
655 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
656 curr_block = curr_block->next;
657 ASSERT_NE(curr_block, nullptr);
658 EXPECT_ALLOW(curr_block);
659
660 EXPECT_EQ(curr_block->next, nullptr);
661
662 free_block_list(block);
663 }
664
TEST_F(ArgFilterTest,unconditional_errno)665 TEST_F(ArgFilterTest, unconditional_errno) {
666 const char *fragment = "return 1";
667 int nr = 1;
668 unsigned int id = 0;
669
670 struct filter_block *block =
671 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
672 ASSERT_NE(block, nullptr);
673 size_t exp_total_len = 2;
674 EXPECT_EQ(block->total_len, exp_total_len);
675
676 /* First block is a label. */
677 struct filter_block *curr_block = block;
678 ASSERT_NE(curr_block, nullptr);
679 EXPECT_EQ(curr_block->len, 1U);
680 EXPECT_LBL(curr_block->instrs);
681
682 /* Second block is SECCOMP_RET_ERRNO. */
683 curr_block = curr_block->next;
684 ASSERT_NE(curr_block, nullptr);
685 EXPECT_EQ(curr_block->len, 1U);
686 EXPECT_EQ_STMT(curr_block->instrs,
687 BPF_RET + BPF_K,
688 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
689
690 EXPECT_EQ(curr_block->next, nullptr);
691
692 free_block_list(block);
693 }
694
TEST_F(ArgFilterTest,invalid_arg_token)695 TEST_F(ArgFilterTest, invalid_arg_token) {
696 const char *fragment = "org0 == 0";
697 int nr = 1;
698 unsigned int id = 0;
699
700 struct filter_block *block =
701 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
702 ASSERT_EQ(block, nullptr);
703 }
704
TEST_F(ArgFilterTest,invalid_arg_number)705 TEST_F(ArgFilterTest, invalid_arg_number) {
706 const char *fragment = "argnn == 0";
707 int nr = 1;
708 unsigned int id = 0;
709
710 struct filter_block *block =
711 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
712 ASSERT_EQ(block, nullptr);
713 }
714
TEST_F(ArgFilterTest,extra_chars_in_arg_token)715 TEST_F(ArgFilterTest, extra_chars_in_arg_token) {
716 const char* fragment = "arg0n == 0";
717 int nr = 1;
718 unsigned int id = 0;
719
720 struct filter_block* block =
721 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
722 ASSERT_EQ(block, nullptr);
723 }
724
TEST_F(ArgFilterTest,invalid_operator)725 TEST_F(ArgFilterTest, invalid_operator) {
726 const char* fragment = "arg0 invalidop 0";
727 int nr = 1;
728 unsigned int id = 0;
729
730 struct filter_block* block =
731 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
732 ASSERT_EQ(block, nullptr);
733 }
734
TEST_F(ArgFilterTest,invalid_constant)735 TEST_F(ArgFilterTest, invalid_constant) {
736 const char *fragment = "arg0 == INVALIDCONSTANT";
737 int nr = 1;
738 unsigned int id = 0;
739
740 struct filter_block* block =
741 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
742 ASSERT_EQ(block, nullptr);
743 }
744
TEST_F(ArgFilterTest,extra_tokens)745 TEST_F(ArgFilterTest, extra_tokens) {
746 const char* fragment = "arg0 == 0 EXTRATOKEN";
747 int nr = 1;
748 unsigned int id = 0;
749
750 struct filter_block* block =
751 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
752 ASSERT_EQ(block, nullptr);
753 }
754
TEST_F(ArgFilterTest,invalid_errno)755 TEST_F(ArgFilterTest, invalid_errno) {
756 const char *fragment = "arg0 == 0 && arg1 == 1; return errno";
757 int nr = 1;
758 unsigned int id = 0;
759
760 struct filter_block *block =
761 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
762 ASSERT_EQ(block, nullptr);
763 }
764
TEST_F(ArgFilterTest,log_no_ret_error)765 TEST_F(ArgFilterTest, log_no_ret_error) {
766 const char *fragment = "arg0 == 0";
767 int nr = 1;
768 unsigned int id = 0;
769 struct filter_block *block =
770 compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
771
772 ASSERT_NE(block, nullptr);
773 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
774 EXPECT_EQ(block->total_len, exp_total_len);
775
776 /* First block is a label. */
777 struct filter_block *curr_block = block;
778 ASSERT_NE(curr_block, nullptr);
779 EXPECT_EQ(curr_block->len, 1U);
780 EXPECT_LBL(curr_block->instrs);
781
782 /* Second block is a comparison. */
783 curr_block = curr_block->next;
784 ASSERT_NE(curr_block, nullptr);
785 EXPECT_COMP(curr_block);
786
787 /* Third block is a jump and a label (end of AND group). */
788 curr_block = curr_block->next;
789 ASSERT_NE(curr_block, nullptr);
790 EXPECT_GROUP_END(curr_block);
791
792 /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
793 curr_block = curr_block->next;
794 ASSERT_NE(curr_block, nullptr);
795 EXPECT_TRAP(curr_block);
796
797 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
798 curr_block = curr_block->next;
799 ASSERT_NE(curr_block, nullptr);
800 EXPECT_ALLOW(curr_block);
801
802 EXPECT_EQ(curr_block->next, nullptr);
803
804 free_block_list(block);
805 }
806
TEST_F(ArgFilterTest,log_bad_ret_error)807 TEST_F(ArgFilterTest, log_bad_ret_error) {
808 const char *fragment = "arg0 == 0; return";
809 int nr = 1;
810 unsigned int id = 0;
811
812 struct filter_block *block =
813 compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
814 ASSERT_NE(block, nullptr);
815 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
816 EXPECT_EQ(block->total_len, exp_total_len);
817
818 /* First block is a label. */
819 struct filter_block *curr_block = block;
820 ASSERT_NE(curr_block, nullptr);
821 EXPECT_EQ(curr_block->len, 1U);
822 EXPECT_LBL(curr_block->instrs);
823
824 /* Second block is a comparison ("arg0 == 0"). */
825 curr_block = curr_block->next;
826 ASSERT_NE(curr_block, nullptr);
827 EXPECT_COMP(curr_block);
828
829 /* Third block is a jump and a label (end of AND group). */
830 curr_block = curr_block->next;
831 ASSERT_NE(curr_block, nullptr);
832 EXPECT_GROUP_END(curr_block);
833
834 /*
835 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
836 */
837 curr_block = curr_block->next;
838 ASSERT_NE(curr_block, nullptr);
839 EXPECT_KILL(curr_block);
840
841 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
842 curr_block = curr_block->next;
843 ASSERT_NE(curr_block, nullptr);
844 EXPECT_ALLOW(curr_block);
845
846 EXPECT_EQ(curr_block->next, nullptr);
847
848 free_block_list(block);
849 }
850
TEST_F(ArgFilterTest,no_log_bad_ret_error)851 TEST_F(ArgFilterTest, no_log_bad_ret_error) {
852 const char *fragment = "arg0 == 0; return";
853 int nr = 1;
854 unsigned int id = 0;
855
856 struct filter_block *block =
857 compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
858 ASSERT_NE(block, nullptr);
859 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
860 EXPECT_EQ(block->total_len, exp_total_len);
861
862 /* First block is a label. */
863 struct filter_block *curr_block = block;
864 ASSERT_NE(curr_block, nullptr);
865 EXPECT_EQ(curr_block->len, 1U);
866 EXPECT_LBL(curr_block->instrs);
867
868 /* Second block is a comparison ("arg0 == 0"). */
869 curr_block = curr_block->next;
870 ASSERT_NE(curr_block, nullptr);
871 EXPECT_COMP(curr_block);
872
873 /* Third block is a jump and a label (end of AND group). */
874 curr_block = curr_block->next;
875 ASSERT_NE(curr_block, nullptr);
876 EXPECT_GROUP_END(curr_block);
877
878 /*
879 * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
880 * SECCOMP_RET_TRAP.
881 */
882 curr_block = curr_block->next;
883 ASSERT_NE(curr_block, nullptr);
884 EXPECT_TRAP(curr_block);
885
886 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
887 curr_block = curr_block->next;
888 ASSERT_NE(curr_block, nullptr);
889 EXPECT_ALLOW(curr_block);
890
891 EXPECT_EQ(curr_block->next, nullptr);
892
893 free_block_list(block);
894 }
895
write_policy_to_pipe(const char * policy,size_t len)896 FILE *write_policy_to_pipe(const char *policy, size_t len) {
897 int pipefd[2];
898 if (pipe(pipefd) == -1) {
899 pwarn("pipe(pipefd) failed");
900 return NULL;
901 }
902
903 size_t i = 0;
904 unsigned int attempts = 0;
905 ssize_t ret;
906 while (i < len) {
907 ret = write(pipefd[1], &policy[i], len - i);
908 if (ret == -1) {
909 close(pipefd[0]);
910 close(pipefd[1]);
911 return NULL;
912 }
913
914 /* If we write 0 bytes three times in a row, fail. */
915 if (ret == 0) {
916 if (++attempts >= 3) {
917 close(pipefd[0]);
918 close(pipefd[1]);
919 warn("write() returned 0 three times in a row");
920 return NULL;
921 }
922 continue;
923 }
924
925 attempts = 0;
926 i += (size_t)ret;
927 }
928
929 close(pipefd[1]);
930 return fdopen(pipefd[0], "r");
931 }
932
933 class FileTest : public ::testing::Test {
934 protected:
SetUp()935 virtual void SetUp() {
936 labels_.count = 0;
937 head_ = new_filter_block();
938 arg_blocks_ = NULL;
939 }
TearDown()940 virtual void TearDown() {
941 free_label_strings(&labels_);
942 free_block_list(head_);
943 free_block_list(arg_blocks_);
944 }
945 struct bpf_labels labels_;
946 struct filter_block *head_;
947 struct filter_block *arg_blocks_;
948 };
949
TEST_F(FileTest,seccomp_mode1)950 TEST_F(FileTest, seccomp_mode1) {
951 const char *policy =
952 "read: 1\n"
953 "write: 1\n"
954 "rt_sigreturn: 1\n"
955 "exit: 1\n";
956
957 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
958 ASSERT_NE(policy_file, nullptr);
959 int res = compile_file(
960 policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
961 fclose(policy_file);
962
963 /*
964 * Checks return value and that the blocks only allow expected syscalls.
965 */
966 ASSERT_EQ(res, 0);
967 struct filter_block *curr_block = head_;
968 ASSERT_NE(curr_block, nullptr);
969 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_read);
970 curr_block = curr_block->next;
971 ASSERT_NE(curr_block, nullptr);
972 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
973 curr_block = curr_block->next;
974 ASSERT_NE(curr_block, nullptr);
975 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
976 curr_block = curr_block->next;
977 ASSERT_NE(curr_block, nullptr);
978 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
979
980 EXPECT_EQ(curr_block->next, nullptr);
981 }
982
TEST_F(FileTest,seccomp_read)983 TEST_F(FileTest, seccomp_read) {
984 const char *policy =
985 "read: arg0 == 0\n"
986 "write: 1\n"
987 "rt_sigreturn: 1\n"
988 "exit: 1\n";
989
990 const int LABEL_ID = 0;
991
992 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
993 ASSERT_NE(policy_file, nullptr);
994 int res = compile_file(
995 policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
996 fclose(policy_file);
997
998 /*
999 * Checks return value, that the blocks only allow expected syscalls, and that
1000 * labels between |head_| and |arg_blocks_| match.
1001 */
1002 ASSERT_EQ(res, 0);
1003 struct filter_block *curr_block = head_;
1004 ASSERT_NE(curr_block, nullptr);
1005 EXPECT_ALLOW_SYSCALL_ARGS(curr_block->instrs,
1006 __NR_read,
1007 LABEL_ID,
1008 JUMP_JT,
1009 JUMP_JF);
1010 curr_block = curr_block->next;
1011 ASSERT_NE(curr_block, nullptr);
1012 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_write);
1013 curr_block = curr_block->next;
1014 ASSERT_NE(curr_block, nullptr);
1015 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_rt_sigreturn);
1016 curr_block = curr_block->next;
1017 ASSERT_NE(curr_block, nullptr);
1018 EXPECT_ALLOW_SYSCALL(curr_block->instrs, __NR_exit);
1019
1020 ASSERT_NE(arg_blocks_, nullptr);
1021 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
1022 EXPECT_EQ(arg_blocks_->total_len, exp_total_len);
1023
1024 /* First block is a label. */
1025 curr_block = arg_blocks_;
1026 ASSERT_NE(curr_block, nullptr);
1027 EXPECT_EQ(curr_block->len, 1U);
1028 EXPECT_ACTUAL_LBL(curr_block->instrs, LABEL_ID);
1029
1030 /* Second block is a comparison. */
1031 curr_block = curr_block->next;
1032 EXPECT_COMP(curr_block);
1033
1034 /* Third block is a jump and a label (end of AND group). */
1035 curr_block = curr_block->next;
1036 ASSERT_NE(curr_block, nullptr);
1037 EXPECT_GROUP_END(curr_block);
1038
1039 /* Fourth block is SECCOMP_RET_KILL. */
1040 curr_block = curr_block->next;
1041 ASSERT_NE(curr_block, nullptr);
1042 EXPECT_KILL(curr_block);
1043
1044 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
1045 curr_block = curr_block->next;
1046 ASSERT_NE(curr_block, nullptr);
1047 EXPECT_ALLOW(curr_block);
1048
1049 EXPECT_EQ(curr_block->next, nullptr);
1050 }
1051
TEST(FilterTest,seccomp_mode1)1052 TEST(FilterTest, seccomp_mode1) {
1053 struct sock_fprog actual;
1054 const char *policy =
1055 "read: 1\n"
1056 "write: 1\n"
1057 "rt_sigreturn: 1\n"
1058 "exit: 1\n";
1059
1060 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1061 ASSERT_NE(policy_file, nullptr);
1062
1063 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1064 fclose(policy_file);
1065
1066 /*
1067 * Checks return value, filter length, and that the filter
1068 * validates arch, loads syscall number, and
1069 * only allows expected syscalls.
1070 */
1071 ASSERT_EQ(res, 0);
1072 EXPECT_EQ(actual.len, 13);
1073 EXPECT_ARCH_VALIDATION(actual.filter);
1074 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1075 BPF_LD + BPF_W + BPF_ABS,
1076 syscall_nr);
1077 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
1078 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
1079 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
1080 __NR_rt_sigreturn);
1081 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
1082 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
1083 BPF_RET + BPF_K,
1084 SECCOMP_RET_KILL);
1085
1086 free(actual.filter);
1087 }
1088
TEST(FilterTest,seccomp_mode1_trap)1089 TEST(FilterTest, seccomp_mode1_trap) {
1090 struct sock_fprog actual;
1091 const char *policy =
1092 "read: 1\n"
1093 "write: 1\n"
1094 "rt_sigreturn: 1\n"
1095 "exit: 1\n";
1096
1097 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1098 ASSERT_NE(policy_file, nullptr);
1099
1100 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
1101 fclose(policy_file);
1102
1103 /*
1104 * Checks return value, filter length, and that the filter
1105 * validates arch, loads syscall number, and
1106 * only allows expected syscalls.
1107 */
1108 ASSERT_EQ(res, 0);
1109 EXPECT_EQ(actual.len, 13);
1110 EXPECT_ARCH_VALIDATION(actual.filter);
1111 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1112 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
1113 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1,
1114 __NR_read);
1115 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3,
1116 __NR_write);
1117 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
1118 __NR_rt_sigreturn);
1119 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
1120 __NR_exit);
1121 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
1122 SECCOMP_RET_TRAP);
1123
1124 free(actual.filter);
1125 }
1126
TEST(FilterTest,seccomp_read_write)1127 TEST(FilterTest, seccomp_read_write) {
1128 struct sock_fprog actual;
1129 const char *policy =
1130 "read: arg0 == 0\n"
1131 "write: arg0 == 1 || arg0 == 2\n"
1132 "rt_sigreturn: 1\n"
1133 "exit: 1\n";
1134
1135 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1136 ASSERT_NE(policy_file, nullptr);
1137
1138 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1139 fclose(policy_file);
1140
1141 /*
1142 * Checks return value, filter length, and that the filter
1143 * validates arch, loads syscall number, and
1144 * only allows expected syscalls, jumping to correct arg filter
1145 * offsets.
1146 */
1147 ASSERT_EQ(res, 0);
1148 size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
1149 EXPECT_EQ(actual.len, exp_total_len);
1150
1151 EXPECT_ARCH_VALIDATION(actual.filter);
1152 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1153 BPF_LD + BPF_W + BPF_ABS,
1154 syscall_nr);
1155 EXPECT_ALLOW_SYSCALL_ARGS(
1156 actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
1157 EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
1158 __NR_write,
1159 12 + BPF_ARG_COMP_LEN,
1160 0,
1161 0);
1162 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
1163 __NR_rt_sigreturn);
1164 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
1165 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
1166 BPF_RET + BPF_K,
1167 SECCOMP_RET_KILL);
1168
1169 free(actual.filter);
1170 }
1171
TEST(FilterTest,misplaced_whitespace)1172 TEST(FilterTest, misplaced_whitespace) {
1173 struct sock_fprog actual;
1174 const char *policy = "open :1\n";
1175
1176 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1177 ASSERT_NE(policy_file, nullptr);
1178
1179 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1180 fclose(policy_file);
1181
1182 /* Checks return value and filter length. */
1183 ASSERT_EQ(res, 0);
1184 EXPECT_EQ(actual.len,
1185 ARCH_VALIDATION_LEN + 1 /* load syscall nr */ + ALLOW_SYSCALL_LEN +
1186 1 /* ret kill */);
1187 free(actual.filter);
1188 }
1189
TEST(FilterTest,missing_atom)1190 TEST(FilterTest, missing_atom) {
1191 struct sock_fprog actual;
1192 const char* policy = "open:\n";
1193
1194 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1195 ASSERT_NE(policy_file, nullptr);
1196
1197 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1198 fclose(policy_file);
1199 ASSERT_NE(res, 0);
1200 }
1201
TEST(FilterTest,whitespace_atom)1202 TEST(FilterTest, whitespace_atom) {
1203 struct sock_fprog actual;
1204 const char* policy = "open:\t \n";
1205
1206 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1207 ASSERT_NE(policy_file, nullptr);
1208
1209 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1210 fclose(policy_file);
1211 ASSERT_NE(res, 0);
1212 }
1213
TEST(FilterTest,invalid_name)1214 TEST(FilterTest, invalid_name) {
1215 struct sock_fprog actual;
1216 const char *policy = "notasyscall: 1\n";
1217
1218 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1219 ASSERT_NE(policy_file, nullptr);
1220
1221 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1222 fclose(policy_file);
1223 ASSERT_NE(res, 0);
1224 }
1225
TEST(FilterTest,invalid_arg)1226 TEST(FilterTest, invalid_arg) {
1227 struct sock_fprog actual;
1228 const char *policy = "open: argnn ==\n";
1229
1230 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1231 ASSERT_NE(policy_file, nullptr);
1232
1233 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1234 fclose(policy_file);
1235 ASSERT_NE(res, 0);
1236 }
1237
TEST(FilterTest,nonexistent)1238 TEST(FilterTest, nonexistent) {
1239 struct sock_fprog actual;
1240 int res = compile_filter(NULL, &actual, USE_RET_KILL, NO_LOGGING);
1241 ASSERT_NE(res, 0);
1242 }
1243
TEST(FilterTest,log)1244 TEST(FilterTest, log) {
1245 struct sock_fprog actual;
1246 const char *policy =
1247 "read: 1\n"
1248 "write: 1\n"
1249 "rt_sigreturn: 1\n"
1250 "exit: 1\n";
1251
1252 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1253 ASSERT_NE(policy_file, nullptr);
1254
1255 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
1256 fclose(policy_file);
1257
1258 size_t i;
1259 size_t index = 0;
1260 /*
1261 * Checks return value, filter length, and that the filter
1262 * validates arch, loads syscall number, only allows expected syscalls,
1263 * and returns TRAP on failure.
1264 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
1265 * for logging.
1266 */
1267 ASSERT_EQ(res, 0);
1268 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
1269 EXPECT_ARCH_VALIDATION(actual.filter);
1270 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1271 BPF_LD + BPF_W + BPF_ABS,
1272 syscall_nr);
1273
1274 index = ARCH_VALIDATION_LEN + 1;
1275 for (i = 0; i < log_syscalls_len; i++)
1276 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
1277 lookup_syscall(log_syscalls[i]));
1278
1279 index += 2 * log_syscalls_len;
1280
1281 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
1282 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
1283 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
1284 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
1285 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
1286
1287 free(actual.filter);
1288 }
1289
TEST(FilterTest,allow_log_but_kill)1290 TEST(FilterTest, allow_log_but_kill) {
1291 struct sock_fprog actual;
1292 const char *policy =
1293 "read: 1\n"
1294 "write: 1\n"
1295 "rt_sigreturn: 1\n"
1296 "exit: 1\n";
1297
1298 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1299 ASSERT_NE(policy_file, nullptr);
1300
1301 int res = compile_filter(policy_file, &actual, USE_RET_KILL, USE_LOGGING);
1302 fclose(policy_file);
1303
1304 size_t i;
1305 size_t index = 0;
1306 /*
1307 * Checks return value, filter length, and that the filter
1308 * validates arch, loads syscall number, only allows expected syscalls,
1309 * and returns TRAP on failure.
1310 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
1311 * for logging.
1312 */
1313 ASSERT_EQ(res, 0);
1314 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
1315 EXPECT_ARCH_VALIDATION(actual.filter);
1316 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1317 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
1318
1319 index = ARCH_VALIDATION_LEN + 1;
1320 for (i = 0; i < log_syscalls_len; i++)
1321 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
1322 lookup_syscall(log_syscalls[i]));
1323
1324 index += 2 * log_syscalls_len;
1325
1326 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
1327 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
1328 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
1329 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
1330 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET+BPF_K,
1331 SECCOMP_RET_KILL);
1332
1333 free(actual.filter);
1334 }
1335
TEST(FilterTest,include_invalid_token)1336 TEST(FilterTest, include_invalid_token) {
1337 struct sock_fprog actual;
1338 const char *invalid_token = "@unclude ./test/seccomp.policy\n";
1339
1340 FILE *policy_file =
1341 write_policy_to_pipe(invalid_token, strlen(invalid_token));
1342 ASSERT_NE(policy_file, nullptr);
1343 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1344 fclose(policy_file);
1345 EXPECT_NE(res, 0);
1346 }
1347
TEST(FilterTest,include_no_space)1348 TEST(FilterTest, include_no_space) {
1349 struct sock_fprog actual;
1350 const char *no_space = "@includetest/seccomp.policy\n";
1351
1352 FILE *policy_file = write_policy_to_pipe(no_space, strlen(no_space));
1353 ASSERT_NE(policy_file, nullptr);
1354 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1355 fclose(policy_file);
1356 EXPECT_NE(res, 0);
1357 }
1358
TEST(FilterTest,include_double_token)1359 TEST(FilterTest, include_double_token) {
1360 struct sock_fprog actual;
1361 const char *double_token = "@includeinclude ./test/seccomp.policy\n";
1362
1363 FILE *policy_file = write_policy_to_pipe(double_token, strlen(double_token));
1364 ASSERT_NE(policy_file, nullptr);
1365 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1366 fclose(policy_file);
1367 EXPECT_NE(res, 0);
1368 }
1369
TEST(FilterTest,include_no_file)1370 TEST(FilterTest, include_no_file) {
1371 struct sock_fprog actual;
1372 const char *no_file = "@include\n";
1373
1374 FILE *policy_file = write_policy_to_pipe(no_file, strlen(no_file));
1375 ASSERT_NE(policy_file, nullptr);
1376 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1377 fclose(policy_file);
1378 EXPECT_NE(res, 0);
1379 }
1380
TEST(FilterTest,include_space_no_file)1381 TEST(FilterTest, include_space_no_file) {
1382 struct sock_fprog actual;
1383 const char *space_no_file = "@include \n";
1384
1385 FILE *policy_file =
1386 write_policy_to_pipe(space_no_file, strlen(space_no_file));
1387 ASSERT_NE(policy_file, nullptr);
1388 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1389 fclose(policy_file);
1390 EXPECT_NE(res, 0);
1391 }
1392
TEST(FilterTest,include_implicit_relative_path)1393 TEST(FilterTest, include_implicit_relative_path) {
1394 struct sock_fprog actual;
1395 const char *implicit_relative_path = "@include test/seccomp.policy\n";
1396
1397 FILE *policy_file = write_policy_to_pipe(implicit_relative_path,
1398 strlen(implicit_relative_path));
1399 ASSERT_NE(policy_file, nullptr);
1400 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1401 fclose(policy_file);
1402 EXPECT_NE(res, 0);
1403 }
1404
TEST(FilterTest,include_extra_text)1405 TEST(FilterTest, include_extra_text) {
1406 struct sock_fprog actual;
1407 const char *extra_text = "@include /some/file: sneaky comment\n";
1408
1409 FILE *policy_file =
1410 write_policy_to_pipe(extra_text, strlen(extra_text));
1411 ASSERT_NE(policy_file, nullptr);
1412 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1413 fclose(policy_file);
1414 EXPECT_NE(res, 0);
1415 }
1416
TEST(FilterTest,include_split_filename)1417 TEST(FilterTest, include_split_filename) {
1418 struct sock_fprog actual;
1419 const char *split_filename = "@include /some/file:colon.policy\n";
1420
1421 FILE *policy_file =
1422 write_policy_to_pipe(split_filename, strlen(split_filename));
1423 ASSERT_NE(policy_file, nullptr);
1424 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1425 fclose(policy_file);
1426 EXPECT_NE(res, 0);
1427 }
1428
TEST(FilterTest,include_nonexistent_file)1429 TEST(FilterTest, include_nonexistent_file) {
1430 struct sock_fprog actual;
1431 const char *include_policy = "@include ./nonexistent.policy\n";
1432
1433 FILE *policy_file =
1434 write_policy_to_pipe(include_policy, strlen(include_policy));
1435 ASSERT_NE(policy_file, nullptr);
1436
1437 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1438 fclose(policy_file);
1439
1440 ASSERT_NE(res, 0);
1441 }
1442
1443 // TODO(jorgelo): Android unit tests don't currently support data files.
1444 // Re-enable by creating a temporary policy file at runtime.
1445 #if !defined(__ANDROID__)
1446
TEST(FilterTest,include)1447 TEST(FilterTest, include) {
1448 struct sock_fprog compiled_plain;
1449 struct sock_fprog compiled_with_include;
1450
1451 const char *policy_plain =
1452 "read: 1\n"
1453 "write: 1\n"
1454 "rt_sigreturn: 1\n"
1455 "exit: 1\n";
1456
1457 const char *policy_with_include = "@include ./test/seccomp.policy\n";
1458
1459 FILE *file_plain = write_policy_to_pipe(policy_plain, strlen(policy_plain));
1460 ASSERT_NE(file_plain, nullptr);
1461 int res_plain =
1462 compile_filter(file_plain, &compiled_plain, USE_RET_KILL, NO_LOGGING);
1463 fclose(file_plain);
1464
1465 FILE *file_with_include =
1466 write_policy_to_pipe(policy_with_include, strlen(policy_with_include));
1467 ASSERT_NE(file_with_include, nullptr);
1468 int res_with_include = compile_filter(
1469 file_with_include, &compiled_with_include, USE_RET_KILL, NO_LOGGING);
1470 fclose(file_with_include);
1471
1472 /*
1473 * Checks that filter length is the same for a plain policy and an equivalent
1474 * policy with an @include statement. Also checks that the filter generated
1475 * from the policy with an @include statement is exactly the same as one
1476 * generated from a plain policy.
1477 */
1478 ASSERT_EQ(res_plain, 0);
1479 ASSERT_EQ(res_with_include, 0);
1480
1481 EXPECT_EQ(compiled_plain.len, 13);
1482 EXPECT_EQ(compiled_with_include.len, 13);
1483
1484 EXPECT_ARCH_VALIDATION(compiled_with_include.filter);
1485 EXPECT_EQ_STMT(compiled_with_include.filter + ARCH_VALIDATION_LEN,
1486 BPF_LD + BPF_W + BPF_ABS,
1487 syscall_nr);
1488 EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 1,
1489 __NR_read);
1490 EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 3,
1491 __NR_write);
1492 EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 5,
1493 __NR_rt_sigreturn);
1494 EXPECT_ALLOW_SYSCALL(compiled_with_include.filter + ARCH_VALIDATION_LEN + 7,
1495 __NR_exit);
1496 EXPECT_EQ_STMT(compiled_with_include.filter + ARCH_VALIDATION_LEN + 9,
1497 BPF_RET + BPF_K,
1498 SECCOMP_RET_KILL);
1499
1500 free(compiled_plain.filter);
1501 free(compiled_with_include.filter);
1502 }
1503
TEST(FilterTest,include_same_syscalls)1504 TEST(FilterTest, include_same_syscalls) {
1505 struct sock_fprog actual;
1506 const char *policy =
1507 "read: 1\n"
1508 "write: 1\n"
1509 "rt_sigreturn: 1\n"
1510 "exit: 1\n"
1511 "@include ./test/seccomp.policy\n";
1512
1513 FILE *policy_file =
1514 write_policy_to_pipe(policy, strlen(policy));
1515 ASSERT_NE(policy_file, nullptr);
1516
1517 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1518 fclose(policy_file);
1519
1520 ASSERT_EQ(res, 0);
1521 EXPECT_EQ(actual.len,
1522 ARCH_VALIDATION_LEN + 1 /* load syscall nr */ +
1523 2 * 8 /* check syscalls twice */ + 1 /* filter return */);
1524 free(actual.filter);
1525 }
1526
TEST(FilterTest,include_invalid_policy)1527 TEST(FilterTest, include_invalid_policy) {
1528 struct sock_fprog actual;
1529 const char *policy =
1530 "read: 1\n"
1531 "write: 1\n"
1532 "rt_sigreturn: 1\n"
1533 "exit: 1\n"
1534 "@include ./test/invalid_syscall_name.policy\n";
1535
1536 FILE *policy_file =
1537 write_policy_to_pipe(policy, strlen(policy));
1538 ASSERT_NE(policy_file, nullptr);
1539
1540 /* Ensure the included (invalid) policy file exists. */
1541 FILE *included_file = fopen("./test/invalid_syscall_name.policy", "r");
1542 ASSERT_NE(included_file, nullptr);
1543 fclose(included_file);
1544
1545 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1546 fclose(policy_file);
1547
1548 ASSERT_NE(res, 0);
1549 }
1550
TEST(FilterTest,include_nested)1551 TEST(FilterTest, include_nested) {
1552 struct sock_fprog actual;
1553 const char *policy = "@include ./test/nested.policy\n";
1554
1555 FILE *policy_file =
1556 write_policy_to_pipe(policy, strlen(policy));
1557 ASSERT_NE(policy_file, nullptr);
1558
1559 /* Ensure the policy file exists. */
1560 FILE *included_file = fopen("./test/nested.policy", "r");
1561 ASSERT_NE(included_file, nullptr);
1562 fclose(included_file);
1563
1564 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
1565 fclose(policy_file);
1566
1567 ASSERT_NE(res, 0);
1568 }
1569
1570 #endif // !__ANDROID__
1571