From 6b1cb05624ad0f419fda5ab001ed3051273e1d4b Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Mon, 22 May 2023 10:42:27 +0200 Subject: filter: fix filter build and adjust tests Changes: - fix initialization of size - addedfew comments - finish to fix the test_filter_build tests --- cooker/filter.c | 45 ++-- tests/unit/test_filter_build.c | 498 +++++++++++++++++++---------------------- 2 files changed, 261 insertions(+), 282 deletions(-) diff --git a/cooker/filter.c b/cooker/filter.c index ef76835..77961d0 100644 --- a/cooker/filter.c +++ b/cooker/filter.c @@ -42,7 +42,6 @@ static void set_no_args(struct bpf_entry *entry) static unsigned int get_number_entries(long nr) { struct filter_call_input *call = filter_input + nr; - return call->count; } @@ -58,9 +57,9 @@ static bool has_args(long nr) { struct filter_call_input *call = filter_input + nr; - if (call-> count < 1) + if (call->count < 1) return false; - if(call-> ignore_args) + if (call->ignore_args) return false; /* Check if the first entry has some arguments */ @@ -127,7 +126,6 @@ static unsigned int get_n_args_syscall_instr(long nr) * accept */ if (has_args(nr)) total_instr++; - return total_instr; } @@ -135,7 +133,8 @@ static unsigned int get_n_args_syscall_instr(long nr) * filter_notify() - Start of notification request, check/flush previous one * @nr: System call number, -1 to just flush previous request */ -void filter_notify(long nr) { +void filter_notify(long nr) +{ struct filter_call_input *call = filter_input + nr; if (nr >= 0) { @@ -161,9 +160,8 @@ void filter_add_arg(int index, struct bpf_arg arg) call->ignore_args = true; return; } - if(call->ignore_args) + if (call->ignore_args) return; - call->entries[call->count] = index_entries; memcpy(&entry->args[index], &arg, sizeof(arg)); } @@ -200,7 +198,6 @@ static long get_syscall(unsigned int i) return (long)table[i]; } - static unsigned int count_shift_right(unsigned int n) { unsigned int i = 0; @@ -433,14 +430,21 @@ static unsigned int and_ne(struct sock_filter filter[], int idx, static unsigned int insert_args(struct sock_filter filter[], long nr) { struct filter_call_input *call = filter_input + nr; - unsigned int i, k, size, next_offset, n_checks = 0; + unsigned int next_offset, n_checks = 0; unsigned int count = get_number_entries(nr); struct bpf_entry *entry; unsigned int offset = 0; + unsigned int size = 0; + unsigned int i, k; for (i = 0; i < count; i++) { n_checks = 0; entry = &entries[call->entries[i]]; + /* If there are multiple entries for the syscall @nr, then the next group + * of arguments to check (i.e. the next offset) is after the number of + * arguments of the current entry. The next_offset is used to + * jump to the next group if the check is false. + */ next_offset = get_args_for_entry(entry); for (k = 0; k < 6; k++) { offset = next_offset - n_checks; @@ -477,6 +481,8 @@ static unsigned int insert_args(struct sock_filter filter[], long nr) } n_checks++; } + /* If there were no arguments for this entry, then we don't need + * to add the notification */ if (n_checks > 0) filter[size++] = (struct sock_filter)BPF_STMT( BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF); @@ -485,7 +491,7 @@ static unsigned int insert_args(struct sock_filter filter[], long nr) return size; } -unsigned int filter_build(struct sock_filter filter[], unsigned n) +unsigned int filter_build(struct sock_filter filter[], unsigned n) { unsigned int offset_left, offset_right; unsigned int n_nodes, notify, accept; @@ -523,11 +529,11 @@ unsigned int filter_build(struct sock_filter filter[], unsigned n) filter[size++] = (struct sock_filter)JUMPA(accept - size); } else { - nr = get_syscall(i); + nr = get_syscall(nodes[i]); offset_left = left_child(i) - i - 1; offset_right = right_child(i) - i - 1; filter[size++] = (struct sock_filter)JGE( - get_syscall(i), offset_right, offset_left); + nr, offset_right, offset_left); } } @@ -535,14 +541,17 @@ unsigned int filter_build(struct sock_filter filter[], unsigned n) /* Insert leaves */ for (i = 0; i < n; i++) { nr = get_syscall(i); - if (get_number_entries(nr) > 0) + if (get_number_entries(nr) > 0) { offset = next_offset; - else - /* If the syscall doesn't have any arguments, then notify */ + } else { + /* If the syscall doesn't have any arguments, then notify */ offset = notify - size - 1; - filter[size++] = (struct sock_filter)EQ(nr, - offset, - accept - size); + } + filter[size++] = + (struct sock_filter)EQ(nr, offset, accept - size); + /* The arguments block of the next entry are after the total + * number of the instructions for checking the arguments of the current entry + */ next_offset += get_n_args_syscall_instr(nr) - 1; } /* Seccomp accept and notify instruction */ diff --git a/tests/unit/test_filter_build.c b/tests/unit/test_filter_build.c index b4f1a2c..00d5180 100644 --- a/tests/unit/test_filter_build.c +++ b/tests/unit/test_filter_build.c @@ -100,270 +100,240 @@ START_TEST(test_single_instr_two_args) filter_write(tfilter); size = read_filter(result, tfilter); - bpf_disasm_all(result, size); ck_assert_uint_eq(size, ARRAY_SIZE(expected)); ck_assert(filter_eq(expected, result, ARRAY_SIZE(expected))); } END_TEST -//START_TEST(test_two_instr) -//{ -// unsigned int size; -// struct bpf_call calls[] = { -// { .name = "test1" }, -// { .name = "test2" }, -// }; -// struct syscall_entry table[] = { -// { .count = 1, .nr = 42, .entry = &calls[0] }, -// { .count = 1, .nr = 49, .entry = &calls[1] }, -// }; -// struct sock_filter expected[] = { -// /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, arch))), -// /* l1 */ -// BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), -// /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l3 */ -// BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, nr))), -// /* ------- level0 -------- */ -// /* l4 */ JGE(49, 1, 0), -// /* ------- leaves -------- */ -// /* l5 */ EQ(42, 2, 1), -// /* l6 */ EQ(49, 1, 0), -// /* l7 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l8 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// }; -// struct sock_filter result[30]; -// -// size = create_bfp_program(table, result, -// sizeof(table) / sizeof(table[0])); -// ck_assert_uint_eq(size, sizeof(expected) / sizeof(expected[0])); -// ck_assert(filter_eq(expected, result, -// sizeof(expected) / sizeof(expected[0]))); -//} -//END_TEST -// -//START_TEST(test_multiple_instr_no_args) -//{ -// unsigned int size; -// struct bpf_call calls[] = { -// { .name = "test1" }, { .name = "test2" }, { .name = "test3" }, -// { .name = "test4" }, { .name = "test5" }, -// }; -// struct syscall_entry table[] = { -// { .count = 1, .nr = 42, .entry = &calls[0] }, -// { .count = 1, .nr = 43, .entry = &calls[1] }, -// { .count = 1, .nr = 44, .entry = &calls[2] }, -// { .count = 1, .nr = 45, .entry = &calls[3] }, -// { .count = 1, .nr = 46, .entry = &calls[4] }, -// }; -// struct sock_filter expected[] = { -// /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, arch))), -// /* l1 */ -// BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), -// /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l3 */ -// BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, nr))), -// /* ------- level0 -------- */ -// /* l4 */ JGE(46, 1, 0), -// /* ------- level1 -------- */ -// /* l5 */ JGE(45, 2, 1), -// /* l6 */ JGE(46, 3, 2), -// /* ------- level2 -------- */ -// /* l7 */ JGE(43, 4, 3), -// /* l8 */ JGE(45, 5, 4), -// /* l9 */ JGE(46, 6, 5), -// /* l10 */ JUMPA(5), -// /* -------- leaves ------- */ -// /* l11 */ EQ(42, 5, 4), -// /* l12 */ EQ(43, 4, 3), -// /* l13 */ EQ(44, 3, 2), -// /* l14 */ EQ(45, 2, 1), -// /* l15 */ EQ(46, 1, 0), -// /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// }; -// struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; -// -// size = create_bfp_program(table, result, -// sizeof(table) / sizeof(table[0])); -// ck_assert_uint_eq(size, sizeof(expected) / sizeof(expected[0])); -// ck_assert(filter_eq(expected, result, -// sizeof(expected) / sizeof(expected[0]))); -//} -//END_TEST -// -//START_TEST(test_multiple_instr_with_args) -//{ -// unsigned int size; -// struct bpf_call calls[] = { -// { .name = "test1", -// .args = { [1] = { .cmp = EQ, -// .value = { .v32 = 123 }, -// .type = BPF_U32 }, -// [2] = { .cmp = EQ, -// .value = { .v32 = 321 }, -// .type = BPF_U32 } } }, -// { .name = "test2" }, -// { .name = "test3" }, -// { .name = "test4", -// .args = { [1] = { .cmp = EQ, -// .value = { .v32 = 123 }, -// .type = BPF_U32 }, -// [2] = { .cmp = EQ, -// .value = { .v32 = 321 }, -// .type = BPF_U32 } } }, -// { .name = "test5" }, -// }; -// struct syscall_entry table[] = { -// { .count = 1, .nr = 42, .entry = &calls[0] }, -// { .count = 1, .nr = 43, .entry = &calls[1] }, -// { .count = 1, .nr = 44, .entry = &calls[2] }, -// { .count = 1, .nr = 45, .entry = &calls[3] }, -// { .count = 1, .nr = 46, .entry = &calls[4] }, -// }; -// struct sock_filter expected[] = { -// /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, arch))), -// /* l1 */ -// BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), -// /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l3 */ -// BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, nr))), -// /* ------- level0 -------- */ -// /* l4 */ JGE(46, 1, 0), -// /* ------- level1 -------- */ -// /* l5 */ JGE(45, 2, 1), -// /* l6 */ JGE(46, 3, 2), -// /* ------- level2 -------- */ -// /* l7 */ JGE(43, 4, 3), -// /* l8 */ JGE(45, 5, 4), -// /* l9 */ JGE(46, 6, 5), -// /* l10 */ JUMPA(5), -// /* -------- leaves ------- */ -// /* l11 */ EQ(42, 6, 4), -// /* l12 */ EQ(43, 4, 3), -// /* l13 */ EQ(44, 3, 2), -// /* l14 */ EQ(45, 9, 1), -// /* l15 */ EQ(46, 1, 0), -// /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* ------- args ---------- */ -// /* l18 */ LOAD(offsetof(struct seccomp_data, args[1])), -// /* l19 */ EQ(123, 0, 2), -// /* l20 */ LOAD(offsetof(struct seccomp_data, args[2])), -// /* l21 */ EQ(321, 0, 1), -// /* l22 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l23 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* ----- end call42 ------ */ -// /* l24 */ LOAD(offsetof(struct seccomp_data, args[1])), -// /* l25 */ EQ(123, 0, 2), -// /* l26 */ LOAD(offsetof(struct seccomp_data, args[2])), -// /* l27 */ EQ(321, 0, 1), -// /* l28 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l29 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* ----- end call45 ------ */ -// }; -// struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; -// -// size = create_bfp_program(table, result, -// sizeof(table) / sizeof(table[0])); -// // bpf_disasm_all(result, size); -// ck_assert_uint_eq(size, sizeof(expected) / sizeof(expected[0])); -// ck_assert(filter_eq(expected, result, -// sizeof(expected) / sizeof(expected[0]))); -//} -//END_TEST -// -//START_TEST(test_multiple_instance_same_instr) -//{ -// unsigned int size; -// struct bpf_call calls[] = { -// { .name = "test1", -// .args = { [1] = { .cmp = EQ, -// .value = { .v32 = 123 }, -// .type = BPF_U32 } } }, -// { .name = "test1", -// .args = { [2] = { .cmp = EQ, -// .value = { .v32 = 321 }, -// .type = BPF_U32 } } }, -// { .name = "test2" }, -// { .name = "test3" }, -// { .name = "test4", -// .args = { [1] = { .cmp = EQ, -// .value = { .v32 = 123 }, -// .type = BPF_U32 } } }, -// { .name = "test4", -// .args = { [2] = { .cmp = EQ, -// .value = { .v32 = 321 }, -// .type = BPF_U32 } } }, -// { .name = "test5" }, -// }; -// struct syscall_entry table[] = { -// { .count = 2, .nr = 42, .entry = &calls[0] }, -// { .count = 1, .nr = 43, .entry = &calls[2] }, -// { .count = 1, .nr = 44, .entry = &calls[3] }, -// { .count = 2, .nr = 45, .entry = &calls[4] }, -// { .count = 1, .nr = 46, .entry = &calls[6] }, -// }; -// struct sock_filter expected[] = { -// /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, arch))), -// /* l1 */ -// BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), -// /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l3 */ -// BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -// (offsetof(struct seccomp_data, nr))), -// /* ------- level0 -------- */ -// /* l4 */ JGE(46, 1, 0), -// /* ------- level1 -------- */ -// /* l5 */ JGE(45, 2, 1), -// /* l6 */ JGE(46, 3, 2), -// /* ------- level2 -------- */ -// /* l7 */ JGE(43, 4, 3), -// /* l8 */ JGE(45, 5, 4), -// /* l9 */ JGE(46, 6, 5), -// /* l10 */ JUMPA(5), -// /* -------- leaves ------- */ -// /* l11 */ EQ(42, 6, 4), -// /* l12 */ EQ(43, 4, 3), -// /* l13 */ EQ(44, 3, 2), -// /* l14 */ EQ(45, 10, 1), -// /* l15 */ EQ(46, 1, 0), -// /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* ------- args ---------- */ -// /* l18 */ LOAD(offsetof(struct seccomp_data, args[1])), -// /* l19 */ EQ(123, 0, 1), -// /* l20 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l21 */ LOAD(offsetof(struct seccomp_data, args[2])), -// /* l22 */ EQ(321, 0, 1), -// /* l23 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l24 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* ----- end call42 ------ */ -// /* l25 */ LOAD(offsetof(struct seccomp_data, args[1])), -// /* l26 */ EQ(123, 0, 1), -// /* l27 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l28 */ LOAD(offsetof(struct seccomp_data, args[2])), -// /* l29 */ EQ(321, 0, 1), -// /* l30 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), -// /* l31 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -// /* ----- end call44 ------ */ -// }; -// struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; -// -// size = create_bfp_program(table, result, -// sizeof(table) / sizeof(table[0])); -// ck_assert_uint_eq(size, sizeof(expected) / sizeof(expected[0])); -// ck_assert(filter_eq(expected, result, -// sizeof(expected) / sizeof(expected[0]))); -//} -//END_TEST +START_TEST(test_two_instr) +{ + unsigned int size; + struct sock_filter expected[] = { + /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, arch))), + /* l1 */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), + /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l3 */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, nr))), + /* ------- level0 -------- */ + /* l4 */ JGE(49, 1, 0), + /* ------- leaves -------- */ + /* l5 */ EQ(42, 2, 1), + /* l6 */ EQ(49, 1, 0), + /* l7 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l8 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + }; + struct sock_filter result[30]; + filter_notify(42); + filter_notify(49); + + filter_write(tfilter); + size = read_filter(result, tfilter); + + ck_assert_uint_eq(size, ARRAY_SIZE(expected)); + ck_assert(filter_eq(expected, result, ARRAY_SIZE(expected))); +} +END_TEST + +START_TEST(test_multiple_instr_no_args) +{ + unsigned int size; + struct sock_filter expected[] = { + /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, arch))), + /* l1 */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), + /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l3 */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, nr))), + /* ------- level0 -------- */ + /* l4 */ JGE(46, 1, 0), + /* ------- level1 -------- */ + /* l5 */ JGE(45, 2, 1), + /* l6 */ JGE(46, 3, 2), + /* ------- level2 -------- */ + /* l7 */ JGE(43, 4, 3), + /* l8 */ JGE(45, 5, 4), + /* l9 */ JGE(46, 6, 5), + /* l10 */ JUMPA(5), + /* -------- leaves ------- */ + /* l11 */ EQ(42, 5, 4), + /* l12 */ EQ(43, 4, 3), + /* l13 */ EQ(44, 3, 2), + /* l14 */ EQ(45, 2, 1), + /* l15 */ EQ(46, 1, 0), + /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + }; + struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; + + filter_notify(42); + filter_notify(43); + filter_notify(44); + filter_notify(45); + filter_notify(46); + + filter_write(tfilter); + size = read_filter(result, tfilter); + + ck_assert_uint_eq(size, ARRAY_SIZE(expected)); + ck_assert(filter_eq(expected, result, ARRAY_SIZE(expected))); +} +END_TEST + +START_TEST(test_multiple_instr_with_args) +{ + unsigned int size; + struct bpf_arg a1 = { .cmp = EQ, + .value = { .v32 = 0x123 }, + .type = BPF_U32 }; + struct bpf_arg a2 = { .cmp = EQ, + .value = { .v32 = 0x321 }, + .type = BPF_U32 }; + struct sock_filter expected[] = { + /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, arch))), + /* l1 */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), + /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l3 */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, nr))), + /* ------- level0 -------- */ + /* l4 */ JGE(46, 1, 0), + /* ------- level1 -------- */ + /* l5 */ JGE(45, 2, 1), + /* l6 */ JGE(46, 3, 2), + /* ------- level2 -------- */ + /* l7 */ JGE(43, 4, 3), + /* l8 */ JGE(45, 5, 4), + /* l9 */ JGE(46, 6, 5), + /* l10 */ JUMPA(5), + /* -------- leaves ------- */ + /* l11 */ EQ(42, 6, 4), + /* l12 */ EQ(43, 4, 3), + /* l13 */ EQ(44, 3, 2), + /* l14 */ EQ(45, 9, 1), + /* l15 */ EQ(46, 1, 0), + /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* ------- args ---------- */ + /* l18 */ LOAD(offsetof(struct seccomp_data, args[1])), + /* l19 */ EQ(0x123, 0, 2), + /* l20 */ LOAD(offsetof(struct seccomp_data, args[2])), + /* l21 */ EQ(0x321, 0, 1), + /* l22 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l23 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* ----- end call42 ------ */ + /* l24 */ LOAD(offsetof(struct seccomp_data, args[1])), + /* l25 */ EQ(0x123, 0, 2), + /* l26 */ LOAD(offsetof(struct seccomp_data, args[2])), + /* l27 */ EQ(0x321, 0, 1), + /* l28 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l29 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* ----- end call45 ------ */ + }; + struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; + filter_notify(42); + filter_add_arg(1, a1); + filter_add_arg(2, a2); + filter_flush_args(); + filter_notify(43); + filter_notify(44); + filter_notify(45); + filter_add_arg(1, a1); + filter_add_arg(2, a2); + filter_flush_args(); + filter_notify(46); + + filter_write(tfilter); + size = read_filter(result, tfilter); + + ck_assert_uint_eq(size, ARRAY_SIZE(expected)); + ck_assert(filter_eq(expected, result, ARRAY_SIZE(expected))); +} +END_TEST + +START_TEST(test_multiple_instance_same_instr) +{ + unsigned int size; + struct bpf_arg a1 = { .cmp = EQ, + .value = { .v32 = 0x123 }, + .type = BPF_U32 }; + struct bpf_arg a2 = { .cmp = EQ, + .value = { .v32 = 0x321 }, + .type = BPF_U32 }; + struct sock_filter expected[] = { + /* l0 */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, arch))), + /* l1 */ + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 1, 0), + /* l2 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l3 */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + (offsetof(struct seccomp_data, nr))), + /* ------- level0 -------- */ + /* l4 */ JGE(46, 1, 0), + /* ------- level1 -------- */ + /* l5 */ JGE(45, 2, 1), + /* l6 */ JGE(46, 3, 2), + /* ------- level2 -------- */ + /* l7 */ JGE(43, 4, 3), + /* l8 */ JGE(45, 5, 4), + /* l9 */ JGE(46, 6, 5), + /* l10 */ JUMPA(5), + /* -------- leaves ------- */ + /* l11 */ EQ(42, 6, 4), + /* l12 */ EQ(43, 4, 3), + /* l13 */ EQ(44, 3, 2), + /* l14 */ EQ(45, 10, 1), + /* l15 */ EQ(46, 1, 0), + /* l16 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* l17 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* ------- args ---------- */ + /* l18 */ LOAD(offsetof(struct seccomp_data, args[1])), + /* l19 */ EQ(0x123, 0, 1), + /* l20 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l21 */ LOAD(offsetof(struct seccomp_data, args[2])), + /* l22 */ EQ(0x321, 0, 1), + /* l23 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l24 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* ----- end call42 ------ */ + /* l25 */ LOAD(offsetof(struct seccomp_data, args[1])), + /* l26 */ EQ(0x123, 0, 1), + /* l27 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l28 */ LOAD(offsetof(struct seccomp_data, args[2])), + /* l29 */ EQ(0x321, 0, 1), + /* l30 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), + /* l31 */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* ----- end call45 ------ */ + }; + struct sock_filter result[sizeof(expected) / sizeof(expected[0]) + 10]; + + filter_notify(42); + filter_add_arg(1, a1); + filter_flush_args(); + filter_add_arg(2, a2); + filter_flush_args(); + filter_notify(43); + filter_notify(44); + filter_notify(45); + filter_add_arg(1, a1); + filter_flush_args(); + filter_add_arg(2, a2); + filter_flush_args(); + filter_notify(46); + + filter_write(tfilter); + size = read_filter(result, tfilter); + + ck_assert_uint_eq(size, ARRAY_SIZE(expected)); + ck_assert(filter_eq(expected, result, ARRAY_SIZE(expected))); +} +END_TEST Suite *bpf_suite(void) { @@ -376,13 +346,13 @@ Suite *bpf_suite(void) tcase_add_test(tsingle_instr, test_single_instr); tcase_add_test(tsingle_instr, test_single_instr_two_args); - //tcase_add_test(tmultiple_instr, test_two_instr); - //tcase_add_test(tmultiple_instr, test_multiple_instr_no_args); - //tcase_add_test(tmultiple_instr, test_multiple_instr_with_args); - //tcase_add_test(tmultiple_instr, test_multiple_instance_same_instr); + tcase_add_test(tmultiple_instr, test_two_instr); + tcase_add_test(tmultiple_instr, test_multiple_instr_no_args); + tcase_add_test(tmultiple_instr, test_multiple_instr_with_args); + tcase_add_test(tmultiple_instr, test_multiple_instance_same_instr); suite_add_tcase(s, tsingle_instr); - //suite_add_tcase(s, tmultiple_instr); + suite_add_tcase(s, tmultiple_instr); return s; } -- cgit v1.2.3