From c54051101e95998b3070d5ccea46f6c7e33dfe57 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 12 Apr 2023 11:06:27 +0200 Subject: Add other comparison operation for the BPF filter --- cooker/filter.c | 141 +++++++++++++++++++++++++++++++++++------------ cooker/filter.h | 5 ++ tests/unit/Makefile | 5 +- tests/unit/test_filter.c | 10 +++- 4 files changed, 122 insertions(+), 39 deletions(-) diff --git a/cooker/filter.c b/cooker/filter.c index 9a2c9f1..a46e8ce 100644 --- a/cooker/filter.c +++ b/cooker/filter.c @@ -259,19 +259,106 @@ unsigned int create_bpf_program_log(struct sock_filter filter[]) return 4; } -static unsigned int eq_u64_filter(struct sock_filter filter[], int idx, - uint64_t v, unsigned int jtrue, - unsigned int jfalse) +static unsigned int eq(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) { - uint32_t hi = get_hi(v); - uint32_t lo = get_lo(v); + unsigned int size = 0; + uint32_t hi, lo; + + switch (entry->args[idx].type) { + case U64: + hi = get_hi((entry->args[idx]).value.v64); + lo = get_lo((entry->args[idx]).value.v64); + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)EQ(lo, 0, jfalse); + filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx)); + filter[size++] = (struct sock_filter)EQ(hi, jtrue, jfalse); + break; + case U32: + + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)EQ( + entry->args[idx].value.v32, jtrue, jfalse); + break; + } - filter[0] = (struct sock_filter)LOAD(LO_ARG(idx)); - filter[1] = (struct sock_filter)EQ(lo, 0, jfalse); - filter[2] = (struct sock_filter)LOAD(HI_ARG(idx)); - filter[3] = (struct sock_filter)EQ(hi, jtrue, jfalse); + return size; +} - return 4; +static unsigned int gt(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) +{ + unsigned int size = 0; + uint32_t hi, lo; + + switch (entry->args[idx].type) { + case U64: + hi = get_hi((entry->args[idx]).value.v64); + lo = get_lo((entry->args[idx]).value.v64); + filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx)); + filter[size++] = (struct sock_filter)GT(hi, jtrue, jfalse); + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)GT(lo, jtrue, jfalse); + break; + case U32: + + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)GT( + entry->args[idx].value.v32, jtrue, jfalse); + break; + } + + return size; +} + +static unsigned int lt(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) +{ + unsigned int size = 0; + uint32_t hi, lo; + + switch (entry->args[idx].type) { + case U64: + hi = get_hi((entry->args[idx]).value.v64); + lo = get_lo((entry->args[idx]).value.v64); + filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx)); + filter[size++] = (struct sock_filter)LT(hi, jtrue, jfalse); + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)LT(lo, jtrue, jfalse); + break; + case U32: + + filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx)); + filter[size++] = (struct sock_filter)LT( + entry->args[idx].value.v32, jtrue, jfalse); + break; + } + + return size; +} + +static unsigned int neq(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) +{ + return eq(filter, idx, entry, jfalse, jtrue); +} + +static unsigned int ge(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) +{ + return lt(filter, idx, entry, jfalse, jtrue); +} + +static unsigned int le(struct sock_filter filter[], int idx, + const struct bpf_call *entry, unsigned int jtrue, + unsigned int jfalse) +{ + return gt(filter, idx, entry, jfalse, jtrue); } unsigned int create_bfp_program(struct syscall_entry table[], @@ -284,7 +371,6 @@ unsigned int create_bfp_program(struct syscall_entry table[], unsigned int notify, accept; unsigned int i, j, k, size; unsigned int next_offset, offset; - unsigned int next_args_off; int nodes[MAX_JUMPS]; create_lookup_nodes(nodes, n_syscall); @@ -349,36 +435,21 @@ unsigned int create_bfp_program(struct syscall_entry table[], for (j = 0; j < (table[i]).count; j++) { unsigned n_checks = 0; entry = table[i].entry + j; - next_args_off = get_n_args_syscall_entry(entry); for (k = 0; k < 6; k++) { - if (entry->args[k].cmp == NO_CHECK) + switch (entry->args[k].cmp) { + case NO_CHECK: continue; - offset = next_args_off - n_checks; - switch (entry->args[k].type) { - case U64: - size += eq_u64_filter( - &filter[size], k, - entry->args[k].value.v64, 0, - offset); - n_checks++; - has_arg = true; - break; - case U32: - filter[size++] = (struct sock_filter) - LOAD((offsetof( - struct seccomp_data, - args[k]))); - filter[size++] = (struct sock_filter)EQ( - entry->args[k].value.v32, 0, - offset); - n_checks++; - has_arg = true; + case EQ: + size += eq(&filter[size], k, entry, 0, + offset); break; default: fprintf(stderr, - "value for args not recognized\n"); - return -1; + "operation not recognized\n"); + continue; } + n_checks++; + has_arg = true; } if (check_args_syscall_entry(table[i].entry)) filter[size++] = (struct sock_filter)JUMPA( diff --git a/cooker/filter.h b/cooker/filter.h index afdd0b9..2729669 100644 --- a/cooker/filter.h +++ b/cooker/filter.h @@ -27,6 +27,11 @@ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, (nr), (right), (left)) #define JUMPA(jump) BPF_JUMP(BPF_JMP | BPF_JA, (jump), 0, 0) #define EQ(x, a1, a2) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (x), (a1), (a2)) +#define NEQ(x, a1, a2) EQ((x), (a2), (a1)) +#define GT(x, a1, a2) BPF_JUMP(BPF_JMP + BPF_JGT + BPF_K, (x), (a1), (a2)) +#define GE(x, a1, a2) BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, (x), (a1), (a2)) +#define LT(x, a1, a2) GE((x), (a2), (a1)) +#define LE(x, a1, a2) GT((x), (a2), (a1)) #define LOAD(x) BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (x)) #define MAX_FILTER 1024 diff --git a/tests/unit/Makefile b/tests/unit/Makefile index fac3f68..ae9631b 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -38,7 +38,7 @@ CFLAGS += -DSEITAN_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH) -DTMP_DATA_SIZE=1000 test: test-filter test-operations test-op-call -build-filter-build: test_filter_build.c $(SRCS_FILTER_BUILD) $(HEADERS_FILTER_BUILD) +build-filter-build: test_filter_build.c $ (SRCS_FILTER_BUILD) $(HEADERS_FILTER_BUILD) $(CC) $(CFLAGS) -o filter-build $(SRCS_FILTER) \ test_filter_build.c @@ -65,3 +65,6 @@ build-operations: test_operations.c $(SRCS_OP) $(HEADERS_OP) test-operations: build-operations ./operations + +clean: + rm -f operations op-call filter filter-build diff --git a/tests/unit/test_filter.c b/tests/unit/test_filter.c index 90ffa2b..5745ba2 100644 --- a/tests/unit/test_filter.c +++ b/tests/unit/test_filter.c @@ -35,6 +35,7 @@ static int generate_install_filter(struct args_target *at) calls[0].args[i].cmp = NO_CHECK; continue; } + calls[0].args[i].cmp = at->cmp[i]; switch (at->type[i]) { case U32: calls[0].args[i].value.v32 = (uint32_t)at->args[i]; @@ -73,6 +74,7 @@ START_TEST(with_getsid) set_args_no_check(at); at->args[0] = &id; at->type[0] = U32; + at->cmp[0] = EQ; at->install_filter = generate_install_filter; setup(); mock_syscall_target(); @@ -90,8 +92,10 @@ START_TEST(with_getpriority) set_args_no_check(at); at->args[0] = &which; at->type[0] = U32; + at->cmp[0] = EQ; at->args[1] = &who; - at->type[0] = U32; + at->type[1] = U32; + at->cmp[1] = EQ; at->install_filter = generate_install_filter; setup(); mock_syscall_target(); @@ -104,7 +108,7 @@ static int target_lseek() /* Open the device on the target, but the arg0 isn't in the filter */ ck_assert_int_ge(fd, 0); - at->args[0] = fd; + at->args[0] = (void *)(long)fd; return target(); } @@ -116,7 +120,7 @@ static void test_lseek(off_t offset) at->nr = __NR_lseek; at->target = target_lseek; set_args_no_check(at); - at->args[1] = offset; + at->args[1] = (void *)offset; at->type[1] = U64; at->install_filter = generate_install_filter; setup(); -- cgit v1.2.3