diff options
author | Alice Frosi <afrosi@redhat.com> | 2023-07-18 11:15:53 +0200 |
---|---|---|
committer | Alice Frosi <afrosi@redhat.com> | 2023-08-24 15:33:17 +0200 |
commit | 240eb94b44f9dc613a85911d4190df129372e9cc (patch) | |
tree | 2535780888d293b71aa5aadc70f2047f2a7f787b | |
parent | 3f2585770384586977483ec4c4b38fe4c3e5fc45 (diff) | |
download | seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar.gz seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar.bz2 seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar.lz seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar.xz seitan-240eb94b44f9dc613a85911d4190df129372e9cc.tar.zst seitan-240eb94b44f9dc613a85911d4190df129372e9cc.zip |
cooker: generate OCI seccomp profile
Generate the OCI seccomp profile instead of directly the BPF filter. The
seccomp profile will be used consquently by the container runtime as
input in order to generate the BPF filter.
Example with mknod:
$ seitan-cooker -g /tmp/gluten -p /tmp/scmp_prof.json -s seccomp.json -i demo/mknod.hjson
$ seitan -s /tmp/seitan.sock -i /tmp/gluten
$ podman run --cap-drop ALL
--security-opt=seccomp=/tmp/scmp_prof.json \
--annotation run.oci.seccomp.receiver=/tmp/seitan.sock \
-ti fedora \
sh -c 'mknod /dev/lol c 1 7 && ls /dev/lol'
/dev/lol
Signed-off-by: Alice Frosi <afrosi@redhat.com>
-rw-r--r-- | common/util.h | 1 | ||||
-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 |
8 files changed, 560 insertions, 21 deletions
diff --git a/common/util.h b/common/util.h index b11edb6..a587665 100644 --- a/common/util.h +++ b/common/util.h @@ -8,6 +8,7 @@ #include <string.h> #include <stdint.h> +#include <stdlib.h> #include <errno.h> #define BIT(n) (1UL << (n)) 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 |