#include #include #include #include #include "libseccomp.h" /* * () around the string is 2 * '\0' at the end is 1 * Total extra space needed is 3 */ #define SECCOMP_STRING_BYTES 3 typedef struct seccomp_filter { #define SECCOMP_FILTER_TYPE_UNSET 0 #define SECCOMP_FILTER_TYPE_NODE 1 #define SECCOMP_FILTER_TYPE_LEAF 2 char type; struct seccomp_filter *parent; struct seccomp_filter *left; struct seccomp_filter *right; #define SECCOMP_FILTER_OP_UNSET 0 #define SECCOMP_FILTER_OP_AND " && " #define SECCOMP_FILTER_OP_OR " || " #define SECCOMP_FILTER_OP_EQUAL " == " #define SECCOMP_FILTER_OP_NOT_EQUAL " != " #define SECCOMP_FILTER_OP_LESS " < " #define SECCOMP_FILTER_OP_LESS_EQUAL " <= " #define SECCOMP_FILTER_OP_GREATER " > " #define SECCOMP_FILTER_OP_GREATER_EQUAL " >= " #define SECCOMP_FILTER_OP_ONE " 1 " #define SECCOMP_FILTER_OP_ZERO " 0 " const char *operation; char *arg; char *value; } seccomp_filter_t; char *seccomp_filter_to_string(seccomp_filter_t *sf) { size_t newlen, len; char *left = NULL; char *right = NULL; char *out; char *p; if (sf->type == SECCOMP_FILTER_TYPE_NODE) { left = seccomp_filter_to_string(sf->left); if (!left) return NULL; right = seccomp_filter_to_string(sf->right); if (!right) { free(left); return NULL; } if (strcmp(sf->operation, SECCOMP_FILTER_OP_AND) && strcmp(sf->operation, SECCOMP_FILTER_OP_OR)) assert(0); } else if (sf->type == SECCOMP_FILTER_TYPE_LEAF) { if (sf->arg) { left = strdup(sf->arg); if (!left) return NULL; } if (sf->value) { right = strdup(sf->value); if (!right) { free(left); return NULL; } } if (strcmp(sf->operation, SECCOMP_FILTER_OP_EQUAL) && strcmp(sf->operation, SECCOMP_FILTER_OP_NOT_EQUAL) && strcmp(sf->operation, SECCOMP_FILTER_OP_LESS) && strcmp(sf->operation, SECCOMP_FILTER_OP_LESS_EQUAL) && strcmp(sf->operation, SECCOMP_FILTER_OP_GREATER) && strcmp(sf->operation, SECCOMP_FILTER_OP_GREATER_EQUAL) && strcmp(sf->operation, SECCOMP_FILTER_OP_ONE) && strcmp(sf->operation, SECCOMP_FILTER_OP_ZERO)) assert(0); } else { assert(0); } newlen = 0; if (left) newlen += strlen(left); newlen += strlen(sf->operation); if (right) newlen += strlen(right); newlen += SECCOMP_STRING_BYTES; out = malloc(newlen); if (!out) { free(left); free(right); return NULL; } p = out; len = sprintf(p, "("); p += len; if (left) { len = sprintf(p, "%s", left); p += len; } len = sprintf(p, "%s", sf->operation); p += len; if (right) { len = sprintf(p, "%s", right); p += len; } len = sprintf(p, ")"); p += len; assert((size_t)(p-out) == (newlen - 1)); free(left); free(right); return out; } seccomp_filter_t *__seccomp_filter_alloc(void) { seccomp_filter_t *sf; sf = malloc(sizeof(*sf)); if (!sf) return NULL; memset(sf, 0, sizeof(*sf)); return sf; } void seccomp_filter_free(seccomp_filter_t *sf) { if (sf->type == SECCOMP_FILTER_TYPE_NODE) { seccomp_filter_free(sf->left); seccomp_filter_free(sf->right); } else if (sf->type == SECCOMP_FILTER_TYPE_LEAF) { free(sf->arg); free(sf->value); } free(sf); } seccomp_filter_t *seccomp_and_filters(seccomp_filter_t *left, seccomp_filter_t *right) { seccomp_filter_t *sf; sf = __seccomp_filter_alloc(); if (!sf) return NULL; left->parent = sf; right->parent = sf; sf->type = SECCOMP_FILTER_TYPE_NODE; sf->operation = SECCOMP_FILTER_OP_AND; sf->left = left; sf->right = right; return sf; } seccomp_filter_t *seccomp_or_filters(seccomp_filter_t *left, seccomp_filter_t *right) { seccomp_filter_t *sf; sf = __seccomp_filter_alloc(); if (!sf) return NULL; left->parent = sf; right->parent = sf; sf->type = SECCOMP_FILTER_TYPE_NODE; sf->operation = SECCOMP_FILTER_OP_OR; sf->left = left; sf->right = right; return sf; } int __seccomp_filter_same(seccomp_filter_t *sf1, seccomp_filter_t *sf2) { if (sf1->type != sf2->type) return 0; if (strcmp(sf1->operation, sf2->operation)) return 0; if (sf1->type == SECCOMP_FILTER_TYPE_NODE) { if (!__seccomp_filter_same(sf1->left, sf2->left)) return 0; if (!__seccomp_filter_same(sf1->right, sf2->right)) return 0; } else if (sf1->type == SECCOMP_FILTER_TYPE_LEAF) { if (sf1->arg && !sf2->arg) return 0; if (!sf1->arg && sf2->arg) return 0; if (sf1->arg && strcmp(sf1->arg, sf2->arg)) return 0; if (sf1->value && !sf2->value) return 0; if (!sf1->value && sf2->value) return 0; if (sf1->value && strcmp(sf1->value, sf2->value)) return 0; } else { assert(0); } return 1; } seccomp_filter_t *__seccomp_arg_value(char *operation, char *arg, char *value) { seccomp_filter_t *sf; sf = __seccomp_filter_alloc(); if (!sf) return NULL; sf->type = SECCOMP_FILTER_TYPE_LEAF; sf->operation = operation; if (arg) { sf->arg = strdup(arg); if (!sf->arg) goto err; } if (value) { sf->value = strdup(value); if (!sf->value) goto err; } return sf; err: free(sf->arg); free(sf->value); free(sf); return NULL; } seccomp_filter_t *seccomp_one(void) { return __seccomp_arg_value(SECCOMP_FILTER_OP_ONE, NULL, NULL); } seccomp_filter_t *seccomp_zero(void) { return __seccomp_arg_value(SECCOMP_FILTER_OP_ZERO, NULL, NULL); } seccomp_filter_t *seccomp_equal_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_EQUAL, arg, value); } seccomp_filter_t *seccomp_not_equal_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_NOT_EQUAL, arg, value); } seccomp_filter_t *seccomp_less_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_LESS, arg, value); } seccomp_filter_t *seccomp_less_equal_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_LESS_EQUAL, arg, value); } seccomp_filter_t *seccomp_greater_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_GREATER, arg, value); } seccomp_filter_t *seccomp_greater_equal_arg_value(char *arg, char *value) { return __seccomp_arg_value(SECCOMP_FILTER_OP_GREATER_EQUAL, arg, value); } int seccomp_filter_unset(seccomp_filter_t *tree __attribute__((unused)), seccomp_filter_t *subset __attribute__((unused))) { /* seccompt_filter_t *sf; if (__seccomp_filter_same(tree, subset)) { } else if (tree->type == SECCOMP_FILTER_TYPE_NODE) { if (!seccomp_filter_unset(tree->left, subset)) return 0; if (!seccomp_filter_unset(tree->right, subset)) return 0; } else { return -EINVAL; } */ return 0; }