diff options
Diffstat (limited to 'cooker')
-rw-r--r-- | cooker/Makefile | 6 | ||||
-rw-r--r-- | cooker/emit.c | 14 | ||||
-rw-r--r-- | cooker/emit.h | 2 | ||||
-rw-r--r-- | cooker/main.c | 39 | ||||
-rw-r--r-- | cooker/match.c | 18 | ||||
-rw-r--r-- | cooker/seccomp_profile.c | 305 | ||||
-rw-r--r-- | cooker/seccomp_profile.h | 196 |
7 files changed, 559 insertions, 21 deletions
diff --git a/cooker/Makefile b/cooker/Makefile index 31b52c9..8cf8691 100644 --- a/cooker/Makefile +++ b/cooker/Makefile @@ -32,11 +32,13 @@ CFLAGS += -DSEITAN_AUDIT_ARCH=AUDIT_ARCH_$(AUDIT_ARCH) SRCS := call.c calls.c emit.c gluten.c filter.c main.c match.c \ parse.c parson.c \ $(COMMON)/util.c \ - calls/net.c calls/ioctl.c calls/process.c calls/fs.c calls/io.c + calls/net.c calls/ioctl.c calls/process.c calls/fs.c calls/io.c \ + seccomp_profile.c HEADERS := call.h calls.h cooker.h emit.h filter.h gluten.h match.h \ parse.h parson.h \ $(COMMON)/gluten.h $(COMMON)/util.h \ - calls/net.h calls/ioctl.h calls/process.h calls/fs.h calls/io.h + calls/net.h calls/ioctl.h calls/process.h calls/fs.h calls/io.h \ + seccomp_profile.h $(BIN): $(SRCS) $(HEADERS) $(CC) $(CFLAGS) -o $(BIN) $(SRCS) diff --git a/cooker/emit.c b/cooker/emit.c index 28afd29..ce325f1 100644 --- a/cooker/emit.c +++ b/cooker/emit.c @@ -14,6 +14,7 @@ #include "filter.h" #include "util.h" #include "emit.h" +#include "seccomp_profile.h" static const char *type_str[] = { "UNDEF", "NONE", @@ -549,8 +550,8 @@ static void gluten_link(struct gluten_ctx *g, enum jump_type type, } } -void emit_bpf_arg(int index, enum type type, union value v, union value mask, - enum op_cmp_type cmp) +static void emit_bpf_filter_arg(int index, enum type type, union value v, + union value mask, enum op_cmp_type cmp) { struct bpf_field bpf; @@ -575,6 +576,15 @@ void emit_bpf_arg(int index, enum type type, union value v, union value mask, filter_add_check(&bpf); } +void emit_bpf_arg(int index, enum type type, union value v, union value mask, + enum op_cmp_type cmp, enum scmp_mode mode) +{ + if (mode == SCMP_FILTER) + emit_bpf_filter_arg(index, type, v, mask, cmp); + else + scmp_profile_add_check(index, v, mask, cmp); +} + void link_block(struct gluten_ctx *g) { debug(" Linking block..."); diff --git a/cooker/emit.h b/cooker/emit.h index 7413eec..835aae7 100644 --- a/cooker/emit.h +++ b/cooker/emit.h @@ -46,7 +46,7 @@ struct gluten_offset emit_data_or(struct gluten_ctx *g, struct gluten_offset offset, enum type type, union value *value); void emit_bpf_arg(int index, enum type type, union value v, union value mask, - enum op_cmp_type cmp); + enum op_cmp_type cmp, enum scmp_mode mode); void link_block(struct gluten_ctx *g); void link_match(struct gluten_ctx *g); void link_matches(struct gluten_ctx *g); diff --git a/cooker/main.c b/cooker/main.c index 85c4746..5c099ff 100644 --- a/cooker/main.c +++ b/cooker/main.c @@ -17,20 +17,23 @@ #include "gluten.h" #include "parse.h" #include "filter.h" +#include "seccomp_profile.h" /* Cooker options */ static struct option options[] = { { "input", required_argument, NULL, 'i' }, { "gluten", required_argument, NULL, 'g' }, { "filter", required_argument, NULL, 'f' }, - { "scmp-profile", required_argument, NULL, 'p' }, + { "scmp-out-prof", required_argument, NULL, 'p' }, + { "scmp-orig-prof", required_argument, NULL, 's' }, //??? is required }; struct arguments { char *input_file; char *gluten_file; char *filter_file; - char *scmp_profile_file; + char *scmp_prof_file; + char *orig_scmp_prof_file; }; static void usage() @@ -38,10 +41,11 @@ static void usage() printf("seitan-cooker: generate the BPF filters or seccomp profile and the action byte code for seitan\n" "Example: setain-cooker -i <input file> -g <gluten_file> -f <filter_file>\n" "Usage:\n" - "\t-i, --input:\tJSON input file\n" - "\t-g, --gluten:\tBytecode file for seitan action\n" - "\t-f, --filter:\tBPF filter file (cannot be used together with scmp-profile)\n" - "\t-p, --scmp-profile:\tSeccomp profile file (cannot be used together with filter)\n"); + "\t-i, --input:\t\tJSON input file\n" + "\t-g, --gluten:\t\tBytecode file for seitan action\n" + "\t-f, --filter:\t\tBPF filter file (cannot be used together with scmp-profile)\n" + "\t-p, --scmp-prof:\tSeccomp profile file (cannot be used together with filter)\n" + "\t-s, --scmp-orig-prof:\tOriginal seccomp profile (ignored if used with filter)\n"); exit(EXIT_FAILURE); } @@ -51,7 +55,7 @@ static void parse(int argc, char **argv, struct arguments *arguments) int oc; if (arguments == NULL) usage(); - while ((oc = getopt_long(argc, argv, ":i:g:f:p:", options, + while ((oc = getopt_long(argc, argv, ":i:g:f:p:s:", options, &option_index)) != -1) { switch (oc) { case 'i': @@ -64,7 +68,10 @@ static void parse(int argc, char **argv, struct arguments *arguments) arguments->filter_file = optarg; break; case 'p': - arguments->scmp_profile_file = optarg; + arguments->scmp_prof_file = optarg; + break; + case 's': + arguments->orig_scmp_prof_file = optarg; break; default: usage(); @@ -75,12 +82,12 @@ static void parse(int argc, char **argv, struct arguments *arguments) usage(); } if (arguments->filter_file != NULL && - arguments->scmp_profile_file != NULL) { + arguments->scmp_prof_file != NULL) { err("the filter and scmp-profile options cannot be used together"); usage(); } if (arguments->filter_file == NULL && - arguments->scmp_profile_file == NULL) { + arguments->scmp_prof_file == NULL) { err("select one of the options between filter and scmp-profile"); usage(); } @@ -104,12 +111,22 @@ int main(int argc, char **argv) parse(argc, argv, &arguments); + if (arguments.filter_file != NULL) { + g.mode = SCMP_FILTER; + } else { + g.mode = SCMP_PROFILE; + scmp_profile_init(arguments.orig_scmp_prof_file); + } + gluten_init(&g); parse_file(&g, arguments.input_file); gluten_write(&g, arguments.gluten_file); - filter_write(arguments.filter_file); + if (arguments.filter_file != NULL) + filter_write(arguments.filter_file); + else + scmp_profile_write(arguments.scmp_prof_file); return 0; } diff --git a/cooker/match.c b/cooker/match.c index c83f9fe..eeedead 100644 --- a/cooker/match.c +++ b/cooker/match.c @@ -18,7 +18,7 @@ #include "util.h" #include "calls/net.h" - +#include "seccomp_profile.h" /** * arg_load() - Allocate and build bytecode for one syscall argument * @g: gluten context @@ -182,7 +182,7 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx emit_cmp(g, cmp, masked, cmp_offset, gluten_size[f->type], jump); - emit_bpf_arg(index, f->type, cmpterm, set, cmp); + emit_bpf_arg(index, f->type, cmpterm, set, cmp, g->mode); break; } @@ -213,7 +213,7 @@ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx emit_cmp(g, cmp, data_offset, const_offset, gluten_size[f->type], jump); - emit_bpf_arg(index, f->type, v, mask, cmp); + emit_bpf_arg(index, f->type, v, mask, cmp, g->mode); break; case GNU_DEV_MAJOR: @@ -379,9 +379,17 @@ void handle_matches(struct gluten_ctx *g, JSON_Value *value) debug(" Found description for %s", name); emit_nr(g, emit_data(g, U64, 0, &v)); - filter_notify(call->number); + if (g->mode == SCMP_FILTER) + filter_notify(call->number); + else + scmp_profile_notify(call->name); + parse_match(g, args, call->args); - filter_flush_args(call->number); + + if (g->mode == SCMP_FILTER) + filter_flush_args(call->number); + else + scmp_profile_flush_args(); break; } diff --git a/cooker/seccomp_profile.c b/cooker/seccomp_profile.c new file mode 100644 index 0000000..e75fda2 --- /dev/null +++ b/cooker/seccomp_profile.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* seitan - Syscall Expressive Interpreter, Transformer and Notifier + * + * cooker/emit.c - Generate gluten (bytecode) instructions and read-only data + * + * Copyright 2023 Red Hat GmbH + * Author: Alice Frosi <afrosi@redhat.com> + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdbool.h> +#include <string.h> + +#include "seccomp_profile.h" + +static struct seccomp scmp_profile; +static unsigned int counter; +static unsigned int count_args; +static JSON_Object *root_obj; +static JSON_Value *root; +static bool ignore_syscall; + +const char *scmp_act_str[] = { + "SCMP_ACT_KILL_THREAD", "SCMP_ACT_TRAP", "SCMP_ACT_ERRNO", + "SCMP_ACT_TRACE", "SCMP_ACT_ALLOW", "SCMP_ACT_LOG", + "SCMP_ACT_NOTIFY", +}; + +const char *scmp_op_str[] = { + "", + "SCMP_CMP_NE", + "SCMP_CMP_LT", + "SCMP_CMP_LE", + "SCMP_CMP_EQ", + "SCMP_CMP_GE", + "SCMP_CMP_GT", + "SCMP_CMP_MASKED_EQ", +}; + +const char *arch_str[] = { + "SCMP_ARCH_NATIVE", "SCMP_ARCH_X86", "SCMP_ARCH_X86_64", + "SCMP_ARCH_X32", "SCMP_ARCH_ARM", "SCMP_ARCH_AARCH64", + "SCMP_ARCH_MIPS", "SCMP_ARCH_MIPS64", "SCMP_ARCH_MIPS64N32", + "SCMP_ARCH_MIPSEL", "SCMP_ARCH_MIPSEL64", "SCMP_ARCH_MIPSEL64N32", + "SCMP_ARCH_PPC", "SCMP_ARCH_PPC64", "SCMP_ARCH_PPC64LE", + "SCMP_ARCH_S390", "SCMP_ARCH_S390X", "SCMP_ARCH_PARISC", + "SCMP_ARCH_PARISC64", "SCMP_ARCH_RISCV64", +}; + +const char *scmp_filter_str[] = { + "SECCOMP_FILTER_FLAG_TSYNC", + "SECCOMP_FILTER_FLAG_LOG", + "SECCOMP_FILTER_FLAG_SPEC_ALLOW", + "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV", +}; + +// TODO: decide defaults for when the original profile isn't definied +static void set_defaults_scmp_profile() +{ + scmp_profile.default_action = ACT_ERRNO; + die("Not implemented yet"); +} + +static void parse_orig_scmp_profile(char *path) +{ + debug("Use %s as base for the generated seccomp profile", path); + root = json_parse_file(path); + if (root == NULL) + die(" failed parsing JSON seccomp profile: %s", path); +} + +/** + * is_scmp_notify_set - Verify if one of the syscall entries has the SCMP_NOTIFY + * action enabled + * + */ +static bool is_scmp_notify_set(JSON_Array *syscalls) +{ + const char *action; + JSON_Object *obj; + unsigned int i; + + for (i = 0; i < json_array_get_count(syscalls); i++) { + if (((obj = json_array_get_object(syscalls, i)) == NULL) || + ((action = json_object_get_string(obj, "action")) == NULL)) + continue; + if (strcmp(action, scmp_act_str[ACT_NOTIFY]) == 0) + return true; + } + return false; +} + +void scmp_profile_init(char *path) +{ + JSON_Array *syscalls; + counter = 0; + count_args = 0; + + if (path == NULL) { + root = json_value_init_object(); + debug("Set defaults for the seccomp profile"); + set_defaults_scmp_profile(); + } else { + parse_orig_scmp_profile(path); + } + if ((root_obj = json_value_get_object(root)) == NULL) + die(" failed serialize JSON"); + + if ((syscalls = json_object_get_array(root_obj, "syscalls")) == NULL) + return; + if (is_scmp_notify_set(syscalls)) + die(" the use of multiple seccomp notifiers isn't supported"); +} + +static bool is_syscall_present(const char *name) +{ + if (name == NULL) + return false; + for (unsigned int i = 0; i < counter; i++) + if (strcmp(scmp_profile.syscalls[i].names, name) == 0) + return true; + + return false; +} + +void scmp_profile_notify(const char *name) +{ + ignore_syscall = false; + if (is_syscall_present(name)) { + ignore_syscall = true; + return; + } + debug(" #%u add syscall %s to seccomp profile", counter, name); + strcpy(scmp_profile.syscalls[counter].names, name); + scmp_profile.syscalls[counter].action = ACT_NOTIFY; +} + +void scmp_profile_add_check(int index, union value v, union value mask, + enum op_cmp_type cmp) +{ + char *name = scmp_profile.syscalls[counter].names; + struct scmp_arg *arg; + + if (count_args > 5) + die(" too many arguments for the syscall entry %d:%s", counter, + name); + debug(" #%u add arg to syscall %s to seccomp profile", count_args); + arg = &scmp_profile.syscalls[counter].args[count_args]; + arg->index = index; + arg->value = v.v_num; + arg->set = true; + if (mask.v_num) { + arg->valueTwo = mask.v_num; + arg->op = OP_MASKEDEQUAL; + return; + } + + // TODO: check if also the other cmp operations are inverted in cooker + switch (cmp) { + case CMP_NE: + arg->op = OP_EQUALTO; + break; + case CMP_EQ: + arg->op = OP_NOTEQUAL; + break; + case CMP_LE: + arg->op = OP_LESSEQUAL; + break; + case CMP_LT: + arg->op = OP_LESSTHAN; + break; + case CMP_GE: + arg->op = OP_GREATEREQUAL; + break; + case CMP_GT: + arg->op = OP_GREATERTHAN; + break; + default: + die(" operation not recognized"); + break; + } +} + +void scmp_profile_flush_args() +{ + if (ignore_syscall) + return; + debug(" flush args for syscall %s", + scmp_profile.syscalls[counter].names); + counter++; + count_args = 0; +} + +static void json_append_syscall(JSON_Array *syscalls, struct syscall *syscall) +{ + JSON_Value *val = json_value_init_object(); + JSON_Object *obj = json_value_get_object(val); + JSON_Value *arg = json_value_init_object(); + JSON_Object *arg_obj = json_value_get_object(arg); + JSON_Array *names_array; + JSON_Array *args_array; + + json_object_set_value(obj, "names", json_value_init_array()); + json_object_set_value(obj, "args", json_value_init_array()); + names_array = json_object_get_array(obj, "names"); + ; + args_array = json_object_get_array(obj, "args"); + ; + check_JSON_status(json_object_set_string(obj, "action", + scmp_act_str[ACT_NOTIFY])); + check_JSON_status( + json_array_append_string(names_array, &syscall->names[0])); + for (unsigned int i = 0; i < 6; i++) { + if (!syscall->args[i].set) + continue; + check_JSON_status(json_object_set_number( + arg_obj, "index", syscall->args[i].index)); + check_JSON_status(json_object_set_number( + arg_obj, "value", syscall->args[i].value)); + check_JSON_status(json_object_set_number( + arg_obj, "valueTwo", syscall->args[i].valueTwo)); + check_JSON_status(json_object_set_string( + arg_obj, "op", scmp_op_str[syscall->args[i].op])); + check_JSON_status(json_array_append_value(args_array, arg)); + debug(" added args for syscall %s %d: ", syscall->names, i, + syscall->args[i].value, syscall->args[i].valueTwo, + scmp_op_str[syscall->args[i].op]); + } + json_array_append_value(syscalls, val); +} + +/** + * remove_existing_syscall() - Remove the syscall entry name from the list where + * the syscall is listed as allowed and without parameters. + * Eg. if in the original seccomp profile with the 'connect' syscall: + * "syscalls": [ + * { + * "names": [ .. + * "connect", + * .. + * "action": "SCMP_ACT_ALLOW", + * "args": [], + * } + * + */ +static void remove_existing_syscall(JSON_Array *syscalls, char *name) +{ + const char *curr_syscall, *action; + JSON_Array *names, *args; + unsigned int i, k; + JSON_Object *obj; + + for (i = 0; i < json_array_get_count(syscalls); i++) { + if (((obj = json_array_get_object(syscalls, i)) == NULL) || + ((names = json_object_get_array(obj, "names")) == NULL) || + ((args = json_object_get_array(obj, "args")) == NULL) || + ((action = json_object_get_string(obj, "action")) == NULL)) + continue; + if ((strcmp(action, scmp_act_str[ACT_ALLOW]) != 0) || + (json_array_get_count(args) > 0)) + continue; + for (k = 0; k < json_array_get_count(names); k++) { + curr_syscall = json_array_get_string(names, k); + if (curr_syscall == NULL) + die(" empty syscall name"); + if (strcmp(curr_syscall, name) == 0) { + debug(" remove %s as duplicate at %d", + curr_syscall, k); + json_array_remove(names, k); + } + } + } +} + +static void json_serialize_syscalls() +{ + JSON_Array *syscalls; + unsigned int i; + + if ((syscalls = json_object_get_array(root_obj, "syscalls")) == NULL) { + json_object_set_value(root_obj, "syscalls", + json_value_init_array()); + syscalls = json_object_get_array(root_obj, "syscalls"); + } + + for (i = 0; i < counter; i++) { + remove_existing_syscall(syscalls, + &scmp_profile.syscalls[i].names[0]); + // Create syscall entry for the notify + json_append_syscall(syscalls, &scmp_profile.syscalls[i]); + } +} + +void scmp_profile_write(const char *file) +{ + debug("Write seccomp profile to %s", file); + json_serialize_syscalls(); + json_serialize_to_file_pretty(root, file); + + json_value_free(root); + + return; +} diff --git a/cooker/seccomp_profile.h b/cooker/seccomp_profile.h new file mode 100644 index 0000000..75e81dd --- /dev/null +++ b/cooker/seccomp_profile.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later +* Copyright 2023 Red Hat GmbH +* Author: Alice Frosi <afrosi@redhat.com> +*/ + +#ifndef SCMP_PROFILE_H_ +#define SCMP_PROFILE_H_ + +#include <linux/limits.h> +#include <stdint.h> +#include <unistd.h> + +#include "parson.h" +#include "util.h" +#include "cooker.h" +#include "gluten.h" + +#define STRING_MAX 2000 +#define COMMENT_MAX 1000 +/* TODO define it in a common place */ +#define SYSCALL_MAX 512 +#define MAX_SUB_ARCHES 3 +#define check_JSON_status(status) \ + do { \ + if (status == JSONFailure) \ + die("failing parsing JSON value"); \ + } while (0) +/* +* Definition for the OCI Seccomp Specification: +* https://github.com/opencontainers/runtime-spec/blob/main/config-linux.md#seccomp +*/ +extern const char *scmp_act_str[]; + +enum scmp_act_type { + ACT_KILLTHREAD, + ACT_TRAP, + ACT_ERRNO, + ACT_TRACE, + ACT_ALLOW, + ACT_LOG, + ACT_NOTIFY, +}; + +// Define operators for syscall arguments in Seccomp +extern const char *scmp_op_str[]; + +enum scmp_op_type { + OP_NO_CHECK, + OP_NOTEQUAL, + OP_LESSTHAN, + OP_LESSEQUAL, + OP_EQUALTO, + OP_GREATEREQUAL, + OP_GREATERTHAN, + OP_MASKEDEQUAL, +}; + +// Arg used for matching specific syscall arguments in Seccomp +struct scmp_arg { + bool set; + uint32_t index; + uint64_t value; + uint64_t valueTwo; + enum scmp_op_type op; +}; + +extern const char *arch_str[]; + +enum arch_type { + ARCH_NATIVE = 0, + ARCH_X86, + ARCH_X86_64, + ARCH_X32, + ARCH_ARM, + ARCH_AARCH64, + ARCH_MIPS, + ARCH_MIPS64, + ARCH_MIPS64N2, + ARCH_MIPSEL, + ARCH_MIPSEL6, + ARCH_MIPSEL6N32, + ARCH_PPC, + ARCH_PPC64, + ARCH_PPC64LE, + ARCH_S390, + ARCH_S390X, + ARCH_PARISC, + ARCH_PARISC6, + ARCH_RISCV64, + ARCH_MAX = ARCH_RISCV64, +}; + +// Architecture is used to represent a specific architecture +// and its sub-architectures +struct architecture { + enum arch_type arch; + enum arch_type subArches[MAX_SUB_ARCHES]; +}; + +enum caps_type { + CAP_CHOWN = 0, + CAP_DAC_OVERRIDE = 1, + CAP_DAC_READ_SEARCH = 2, + CAP_FOWNER = 3, + CAP_FSETID = 4, + CAP_KILL = 5, + CAP_SETGID = 6, + CAP_SETUID = 7, + CAP_SETPCAP = 8, + CAP_LINUX_IMMUTABLE = 9, + CAP_NET_BIND_SERVICE = 10, + CAP_NET_BROADCAST = 11, + CAP_NET_ADMIN = 12, + CAP_NET_RAW = 13, + CAP_IPC_LOCK = 14, + CAP_IPC_OWNER = 15, + CAP_SYS_MODULE = 16, + CAP_SYS_RAWIO = 17, + CAP_SYS_CHROOT = 18, + CAP_SYS_PTRACE = 19, + CAP_SYS_PACCT = 20, + CAP_SYS_ADMIN = 21, + CAP_SYS_BOOT = 22, + CAP_SYS_NICE = 23, + CAP_SYS_RESOURCE = 24, + CAP_SYS_TIME = 25, + CAP_SYS_TTY_CONFIG = 26, + CAP_MKNOD = 27, + CAP_LEASE = 28, + CAP_AUDIT_WRITE = 29, + CAP_AUDIT_CONTROL = 30, + CAP_SETFCAP = 31, + CAP_MAC_OVERRIDE = 32, + CAP_MAC_ADMIN = 33, + CAP_SYSLOG = 34, + CAP_WAKE_ALARM = 35, + CAP_BLOCK_SUSPEND = 36, + CAP_AUDIT_READ = 37, + CAP_PERFMON = 38, + CAP_BPF = 39, + CAP_CHECKPOINT_RESTORE = 40, + CAP_LAST_CAP = 41, + CAPS_MAX = CAP_LAST_CAP, +}; + +// Filter is used to conditionally apply Seccomp rules +struct scmp_filter { + enum caps_type caps[CAPS_MAX]; + enum arch_type arches[ARCH_MAX]; +}; + +extern const char *scmp_filter_str[]; + +enum scmp_filter_type { + SCMP_FILT_FLAG_TSYNC, + SCMP_FILT_FLAG_LOG, + SCMP_FILT_FLAG_SPEC_ALLOW, + SCMP_FILT_FLAG_WAIT_KILLABLE_RECV, + SCMP_FILT_FLAG_MAX = SCMP_FILT_FLAG_WAIT_KILLABLE_RECV, +}; + +// Syscall is used to match a group of syscalls in Seccomp +struct syscall { + /* here we use a single syscall per entry*/ + char names[STRING_MAX]; + enum scmp_act_type action; + struct scmp_arg args[6]; + char comment[COMMENT_MAX]; + enum scmp_filter_type includes; + enum scmp_filter_type excludes; + char err[STRING_MAX]; +}; + +// Seccomp represents the config for a seccomp profile for syscall restriction. +struct seccomp { + enum scmp_act_type default_action; + + char defaultErrno[STRING_MAX]; + + // Architectures is kept to maintain backward compatibility with the old + // seccomp profile. + enum arch_type architectures[ARCH_MAX]; + struct architecture archMap[ARCH_MAX]; + struct syscall syscalls[SYSCALL_MAX]; + enum scmp_filter_type flags[SCMP_FILT_FLAG_MAX]; + char listenerPath[PATH_MAX]; + char listenerMetadata[PATH_MAX]; +}; + +void scmp_profile_init(); +void scmp_profile_notify(const char *name); +void scmp_profile_add_check(int index, union value v, union value mask, + enum op_cmp_type cmp); +void scmp_profile_write(const char *file); +void scmp_profile_flush_args(); +#endif |