blob: c94aa24328a3334263ef337c50905b5de1a52a73 [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>
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -040023#include <string>
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -040024
25#include "bpf.h"
26#include "syscall_filter.h"
27#include "syscall_filter_unittest_macros.h"
28#include "util.h"
29
Jorge Lucangeli Obes07459372016-10-19 15:33:31 -040030TEST(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
47TEST(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
66TEST(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
74TEST(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
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -040093/* Test that setting one BPF instruction works. */
94TEST(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
106TEST(bpf, bpf_load_arg) {
107 struct sock_filter load_arg[BPF_LOAD_ARG_LEN];
108 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
123TEST(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
142TEST(bpf, bpf_comp_jset) {
143 struct sock_filter comp_jset[BPF_COMP_LEN];
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400144 unsigned long mask = (1UL << (sizeof(unsigned long) * 8 - 1)) | O_WRONLY;
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400145 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)
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400155 EXPECT_EQ_BLOCK(
156 &comp_jset[0], BPF_JMP + BPF_JSET + BPF_K, 0x80000000, jt + 2, 0);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400157 EXPECT_EQ_STMT(&comp_jset[1], BPF_LD + BPF_MEM, 0);
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400158 EXPECT_EQ_BLOCK(&comp_jset[2], BPF_JMP + BPF_JSET + BPF_K, O_WRONLY, jt, jf);
159#endif
160}
161
162TEST(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);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400179#endif
180}
181
182TEST(bpf, bpf_arg_comp) {
183 struct sock_filter *arg_comp;
184 int op = EQ;
185 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
211TEST(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
220TEST(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
230TEST(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
Jorge Lucangeli Obes8cc9d4a2016-10-03 10:00:57 -0400241class BpfLabelTest : public ::testing::Test {
242 protected:
243 virtual void TearDown() { free_label_strings(&labels_); }
244 struct bpf_labels labels_;
245};
246
247TEST_F(BpfLabelTest, zero_length_filter) {
248 int res = bpf_resolve_jumps(&labels_, NULL, 0);
249
250 EXPECT_EQ(res, 0);
251 EXPECT_EQ(labels_.count, 0U);
252}
253
254TEST_F(BpfLabelTest, single_label) {
255 struct sock_filter test_label[1];
256
257 int id = bpf_label_id(&labels_, "test");
258 set_bpf_lbl(test_label, id);
259 int res = bpf_resolve_jumps(&labels_, test_label, 1);
260
261 EXPECT_EQ(res, 0);
262 EXPECT_EQ(labels_.count, 1U);
263}
264
265TEST_F(BpfLabelTest, repeated_label) {
266 struct sock_filter test_label[2];
267
268 int id = bpf_label_id(&labels_, "test");
269 set_bpf_lbl(&test_label[0], id);
270 set_bpf_lbl(&test_label[1], id);
271 int res = bpf_resolve_jumps(&labels_, test_label, 2);
272
273 EXPECT_EQ(res, -1);
274}
275
276TEST_F(BpfLabelTest, jump_with_no_label) {
277 struct sock_filter test_jump[1];
278
279 set_bpf_jump_lbl(test_jump, 14831);
280 int res = bpf_resolve_jumps(&labels_, test_jump, 1);
281
282 EXPECT_EQ(res, -1);
283}
284
285TEST_F(BpfLabelTest, jump_to_valid_label) {
286 struct sock_filter test_jump[2];
287
288 int id = bpf_label_id(&labels_, "test");
289 set_bpf_jump_lbl(&test_jump[0], id);
290 set_bpf_lbl(&test_jump[1], id);
291
292 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
293 EXPECT_EQ(res, 0);
294 EXPECT_EQ(labels_.count, 1U);
295}
296
297TEST_F(BpfLabelTest, jump_to_invalid_label) {
298 struct sock_filter test_jump[2];
299
300 int id = bpf_label_id(&labels_, "test");
301 set_bpf_jump_lbl(&test_jump[0], id + 1);
302 set_bpf_lbl(&test_jump[1], id);
303
304 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
305 EXPECT_EQ(res, -1);
306}
307
308TEST_F(BpfLabelTest, jump_to_unresolved_label) {
309 struct sock_filter test_jump[2];
310
311 int id = bpf_label_id(&labels_, "test");
312 /* Notice the order of the instructions is reversed. */
313 set_bpf_lbl(&test_jump[0], id);
314 set_bpf_jump_lbl(&test_jump[1], id);
315
316 int res = bpf_resolve_jumps(&labels_, test_jump, 2);
317 EXPECT_EQ(res, -1);
318}
319
320TEST_F(BpfLabelTest, too_many_labels) {
321 unsigned int i;
322 char label[20];
323
324 for (i = 0; i < BPF_LABELS_MAX; i++) {
325 snprintf(label, 20, "test%u", i);
326 (void) bpf_label_id(&labels_, label);
327 }
328 int id = bpf_label_id(&labels_, "test");
329
330 /* Insertion failed... */
331 EXPECT_EQ(id, -1);
332 /* ... because the label lookup table is full. */
333 EXPECT_EQ(labels_.count, BPF_LABELS_MAX);
334}
335
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400336class ArgFilterTest : public ::testing::Test {
337 protected:
338 virtual void TearDown() { free_label_strings(&labels_); }
339 struct bpf_labels labels_;
340};
341
342TEST_F(ArgFilterTest, arg0_equals) {
343 const char *fragment = "arg0 == 0";
344 int nr = 1;
345 unsigned int id = 0;
346 struct filter_block *block =
347 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
348
349 ASSERT_TRUE(block != NULL);
350 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
351 EXPECT_EQ(block->total_len, exp_total_len);
352
353 /* First block is a label. */
354 struct filter_block *curr_block = block;
355 ASSERT_TRUE(curr_block != NULL);
356 EXPECT_EQ(block->len, 1U);
357 EXPECT_LBL(curr_block->instrs);
358
359 /* Second block is a comparison. */
360 curr_block = block->next;
361 EXPECT_COMP(curr_block);
362
363 /* Third block is a jump and a label (end of AND group). */
364 curr_block = curr_block->next;
365 ASSERT_TRUE(curr_block != NULL);
366 EXPECT_GROUP_END(curr_block);
367
368 /* Fourth block is SECCOMP_RET_KILL. */
369 curr_block = curr_block->next;
370 ASSERT_TRUE(curr_block != NULL);
371 EXPECT_KILL(curr_block);
372
373 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
374 curr_block = curr_block->next;
375 ASSERT_TRUE(curr_block != NULL);
376 EXPECT_ALLOW(curr_block);
377
378 EXPECT_TRUE(curr_block->next == NULL);
379
380 free_block_list(block);
381}
382
383TEST_F(ArgFilterTest, arg0_mask) {
384 const char *fragment = "arg1 & O_RDWR";
385 int nr = 1;
386 unsigned int id = 0;
387 struct filter_block *block =
388 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
389
390 ASSERT_TRUE(block != NULL);
391 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
392 EXPECT_EQ(block->total_len, exp_total_len);
393
394 /* First block is a label. */
395 struct filter_block *curr_block = block;
396 ASSERT_TRUE(curr_block != NULL);
397 EXPECT_EQ(block->len, 1U);
398 EXPECT_LBL(curr_block->instrs);
399
400 /* Second block is a comparison. */
401 curr_block = block->next;
402 EXPECT_COMP(curr_block);
403
404 /* Third block is a jump and a label (end of AND group). */
405 curr_block = curr_block->next;
406 ASSERT_TRUE(curr_block != NULL);
407 EXPECT_GROUP_END(curr_block);
408
409 /* Fourth block is SECCOMP_RET_KILL. */
410 curr_block = curr_block->next;
411 ASSERT_TRUE(curr_block != NULL);
412 EXPECT_KILL(curr_block);
413
414 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
415 curr_block = curr_block->next;
416 ASSERT_TRUE(curr_block != NULL);
417 EXPECT_ALLOW(curr_block);
418
419 EXPECT_TRUE(curr_block->next == NULL);
420
421 free_block_list(block);
422}
423
Jorge Lucangeli Obesfd6f8e32016-10-12 11:19:28 -0400424TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
425 const char *fragment = "arg0 in O_RDONLY|O_CREAT";
426 int nr = 1;
427 unsigned int id = 0;
428 struct filter_block *block =
429 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
430
431 ASSERT_NE(block, nullptr);
432 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
433 EXPECT_EQ(block->total_len, exp_total_len);
434
435 /* First block is a label. */
436 struct filter_block *curr_block = block;
437 ASSERT_NE(curr_block, nullptr);
438 EXPECT_EQ(block->len, 1U);
439 EXPECT_LBL(curr_block->instrs);
440
441 /* Second block is a comparison. */
442 curr_block = block->next;
443 ASSERT_NE(curr_block, nullptr);
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
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400466TEST_F(ArgFilterTest, arg0_eq_mask) {
467 const char *fragment = "arg1 == O_WRONLY|O_CREAT";
468 int nr = 1;
469 unsigned int id = 0;
470
471 struct filter_block *block =
472 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
473
474 ASSERT_TRUE(block != NULL);
475 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
476 EXPECT_EQ(block->total_len, exp_total_len);
477
478 /* First block is a label. */
479 struct filter_block *curr_block = block;
480 ASSERT_TRUE(curr_block != NULL);
481 EXPECT_EQ(block->len, 1U);
482 EXPECT_LBL(curr_block->instrs);
483
484 /* Second block is a comparison. */
485 curr_block = block->next;
486 ASSERT_TRUE(curr_block != NULL);
487 EXPECT_COMP(curr_block);
488 EXPECT_EQ(curr_block->instrs[BPF_ARG_COMP_LEN - 1].k,
489 (unsigned int)(O_WRONLY | O_CREAT));
490
491 /* Third block is a jump and a label (end of AND group). */
492 curr_block = curr_block->next;
493 ASSERT_TRUE(curr_block != NULL);
494 EXPECT_GROUP_END(curr_block);
495
496 /* Fourth block is SECCOMP_RET_KILL. */
497 curr_block = curr_block->next;
498 ASSERT_TRUE(curr_block != NULL);
499 EXPECT_KILL(curr_block);
500
501 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
502 curr_block = curr_block->next;
503 ASSERT_TRUE(curr_block != NULL);
504 EXPECT_ALLOW(curr_block);
505
506 EXPECT_TRUE(curr_block->next == NULL);
507
508 free_block_list(block);
509}
510
511TEST_F(ArgFilterTest, and_or) {
512 const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
513 int nr = 1;
514 unsigned int id = 0;
515
516 struct filter_block *block =
517 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
518 ASSERT_TRUE(block != NULL);
519 size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
520 EXPECT_EQ(block->total_len, exp_total_len);
521
522 /* First block is a label. */
523 struct filter_block *curr_block = block;
524 ASSERT_TRUE(curr_block != NULL);
525 EXPECT_EQ(block->len, 1U);
526 EXPECT_LBL(curr_block->instrs);
527
528 /* Second block is a comparison ("arg0 == 0"). */
529 curr_block = curr_block->next;
530 ASSERT_TRUE(curr_block != NULL);
531 EXPECT_COMP(curr_block);
532
533 /* Third block is a comparison ("arg1 == 0"). */
534 curr_block = curr_block->next;
535 ASSERT_TRUE(curr_block != NULL);
536 EXPECT_COMP(curr_block);
537
538 /* Fourth block is a jump and a label (end of AND group). */
539 curr_block = curr_block->next;
540 ASSERT_TRUE(curr_block != NULL);
541 EXPECT_GROUP_END(curr_block);
542
543 /* Fifth block is a comparison ("arg0 == 1"). */
544 curr_block = curr_block->next;
545 ASSERT_TRUE(curr_block != NULL);
546 EXPECT_COMP(curr_block);
547
548 /* Sixth block is a jump and a label (end of AND group). */
549 curr_block = curr_block->next;
550 ASSERT_TRUE(curr_block != NULL);
551 EXPECT_GROUP_END(curr_block);
552
553 /* Seventh block is SECCOMP_RET_KILL. */
554 curr_block = curr_block->next;
555 ASSERT_TRUE(curr_block != NULL);
556 EXPECT_KILL(curr_block);
557
558 /* Eigth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
559 curr_block = curr_block->next;
560 ASSERT_TRUE(curr_block != NULL);
561 EXPECT_ALLOW(curr_block);
562
563 EXPECT_TRUE(curr_block->next == NULL);
564
565 free_block_list(block);
566}
567
568TEST_F(ArgFilterTest, ret_errno) {
569 const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
570 int nr = 1;
571 unsigned int id = 0;
572
573 struct filter_block *block =
574 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
575 ASSERT_TRUE(block != NULL);
576 size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
577 EXPECT_EQ(block->total_len, exp_total_len);
578
579 /* First block is a label. */
580 struct filter_block *curr_block = block;
581 ASSERT_TRUE(curr_block != NULL);
582 EXPECT_EQ(block->len, 1U);
583 EXPECT_LBL(curr_block->instrs);
584
585 /* Second block is a comparison ("arg0 == 0"). */
586 curr_block = curr_block->next;
587 ASSERT_TRUE(curr_block != NULL);
588 EXPECT_COMP(curr_block);
589
590 /* Third block is a jump and a label (end of AND group). */
591 curr_block = curr_block->next;
592 ASSERT_TRUE(curr_block != NULL);
593 EXPECT_GROUP_END(curr_block);
594
595 /* Fourth block is a comparison ("arg0 == 1"). */
596 curr_block = curr_block->next;
597 ASSERT_TRUE(curr_block != NULL);
598 EXPECT_COMP(curr_block);
599
600 /* Fifth block is a jump and a label (end of AND group). */
601 curr_block = curr_block->next;
602 ASSERT_TRUE(curr_block != NULL);
603 EXPECT_GROUP_END(curr_block);
604
605 /* Sixth block is SECCOMP_RET_ERRNO. */
606 curr_block = curr_block->next;
607 ASSERT_TRUE(curr_block != NULL);
608 EXPECT_EQ(curr_block->len, 1U);
609 EXPECT_EQ_STMT(curr_block->instrs,
610 BPF_RET + BPF_K,
611 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
612
613 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
614 curr_block = curr_block->next;
615 ASSERT_TRUE(curr_block != NULL);
616 EXPECT_ALLOW(curr_block);
617
618 EXPECT_TRUE(curr_block->next == NULL);
619
620 free_block_list(block);
621}
622
623TEST_F(ArgFilterTest, unconditional_errno) {
624 const char *fragment = "return 1";
625 int nr = 1;
626 unsigned int id = 0;
627
628 struct filter_block *block =
629 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
630 ASSERT_TRUE(block != NULL);
631 size_t exp_total_len = 2;
632 EXPECT_EQ(block->total_len, exp_total_len);
633
634 /* First block is a label. */
635 struct filter_block *curr_block = block;
636 ASSERT_TRUE(curr_block != NULL);
637 EXPECT_EQ(block->len, 1U);
638 EXPECT_LBL(curr_block->instrs);
639
640 /* Second block is SECCOMP_RET_ERRNO. */
641 curr_block = curr_block->next;
642 ASSERT_TRUE(curr_block != NULL);
643 EXPECT_EQ(curr_block->len, 1U);
644 EXPECT_EQ_STMT(curr_block->instrs,
645 BPF_RET + BPF_K,
646 SECCOMP_RET_ERRNO | (1 & SECCOMP_RET_DATA));
647
648 EXPECT_TRUE(curr_block->next == NULL);
649
650 free_block_list(block);
651}
652
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400653TEST_F(ArgFilterTest, invalid_arg_number) {
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400654 const char *fragment = "argnn == 0";
655 int nr = 1;
656 unsigned int id = 0;
657
658 struct filter_block *block =
659 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400660 ASSERT_EQ(block, nullptr);
661}
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400662
Jorge Lucangeli Obes53895402016-10-18 12:02:58 -0400663TEST_F(ArgFilterTest, invalid_constant) {
664 const char *fragment = "arg0 == INVALIDCONSTANT";
665 int nr = 1;
666 unsigned int id = 0;
667
668 struct filter_block* block =
669 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
670 ASSERT_EQ(block, nullptr);
671}
672
673TEST_F(ArgFilterTest, invalid_errno) {
674 const char *fragment = "arg0 == 0 && arg1 == 1; return errno";
675 int nr = 1;
676 unsigned int id = 0;
677
678 struct filter_block *block =
679 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
680 ASSERT_EQ(block, nullptr);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400681}
682
683TEST_F(ArgFilterTest, log_no_ret_error) {
684 const char *fragment = "arg0 == 0";
685 int nr = 1;
686 unsigned int id = 0;
687 struct filter_block *block =
688 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
689
690 ASSERT_TRUE(block != NULL);
691 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
692 EXPECT_EQ(block->total_len, exp_total_len);
693
694 /* First block is a label. */
695 struct filter_block *curr_block = block;
696 ASSERT_TRUE(curr_block != NULL);
697 EXPECT_EQ(block->len, 1U);
698 EXPECT_LBL(curr_block->instrs);
699
700 /* Second block is a comparison. */
701 curr_block = block->next;
702 ASSERT_TRUE(curr_block != NULL);
703 EXPECT_COMP(curr_block);
704
705 /* Third block is a jump and a label (end of AND group). */
706 curr_block = curr_block->next;
707 ASSERT_TRUE(curr_block != NULL);
708 EXPECT_GROUP_END(curr_block);
709
710 /* Fourth block is SECCOMP_RET_TRAP, with no errno. */
711 curr_block = curr_block->next;
712 ASSERT_TRUE(curr_block != NULL);
713 EXPECT_TRAP(curr_block);
714
715 /* Fifth block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
716 curr_block = curr_block->next;
717 ASSERT_TRUE(curr_block != NULL);
718 EXPECT_ALLOW(curr_block);
719
720 EXPECT_TRUE(curr_block->next == NULL);
721
722 free_block_list(block);
723}
724
725TEST_F(ArgFilterTest, log_bad_ret_error) {
726 const char *fragment = "arg0 == 0; return";
727 int nr = 1;
728 unsigned int id = 0;
729
730 struct filter_block *block =
731 compile_section(nr, fragment, id, &labels_, NO_LOGGING);
732 ASSERT_TRUE(block != NULL);
733 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
734 EXPECT_EQ(block->total_len, exp_total_len);
735
736 /* First block is a label. */
737 struct filter_block *curr_block = block;
738 ASSERT_TRUE(curr_block != NULL);
739 EXPECT_EQ(block->len, 1U);
740 EXPECT_LBL(curr_block->instrs);
741
742 /* Second block is a comparison ("arg0 == 0"). */
743 curr_block = curr_block->next;
744 ASSERT_TRUE(curr_block != NULL);
745 EXPECT_COMP(curr_block);
746
747 /* Third block is a jump and a label (end of AND group). */
748 curr_block = curr_block->next;
749 ASSERT_TRUE(curr_block != NULL);
750 EXPECT_GROUP_END(curr_block);
751
752 /*
753 * Sixth block is NOT SECCOMP_RET_ERRNO, it should be SECCOMP_RET_KILL.
754 */
755 curr_block = curr_block->next;
756 ASSERT_TRUE(curr_block != NULL);
757 EXPECT_KILL(curr_block);
758
759 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
760 curr_block = curr_block->next;
761 ASSERT_TRUE(curr_block != NULL);
762 EXPECT_ALLOW(curr_block);
763
764 EXPECT_TRUE(curr_block->next == NULL);
765
766 free_block_list(block);
767}
768
769TEST_F(ArgFilterTest, no_log_bad_ret_error) {
770 const char *fragment = "arg0 == 0; return";
771 int nr = 1;
772 unsigned int id = 0;
773
774 struct filter_block *block =
775 compile_section(nr, fragment, id, &labels_, USE_LOGGING);
776 ASSERT_TRUE(block != NULL);
777 size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
778 EXPECT_EQ(block->total_len, exp_total_len);
779
780 /* First block is a label. */
781 struct filter_block *curr_block = block;
782 ASSERT_TRUE(curr_block != NULL);
783 EXPECT_EQ(block->len, 1U);
784 EXPECT_LBL(curr_block->instrs);
785
786 /* Second block is a comparison ("arg0 == 0"). */
787 curr_block = curr_block->next;
788 ASSERT_TRUE(curr_block != NULL);
789 EXPECT_COMP(curr_block);
790
791 /* Third block is a jump and a label (end of AND group). */
792 curr_block = curr_block->next;
793 ASSERT_TRUE(curr_block != NULL);
794 EXPECT_GROUP_END(curr_block);
795
796 /*
797 * Sixth block is *not* SECCOMP_RET_ERRNO, it should be
798 * SECCOMP_RET_TRAP.
799 */
800 curr_block = curr_block->next;
801 ASSERT_TRUE(curr_block != NULL);
802 EXPECT_TRAP(curr_block);
803
804 /* Seventh block is "SUCCESS" label and SECCOMP_RET_ALLOW. */
805 curr_block = curr_block->next;
806 ASSERT_TRUE(curr_block != NULL);
807 EXPECT_ALLOW(curr_block);
808
809 EXPECT_TRUE(curr_block->next == NULL);
810
811 free_block_list(block);
812}
813
814FILE *write_policy_to_pipe(const char *policy, size_t len) {
815 int pipefd[2];
816 if (pipe(pipefd) == -1) {
817 pwarn("pipe(pipefd) failed");
818 return NULL;
819 }
820
821 size_t i = 0;
822 unsigned int attempts = 0;
823 ssize_t ret;
824 while (i < len) {
825 ret = write(pipefd[1], &policy[i], len - i);
826 if (ret == -1) {
827 close(pipefd[0]);
828 close(pipefd[1]);
829 return NULL;
830 }
831
832 /* If we write 0 bytes three times in a row, fail. */
833 if (ret == 0) {
834 if (++attempts >= 3) {
835 close(pipefd[0]);
836 close(pipefd[1]);
837 warn("write() returned 0 three times in a row");
838 return NULL;
839 }
840 continue;
841 }
842
843 attempts = 0;
844 i += (size_t)ret;
845 }
846
847 close(pipefd[1]);
848 return fdopen(pipefd[0], "r");
849}
850
851TEST(FilterTest, seccomp_mode1) {
852 struct sock_fprog actual;
853 const char *policy =
854 "read: 1\n"
855 "write: 1\n"
856 "rt_sigreturn: 1\n"
857 "exit: 1\n";
858
859 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
860 ASSERT_TRUE(policy_file != NULL);
861
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400862 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400863 fclose(policy_file);
864
865 /*
866 * Checks return value, filter length, and that the filter
867 * validates arch, loads syscall number, and
868 * only allows expected syscalls.
869 */
870 ASSERT_EQ(res, 0);
871 EXPECT_EQ(actual.len, 13);
872 EXPECT_ARCH_VALIDATION(actual.filter);
873 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
874 BPF_LD + BPF_W + BPF_ABS,
875 syscall_nr);
876 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read);
877 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3, __NR_write);
878 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
879 __NR_rt_sigreturn);
880 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
881 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
882 BPF_RET + BPF_K,
883 SECCOMP_RET_KILL);
884
885 free(actual.filter);
886}
887
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400888TEST(FilterTest, seccomp_mode1_trap) {
889 struct sock_fprog actual;
890 const char *policy =
891 "read: 1\n"
892 "write: 1\n"
893 "rt_sigreturn: 1\n"
894 "exit: 1\n";
895
896 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
897 ASSERT_TRUE(policy_file != NULL);
898
899 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
900 fclose(policy_file);
901
902 /*
903 * Checks return value, filter length, and that the filter
904 * validates arch, loads syscall number, and
905 * only allows expected syscalls.
906 */
907 ASSERT_EQ(res, 0);
908 EXPECT_EQ(actual.len, 13);
909 EXPECT_ARCH_VALIDATION(actual.filter);
910 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
911 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
912 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 1,
913 __NR_read);
914 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 3,
915 __NR_write);
916 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
917 __NR_rt_sigreturn);
918 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7,
919 __NR_exit);
920 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9, BPF_RET+BPF_K,
921 SECCOMP_RET_TRAP);
922
923 free(actual.filter);
924}
925
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400926TEST(FilterTest, seccomp_read_write) {
927 struct sock_fprog actual;
928 const char *policy =
929 "read: arg0 == 0\n"
930 "write: arg0 == 1 || arg0 == 2\n"
931 "rt_sigreturn: 1\n"
932 "exit: 1\n";
933
934 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
935 ASSERT_TRUE(policy_file != NULL);
936
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400937 int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400938 fclose(policy_file);
939
940 /*
941 * Checks return value, filter length, and that the filter
942 * validates arch, loads syscall number, and
943 * only allows expected syscalls, jumping to correct arg filter
944 * offsets.
945 */
946 ASSERT_EQ(res, 0);
947 size_t exp_total_len = 27 + 3 * (BPF_ARG_COMP_LEN + 1);
948 EXPECT_EQ(actual.len, exp_total_len);
949
950 EXPECT_ARCH_VALIDATION(actual.filter);
951 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
952 BPF_LD + BPF_W + BPF_ABS,
953 syscall_nr);
954 EXPECT_ALLOW_SYSCALL_ARGS(
955 actual.filter + ARCH_VALIDATION_LEN + 1, __NR_read, 7, 0, 0);
956 EXPECT_ALLOW_SYSCALL_ARGS(actual.filter + ARCH_VALIDATION_LEN + 3,
957 __NR_write,
958 12 + BPF_ARG_COMP_LEN,
959 0,
960 0);
961 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 5,
962 __NR_rt_sigreturn);
963 EXPECT_ALLOW_SYSCALL(actual.filter + ARCH_VALIDATION_LEN + 7, __NR_exit);
964 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN + 9,
965 BPF_RET + BPF_K,
966 SECCOMP_RET_KILL);
967
968 free(actual.filter);
969}
970
971TEST(FilterTest, invalid_name) {
972 struct sock_fprog actual;
973 const char *policy = "notasyscall: 1\n";
974
975 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
976 ASSERT_TRUE(policy_file != NULL);
977
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400978 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400979 fclose(policy_file);
980 ASSERT_NE(res, 0);
981}
982
983TEST(FilterTest, invalid_arg) {
984 struct sock_fprog actual;
985 const char *policy = "open: argnn ==\n";
986
987 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
988 ASSERT_TRUE(policy_file != NULL);
989
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400990 int res = compile_filter(policy_file, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400991 fclose(policy_file);
992 ASSERT_NE(res, 0);
993}
994
995TEST(FilterTest, nonexistent) {
996 struct sock_fprog actual;
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -0400997 int res = compile_filter(NULL, &actual, 0, NO_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -0400998 ASSERT_NE(res, 0);
999}
1000
1001TEST(FilterTest, log) {
1002 struct sock_fprog actual;
1003 const char *policy =
1004 "read: 1\n"
1005 "write: 1\n"
1006 "rt_sigreturn: 1\n"
1007 "exit: 1\n";
1008
1009 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1010 ASSERT_TRUE(policy_file != NULL);
1011
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -04001012 int res = compile_filter(policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
Jorge Lucangeli Obes106d97f2016-08-19 12:34:02 -04001013 fclose(policy_file);
1014
1015 size_t i;
1016 size_t index = 0;
1017 /*
1018 * Checks return value, filter length, and that the filter
1019 * validates arch, loads syscall number, only allows expected syscalls,
1020 * and returns TRAP on failure.
1021 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
1022 * for logging.
1023 */
1024 ASSERT_EQ(res, 0);
1025 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
1026 EXPECT_ARCH_VALIDATION(actual.filter);
1027 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1028 BPF_LD + BPF_W + BPF_ABS,
1029 syscall_nr);
1030
1031 index = ARCH_VALIDATION_LEN + 1;
1032 for (i = 0; i < log_syscalls_len; i++)
1033 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
1034 lookup_syscall(log_syscalls[i]));
1035
1036 index += 2 * log_syscalls_len;
1037
1038 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
1039 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
1040 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
1041 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
1042 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET + BPF_K, SECCOMP_RET_TRAP);
1043
1044 free(actual.filter);
1045}
Jorge Lucangeli Obes713f6fb2016-10-03 13:03:25 -04001046
1047TEST(FilterTest, allow_log_but_kill) {
1048 struct sock_fprog actual;
1049 const char *policy =
1050 "read: 1\n"
1051 "write: 1\n"
1052 "rt_sigreturn: 1\n"
1053 "exit: 1\n";
1054
1055 FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
1056 ASSERT_TRUE(policy_file != NULL);
1057
1058 int res = compile_filter(policy_file, &actual, USE_RET_KILL, USE_LOGGING);
1059 fclose(policy_file);
1060
1061 size_t i;
1062 size_t index = 0;
1063 /*
1064 * Checks return value, filter length, and that the filter
1065 * validates arch, loads syscall number, only allows expected syscalls,
1066 * and returns TRAP on failure.
1067 * NOTE(jorgelo): the filter is longer since we add the syscalls needed
1068 * for logging.
1069 */
1070 ASSERT_EQ(res, 0);
1071 EXPECT_EQ(actual.len, 13 + 2 * log_syscalls_len);
1072 EXPECT_ARCH_VALIDATION(actual.filter);
1073 EXPECT_EQ_STMT(actual.filter + ARCH_VALIDATION_LEN,
1074 BPF_LD+BPF_W+BPF_ABS, syscall_nr);
1075
1076 index = ARCH_VALIDATION_LEN + 1;
1077 for (i = 0; i < log_syscalls_len; i++)
1078 EXPECT_ALLOW_SYSCALL(actual.filter + (index + 2 * i),
1079 lookup_syscall(log_syscalls[i]));
1080
1081 index += 2 * log_syscalls_len;
1082
1083 EXPECT_ALLOW_SYSCALL(actual.filter + index, __NR_read);
1084 EXPECT_ALLOW_SYSCALL(actual.filter + index + 2, __NR_write);
1085 EXPECT_ALLOW_SYSCALL(actual.filter + index + 4, __NR_rt_sigreturn);
1086 EXPECT_ALLOW_SYSCALL(actual.filter + index + 6, __NR_exit);
1087 EXPECT_EQ_STMT(actual.filter + index + 8, BPF_RET+BPF_K,
1088 SECCOMP_RET_KILL);
1089
1090 free(actual.filter);
1091}