aboutgitcodelistschat:MatrixIRC
path: root/cooker/filter.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2023-05-16 03:19:01 +0200
committerStefano Brivio <sbrivio@redhat.com>2023-05-16 07:20:25 +0200
commit7ab2bda2e69d4a862572be4b5e389a6aa864470d (patch)
treefa9653204a4ab9581b76499c95d76d16d467301d /cooker/filter.c
parent049bd1ca828da835f2903b88adcf9ce0bdacd6e4 (diff)
downloadseitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar.gz
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar.bz2
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar.lz
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar.xz
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.tar.zst
seitan-7ab2bda2e69d4a862572be4b5e389a6aa864470d.zip
cooker, seitan: Now with 100% more gluten
Pseudorandom changes and progress around cooker and seitan: - cooker: - rename matching functions, split match.c - fix up SELECT semantics - add some form of handling for all syscalls in the example (some stubs) - OP_CMP for all basic and compound types except for flags - link jumps to next block and next match - completed implementation of tags - gluten write - filter clean-ups, write filters (probably not working) - seitan: - load gluten and source instructions and data from there $ ./seitan-cooker cooker/example.hjson example.gluten example.bpf Parsing block 0 Parsing match 0: connect Found description for connect 0: OP_NR: if syscall number is not 0, jump to next block Parsing match argument fd setting tag reference 'fd' tag 'fd' now refers to seccomp data at 0 Parsing match argument addr allocating 128 at offset 0 1: OP_LOAD: #0 < args[1] (size: 128) C#0: (INT) 1 2: OP_CMP: if temporary data: #0 NE (size: 4) read-only data: #0, jump to next block C#4: (STRING:24) /var/run/pr-helper.sock 3: OP_CMP: if temporary data: #0 NE (size: 24) read-only data: #4, jump to next block Linking match... Linking block... linked jump of instruction #0 to #4 linked jump of instruction #2 to #4 linked jump of instruction #3 to #4 Parsing block 1 Parsing match 0: ioctl Found description for ioctl 4: OP_NR: if syscall number is not 112, jump to next block Parsing match argument path Parsing match argument request C#28: (INT) 1074025674 5: OP_CMP: if seccomp data: #1 NE (size: 4) read-only data: #28, jump to next block Parsing match argument ifr allocating 40 at offset 128 6: OP_LOAD: #128 < args[2] (size: 40) C#32: (STRING:5) tap0 7: OP_CMP: if temporary data: #128 NE (size: 5) read-only data: #32, jump to next block C#37: (INT) 1 8: OP_CMP: if temporary data: #128 NE (size: 4) read-only data: #37, jump to next block Linking match... Linking block... linked jump of instruction #4 to #9 linked jump of instruction #5 to #9 linked jump of instruction #7 to #9 linked jump of instruction #8 to #9 Parsing block 2 Parsing match 0: unshare Found description for unshare 9: OP_NR: if syscall number is not 164, jump to next block Parsing match argument flags Linking match... Linking block... linked jump of instruction #9 to #10 Parsing block 3 Parsing match 0: unshare Found description for unshare 10: OP_NR: if syscall number is not 164, jump to next block Parsing match argument flags Linking match... Linking block... linked jump of instruction #10 to #11 Parsing block 4 Parsing match 0: mknod Found description for mknod 11: OP_NR: if syscall number is not 164, jump to next block Parsing match argument path allocating 1 at offset 168 12: OP_LOAD: #168 < args[0] (size: 1) setting tag reference 'path' tag 'path' now refers to temporary data at 168 Parsing match argument mode Parsing match argument major Parsing match argument minor setting tag reference 'minor' tag 'minor' now refers to seccomp data at 2 Linking match... Linking block... linked jump of instruction #11 to #13 Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'cooker/filter.c')
-rw-r--r--cooker/filter.c388
1 files changed, 200 insertions, 188 deletions
diff --git a/cooker/filter.c b/cooker/filter.c
index 0539e42..9476089 100644
--- a/cooker/filter.c
+++ b/cooker/filter.c
@@ -12,29 +12,13 @@
#include <string.h>
#include <unistd.h>
-#include "numbers.h"
#include "filter.h"
#include "util.h"
-#define N_SYSCALL sizeof(numbers) / sizeof(numbers[0])
-
-static int compare_key(const void *key, const void *base)
-{
- return strcmp((const char *)key,
- ((struct syscall_numbers *)base)->name);
-}
-
-int compare_bpf_call_names(const void *a, const void *b)
-{
- return strcmp(((struct bpf_call *)a)->name,
- ((struct bpf_call *)b)->name);
-}
-
-static int compare_table_nr(const void *a, const void *b)
-{
- return (((struct syscall_entry *)a)->nr -
- ((struct syscall_entry *)b)->nr);
-}
+struct notify {
+ long nr;
+ struct bpf_arg arg[6];
+} notify_call[512];
static unsigned int count_shift_right(unsigned int n)
{
@@ -104,102 +88,50 @@ void create_lookup_nodes(int jumps[], unsigned int n)
}
}
-long resolve_syscall_nr(const char *name)
-{
- struct syscall_numbers *p;
- p = (struct syscall_numbers *)bsearch(
- name, numbers, sizeof(numbers) / sizeof(numbers[0]),
- sizeof(numbers[0]), compare_key);
- if (p == NULL)
- return -1;
- return p->number;
-}
-
-/*
- * Construct a syscall tables ordered by increasing syscall number
- * @returns number of syscall entries in the table
- */
-int construct_table(const struct bpf_call *entries, int n,
- struct syscall_entry *table)
-{
- long nr;
- unsigned int tn;
- int i;
-
- tn = 0;
- for (i = 0; i < n; i++) {
- table[i].count = 0;
- table[i].entry = NULL;
- }
-
- for (i = 0; i < n; i++) {
- if (tn > N_SYSCALL - 1)
- return -1;
- if (i > 0) {
- if (strcmp((entries[i]).name, (entries[i - 1]).name) ==
- 0) {
- table[tn - 1].count++;
- continue;
- }
- }
- nr = resolve_syscall_nr((entries[i]).name);
- if (nr < 0) {
- fprintf(stderr, "wrong syscall number for %s\n",
- (entries[i]).name);
- continue;
- }
- table[tn].entry = &entries[i];
- table[tn].count++;
- table[tn].nr = nr;
- tn++;
- }
- qsort(table, tn, sizeof(struct syscall_entry), compare_table_nr);
-
- return tn;
-}
-
-static unsigned get_n_args_syscall_entry(const struct bpf_call *entry)
+static unsigned get_n_args_syscall_entry(const struct notify *entry)
{
unsigned i, n = 0;
for (i = 0; i < 6; i++)
- if (entry->args[i].cmp != NO_CHECK)
+ if (entry->arg[i].cmp != NO_CHECK)
n++;
return n;
}
-static unsigned int get_n_args_syscall_instr(const struct syscall_entry *table)
+static unsigned int get_n_args_syscall_instr(const struct notify *table,
+ int len)
{
- const struct bpf_call *entry;
+ const struct notify *entry;
bool has_arg = false;
unsigned n = 0, total_instr = 0;
+ int i;
- for (unsigned int i = 0; i < table->count; i++) {
- entry = table->entry + i;
+ for (i = 0; i < len; i++) {
+ entry = table + i;
n = 0;
for (unsigned int k = 0; k < 6; k++) {
- if (entry->args[k].cmp == NO_CHECK)
+ if (entry->arg[k].cmp == NO_CHECK)
continue;
- switch (entry->args[k].type) {
- case U32:
+ switch (entry->arg[k].type) {
+ case BPF_U32:
/* For 32 bit arguments
* comparison instructions (2):
* 1 loading the value + 1 for evaluation
* arithemtic instructions (3):
* 1 loading the value + 1 for the operation + 1 for evaluation
*/
- if (entry->args[k].cmp == AND_EQ ||
- entry->args[k].cmp == AND_NE)
+ if (entry->arg[k].cmp == AND_EQ ||
+ entry->arg[k].cmp == AND_NE)
n += 3;
else
n += 2;
break;
- case U64:
+ case BPF_U64:
/* For 64 bit arguments: 32 instructions * 2
* for loading and evaluating the high and low 32 bits chuncks.
*/
- if (entry->args[k].cmp == AND_EQ ||
- entry->args[k].cmp == AND_NE)
+ if (entry->arg[k].cmp == AND_EQ ||
+ entry->arg[k].cmp == AND_NE)
n += 6;
else
n += 4;
@@ -222,44 +154,34 @@ static unsigned int get_n_args_syscall_instr(const struct syscall_entry *table)
return total_instr;
}
-static bool check_args_syscall_entry(const struct bpf_call *entry){
- return entry->args[0].cmp != NO_CHECK ||
- entry->args[1].cmp != NO_CHECK ||
- entry->args[2].cmp != NO_CHECK ||
- entry->args[3].cmp != NO_CHECK ||
- entry->args[4].cmp != NO_CHECK || entry->args[5].cmp != NO_CHECK;
-}
-
-static bool check_args_syscall(const struct syscall_entry *table)
-{
- for (unsigned int i = 0; i < table->count; i++) {
- if (check_args_syscall_entry(table->entry + i))
- return true;
- }
- return false;
+static bool check_args_syscall_entry(const struct notify *entry){
+ return entry->arg[0].cmp != NO_CHECK ||
+ entry->arg[1].cmp != NO_CHECK ||
+ entry->arg[2].cmp != NO_CHECK ||
+ entry->arg[3].cmp != NO_CHECK ||
+ entry->arg[4].cmp != NO_CHECK || entry->arg[5].cmp != NO_CHECK;
}
static unsigned int eq(struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *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);
+ switch (entry->arg[idx].type) {
+ case BPF_U64:
+ hi = get_hi((entry->arg[idx]).value.v64);
+ lo = get_lo((entry->arg[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:
-
+ case BPF_U32:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)EQ(
- entry->args[idx].value.v32, jtrue, jfalse);
+ entry->arg[idx].value.v32, jtrue, jfalse);
break;
}
@@ -267,26 +189,25 @@ static unsigned int eq(struct sock_filter filter[], int idx,
}
static unsigned int gt(struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *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);
+ switch (entry->arg[idx].type) {
+ case BPF_U64:
+ hi = get_hi((entry->arg[idx]).value.v64);
+ lo = get_lo((entry->arg[idx]).value.v64);
filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx));
filter[size++] = (struct sock_filter)GT(hi, jtrue + 2, 0);
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)GT(lo, jtrue, jfalse);
break;
- case U32:
-
+ case BPF_U32:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)GT(
- entry->args[idx].value.v32, jtrue, jfalse);
+ entry->arg[idx].value.v32, jtrue, jfalse);
break;
}
@@ -294,26 +215,25 @@ static unsigned int gt(struct sock_filter filter[], int idx,
}
static unsigned int lt(struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *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);
+ switch (entry->arg[idx].type) {
+ case BPF_U64:
+ hi = get_hi((entry->arg[idx]).value.v64);
+ lo = get_lo((entry->arg[idx]).value.v64);
filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx));
filter[size++] = (struct sock_filter)LT(hi, jtrue + 2, jfalse);
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)LT(lo, jtrue, jfalse);
break;
- case U32:
-
+ case BPF_U32:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)LT(
- entry->args[idx].value.v32, jtrue, jfalse);
+ entry->arg[idx].value.v32, jtrue, jfalse);
break;
}
@@ -321,52 +241,51 @@ static unsigned int lt(struct sock_filter filter[], int idx,
}
static unsigned int neq(struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *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,
+ const struct notify *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,
+ const struct notify *entry, unsigned int jtrue,
unsigned int jfalse)
{
return gt(filter, idx, entry, jfalse, jtrue);
}
static unsigned int and_eq (struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *entry, unsigned int jtrue,
unsigned int jfalse)
{
unsigned int size = 0;
- switch (entry->args[idx].type) {
- case U64:
+ switch (entry->arg[idx].type) {
+ case BPF_U64:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)AND(
- get_lo(entry->args[idx].op2.v64));
+ get_lo(entry->arg[idx].op2.v64));
filter[size++] = (struct sock_filter)EQ(
- get_lo((entry->args[idx]).value.v64), 0, jfalse);
+ get_lo((entry->arg[idx]).value.v64), 0, jfalse);
filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx));
filter[size++] = (struct sock_filter)AND(
- get_hi(entry->args[idx].op2.v64));
+ get_hi(entry->arg[idx].op2.v64));
filter[size++] = (struct sock_filter)EQ(
- get_hi(entry->args[idx].value.v64), jtrue, jfalse);
+ get_hi(entry->arg[idx].value.v64), jtrue, jfalse);
break;
- case U32:
-
+ case BPF_U32:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] =
- (struct sock_filter)AND(entry->args[idx].op2.v32);
+ (struct sock_filter)AND(entry->arg[idx].op2.v32);
filter[size++] = (struct sock_filter)EQ(
- entry->args[idx].value.v32, jtrue, jfalse);
+ entry->arg[idx].value.v32, jtrue, jfalse);
break;
}
@@ -374,55 +293,52 @@ static unsigned int and_eq (struct sock_filter filter[], int idx,
}
static unsigned int and_ne(struct sock_filter filter[], int idx,
- const struct bpf_call *entry, unsigned int jtrue,
+ const struct notify *entry, unsigned int jtrue,
unsigned int jfalse)
{
unsigned int size = 0;
- switch (entry->args[idx].type) {
- case U64:
+ switch (entry->arg[idx].type) {
+ case BPF_U64:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] = (struct sock_filter)AND(
- get_lo(entry->args[idx].op2.v64));
+ get_lo(entry->arg[idx].op2.v64));
filter[size++] = (struct sock_filter)EQ(
- get_lo((entry->args[idx]).value.v64), 0, jtrue + 3);
+ get_lo((entry->arg[idx]).value.v64), 0, jtrue + 3);
filter[size++] = (struct sock_filter)LOAD(HI_ARG(idx));
filter[size++] = (struct sock_filter)AND(
- get_hi(entry->args[idx].op2.v64));
+ get_hi(entry->arg[idx].op2.v64));
filter[size++] = (struct sock_filter)EQ(
- get_hi(entry->args[idx].value.v64), jfalse, jtrue);
+ get_hi(entry->arg[idx].value.v64), jfalse, jtrue);
break;
- case U32:
-
+ case BPF_U32:
filter[size++] = (struct sock_filter)LOAD(LO_ARG(idx));
filter[size++] =
- (struct sock_filter)AND(entry->args[idx].op2.v32);
+ (struct sock_filter)AND(entry->arg[idx].op2.v32);
filter[size++] = (struct sock_filter)EQ(
- entry->args[idx].value.v32, jfalse, jtrue);
+ entry->arg[idx].value.v32, jfalse, jtrue);
break;
}
return size;
}
-unsigned int create_bfp_program(struct syscall_entry table[],
- struct sock_filter filter[],
- unsigned int n_syscall)
+unsigned int filter_build(struct sock_filter filter[], unsigned int n)
{
unsigned int offset_left, offset_right;
unsigned int n_nodes, notify, accept;
unsigned int next_offset, offset;
- const struct bpf_call *entry;
+ const struct notify *entry;
unsigned int size = 0;
unsigned int next_args_off;
int nodes[MAX_JUMPS];
unsigned int i, j, k;
unsigned n_checks;
- create_lookup_nodes(nodes, n_syscall);
+ create_lookup_nodes(nodes, n);
/* No nodes if there is a single syscall */
- n_nodes = (1 << count_shift_right(n_syscall - 1)) - 1;
+ n_nodes = (1 << count_shift_right(n - 1)) - 1;
/* Pre */
/* cppcheck-suppress badBitmaskCheck */
@@ -438,7 +354,7 @@ unsigned int create_bfp_program(struct syscall_entry table[],
BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr)));
/* pre-check instruction + load syscall number (4 instructions) */
- accept = size + n_nodes + n_syscall;
+ accept = size + n_nodes + n;
notify = accept + 1;
/* Insert nodes */
@@ -450,21 +366,22 @@ unsigned int create_bfp_program(struct syscall_entry table[],
offset_left = left_child(i) - i - 1;
offset_right = right_child(i) - i - 1;
filter[size++] = (struct sock_filter)JGE(
- table[nodes[i]].nr, offset_right, offset_left);
+ notify_call[i].nr, offset_right, offset_left);
}
}
- next_offset = n_syscall + 1;
+ next_offset = n + 1;
/* Insert leaves */
- for (i = 0; i < n_syscall; i++) {
+ for (i = 0; i < n; i++) {
/* If the syscall doesn't have any arguments, then notify */
- if (check_args_syscall(&table[i]))
+ if (check_args_syscall_entry(notify_call + i))
offset = next_offset;
else
offset = notify - size - 1;
- filter[size++] = (struct sock_filter)EQ(table[i].nr, offset,
+ filter[size++] = (struct sock_filter)EQ(notify_call[i].nr,
+ offset,
accept - size);
- next_offset += get_n_args_syscall_instr(&table[i]) - 1;
+ next_offset += get_n_args_syscall_instr(notify_call + i, n) - 1;
}
/* Seccomp accept and notify instruction */
filter[size++] = (struct sock_filter)BPF_STMT(BPF_RET | BPF_K,
@@ -477,15 +394,20 @@ unsigned int create_bfp_program(struct syscall_entry table[],
* entry. If a check on the argument isn't equal then it jumps to
* check the following entry of the syscall and its arguments.
*/
- for (i = 0; i < n_syscall; i++) {
+ for (i = 0; i < n; i++) {
bool has_arg = false;
- for (j = 0; j < (table[i]).count; j++) {
+ unsigned int count = 0, x;
+
+ for (x = 0; x < 6; x++)
+ count += notify_call[i].arg[x].cmp == NO_CHECK;
+
+ for (j = 0; j < count; j++) {
n_checks = 0;
- entry = table[i].entry + j;
+ entry = notify_call + i + j;
next_args_off = get_n_args_syscall_entry(entry);
for (k = 0; k < 6; k++) {
offset = next_args_off - n_checks;
- switch (entry->args[k].cmp) {
+ switch (entry->arg[k].cmp) {
case NO_CHECK:
continue;
case EQ:
@@ -525,7 +447,7 @@ unsigned int create_bfp_program(struct syscall_entry table[],
n_checks++;
has_arg = true;
}
- if (check_args_syscall_entry(table[i].entry))
+ if (check_args_syscall_entry(notify_call + i))
filter[size++] = (struct sock_filter)BPF_STMT(
BPF_RET | BPF_K,
SECCOMP_RET_USER_NOTIF);
@@ -541,31 +463,121 @@ unsigned int create_bfp_program(struct syscall_entry table[],
return size;
}
-static int compare_names(const void *a, const void *b)
-{
- return strcmp(((struct syscall_numbers *)a)->name,
- ((struct syscall_numbers *)b)->name);
+/**
+ * struct filter_call_input - First input stage for cooker notification requests
+ * @notify: Notify on this system call
+ * @no_args: No argument comparisons are allowed for this call
+ * @args_set: Argument matches were already set up once for this call
+ * @arg: Argument specification
+ */
+struct filter_call_input {
+ bool notify;
+ bool no_args;
+ bool args_set;
+ struct bpf_arg arg[6];
+} filter_input[512] = { 0 };
+
+static struct {
+ bool used;
+ struct bpf_arg arg[6];
+} filter_current_args;
+
+static long current_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) {
+ struct filter_call_input *call = filter_input + nr;
+ long prev_nr = current_nr;
+
+ if (nr >= 0) {
+ current_nr = nr;
+ call->notify = true;
+ }
+
+ if (filter_current_args.used) {
+ struct filter_call_input *prev_call = filter_input + prev_nr;
+
+ /* First time arguments for previous call are flushed? */
+ if (!prev_call->args_set && !prev_call->no_args) {
+ prev_call->args_set = true;
+ memcpy(prev_call->arg, filter_current_args.arg,
+ sizeof(filter_current_args.arg));
+ return;
+ }
+
+ prev_call->args_set = true;
+
+ /* ...not the first time: check exact overlap of matches */
+ if (memcmp(prev_call->arg, filter_current_args.arg,
+ sizeof(filter_current_args.arg)))
+ prev_call->no_args = true;
+
+ /* Flush temporary set of arguments */
+ memset(&filter_current_args, 0, sizeof(filter_current_args));
+ }
+}
+
+/**
+ * filter_needs_deref() - Mark system call as ineligible for argument evaluation
+ */
+void filter_needs_deref(void) {
+ struct filter_call_input *call = filter_input + current_nr;
+
+ call->no_args = true;
}
-int convert_bpf(char *file, struct bpf_call *entries, int n)
+/**
+ * Use temporary filter_call_cur_args storage. When there's a new notification,
+ * or the parser is done, we flush these argument matches to filter_input, and
+ * check if they match (including no-matches) all the previous argument
+ * specification. If they don't, the arguments can't be evaluated in the filter.
+ */
+void filter_add_arg(int index, struct bpf_arg arg) {
+ struct filter_call_input *call = filter_input + current_nr;
+
+ if (call->no_args)
+ return;
+
+ memcpy(filter_current_args.arg + index, &arg, sizeof(arg));
+ filter_current_args.used = true;
+}
+
+unsigned int filter_close_input(void)
{
- int nt, fd, fsize;
- struct syscall_entry table[N_SYSCALL];
- struct sock_filter filter[MAX_FILTER];
+ struct notify *call = notify_call;
+ int i, count = 0;
- qsort(numbers, sizeof(numbers) / sizeof(numbers[0]), sizeof(numbers[0]),
- compare_names);
+ filter_notify(-1);
- qsort(entries, n, sizeof(struct bpf_call), compare_bpf_call_names);
- nt = construct_table(entries, n, table);
+ for (i = 0; i < 512; i++) {
+ if (filter_input[i].notify) {
+ count++;
+ call->nr = i;
- fsize = create_bfp_program(table, filter, nt);
+ if (filter_input[i].no_args)
+ continue;
- fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR);
- write(fd, filter, sizeof(struct sock_filter) * fsize);
+ memcpy(call->arg, filter_input[i].arg,
+ sizeof(call->arg));
+ }
+ }
- close(fd);
+ return count;
+}
- return 0;
+void filter_write(const char *path)
+{
+ struct sock_filter filter[MAX_FILTER];
+ int fd, n;
+
+ n = filter_close_input();
+ n = filter_build(filter, n);
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+ S_IRUSR | S_IWUSR);
+ write(fd, filter, sizeof(struct sock_filter) * n);
+ close(fd);
}