diff options
-rw-r--r-- | src/api.c | 251 | ||||
-rw-r--r-- | src/db.c | 535 | ||||
-rw-r--r-- | src/db.h | 15 |
3 files changed, 422 insertions, 379 deletions
@@ -69,51 +69,21 @@ static int _syscall_valid(int syscall) /* NOTE - function header comment in include/seccomp.h */ API scmp_filter_ctx seccomp_init(uint32_t def_action) { - struct db_filter_col *col; - struct db_filter *db; - if (db_action_valid(def_action) < 0) return NULL; - col = db_col_init(def_action); - if (col == NULL) - return NULL; - db = db_init(arch_def_native); - if (db == NULL) - goto init_failure_col; - - if (db_col_db_add(col, db) < 0) - goto init_failure_db; - - return col; - -init_failure_db: - db_release(db); -init_failure_col: - db_col_release(col); - return NULL; + return db_col_init(def_action); } /* NOTE - function header comment in include/seccomp.h */ API int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action) { - int rc; struct db_filter_col *col = (struct db_filter_col *)ctx; - struct db_filter *db; if (ctx == NULL || db_action_valid(def_action) < 0) return -EINVAL; - db_col_reset(col, def_action); - - db = db_init(arch_def_native); - if (db == NULL) - return -ENOMEM; - rc = db_col_db_add(col, db); - if (rc < 0) - db_release(db); - - return rc; + return db_col_reset(col, def_action); } /* NOTE - function header comment in include/seccomp.h */ @@ -180,9 +150,7 @@ API int seccomp_arch_exist(const scmp_filter_ctx ctx, /* NOTE - function header comment in include/seccomp.h */ API int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token) { - int rc; const struct arch_def *arch; - struct db_filter *db; struct db_filter_col *col = (struct db_filter_col *)ctx; if (arch_token == 0) @@ -196,14 +164,7 @@ API int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token) arch = arch_def_lookup(arch_token); if (arch == NULL) return -EFAULT; - db = db_init(arch); - if (db == NULL) - return -ENOMEM; - rc = db_col_db_add(col, db); - if (rc < 0) - db_release(db); - - return rc; + return db_col_db_new(col, arch); } /* NOTE - function header comment in include/seccomp.h */ @@ -336,81 +297,25 @@ API int seccomp_syscall_resolve_name(const char *name) API int seccomp_syscall_priority(scmp_filter_ctx ctx, int syscall, uint8_t priority) { - int rc = 0, rc_tmp; - unsigned int iter; - int sc_tmp; - struct db_filter_col *col; - struct db_filter *filter; + struct db_filter_col *col = (struct db_filter_col *)ctx; - if (_ctx_valid(ctx) || _syscall_valid(syscall)) + if (db_col_valid(col) || _syscall_valid(syscall)) return -EINVAL; - col = (struct db_filter_col *)ctx; - for (iter = 0; iter < col->filter_cnt; iter++) { - filter = col->filters[iter]; - sc_tmp = syscall; - - rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); - if (rc_tmp < 0) - goto syscall_priority_failure; - - /* if this is a pseudo syscall (syscall < 0) then we need to - * rewrite the syscall for some arch specific reason */ - if (sc_tmp < 0) { - /* we set this as a strict op - we don't really care - * since priorities are a "best effort" thing - as we - * want to catch the -EDOM error and bail on this - * architecture */ - rc_tmp = arch_syscall_rewrite(filter->arch, &sc_tmp); - if (rc_tmp == -EDOM) - continue; - if (rc_tmp < 0) - goto syscall_priority_failure; - } - - rc_tmp = db_syscall_priority(filter, sc_tmp, priority); - -syscall_priority_failure: - if (rc == 0 && rc_tmp < 0) - rc = rc_tmp; - } - - return rc; + return db_col_syscall_priority(col, syscall, priority); } -/** - * Add a new rule to the current filter - * @param col the filter collection - * @param strict the strict flag - * @param action the filter action - * @param syscall the syscall number - * @param arg_cnt the number of argument filters in the argument filter chain - * @param arg_array the argument filter chain, (uint, enum scmp_compare, ulong) - * - * This function adds a new argument/comparison/value to the seccomp filter for - * a syscall; multiple arguments can be specified and they will be chained - * together (essentially AND'd together) in the filter. When the strict flag - * is true the function will fail if the exact rule can not be added to the - * filter, if the strict flag is false the function will not fail if the - * function needs to adjust the rule due to architecture specifics. Returns - * zero on success, negative values on failure. - * - */ -static int _seccomp_rule_add(struct db_filter_col *col, - bool strict, uint32_t action, int syscall, - unsigned int arg_cnt, - const struct scmp_arg_cmp *arg_array) +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_rule_add_array(scmp_filter_ctx ctx, + uint32_t action, int syscall, + unsigned int arg_cnt, + const struct scmp_arg_cmp *arg_array) { - int rc = 0, rc_tmp; - int sc_tmp; - unsigned int iter; - unsigned int chain_len; - unsigned int arg_num; - size_t chain_size; - struct db_filter *filter; - struct db_api_arg *chain = NULL, *chain_tmp; - struct scmp_arg_cmp arg_data; + int rc; + struct db_filter_col *col = (struct db_filter_col *)ctx; + if (arg_cnt > ARG_COUNT_MAX) + return -EINVAL; if (arg_cnt > 0 && arg_array == NULL) return -EINVAL; @@ -423,110 +328,7 @@ static int _seccomp_rule_add(struct db_filter_col *col, if (action == col->attr.act_default) return -EPERM; - if (strict && col->filter_cnt > 1) - return -EOPNOTSUPP; - - /* collect the arguments for the filter rule */ - chain_len = ARG_COUNT_MAX; - chain_size = sizeof(*chain) * chain_len; - chain = malloc(chain_size); - if (chain == NULL) - return -ENOMEM; - memset(chain, 0, chain_size); - for (iter = 0; iter < arg_cnt; iter++) { - arg_data = arg_array[iter]; - arg_num = arg_data.arg; - if (arg_num < chain_len && chain[arg_num].valid == 0) { - chain[arg_num].valid = 1; - chain[arg_num].arg = arg_num; - chain[arg_num].op = arg_data.op; - /* XXX - we should check datum/mask size against the - * arch definition, e.g. 64 bit datum on x86 */ - switch (chain[arg_num].op) { - case SCMP_CMP_NE: - case SCMP_CMP_LT: - case SCMP_CMP_LE: - case SCMP_CMP_EQ: - case SCMP_CMP_GE: - case SCMP_CMP_GT: - chain[arg_num].mask = DATUM_MAX; - chain[arg_num].datum = arg_data.datum_a; - break; - case SCMP_CMP_MASKED_EQ: - chain[arg_num].mask = arg_data.datum_a; - chain[arg_num].datum = arg_data.datum_b; - break; - default: - rc = -EINVAL; - goto rule_add_return; - } - } else { - rc = -EINVAL; - goto rule_add_return; - } - } - - for (iter = 0; iter < col->filter_cnt; iter++) { - filter = col->filters[iter]; - sc_tmp = syscall; - - rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); - if (rc_tmp < 0) - goto rule_add_failure; - - /* if this is a pseudo syscall (syscall < 0) then we need to - * rewrite the rule for some arch specific reason */ - if (sc_tmp < 0) { - /* make a private copy of the chain */ - chain_tmp = malloc(chain_size); - if (chain_tmp == NULL) { - rc = -ENOMEM; - goto rule_add_failure; - } - memcpy(chain_tmp, chain, chain_size); - - /* mangle the private chain copy */ - rc_tmp = arch_filter_rewrite(filter->arch, strict, - &sc_tmp, chain_tmp); - if ((rc_tmp == -EDOM) && (!strict)) { - free(chain_tmp); - continue; - } - if (rc_tmp < 0) { - free(chain_tmp); - goto rule_add_failure; - } - - /* add the new rule to the existing filter */ - rc_tmp = db_rule_add(filter, action, sc_tmp, chain_tmp); - free(chain_tmp); - } else - /* add the new rule to the existing filter */ - rc_tmp = db_rule_add(filter, action, sc_tmp, chain); - -rule_add_failure: - if (rc == 0 && rc_tmp < 0) - rc = rc_tmp; - } - -rule_add_return: - if (chain != NULL) - free(chain); - return rc; -} - -/* NOTE - function header comment in include/seccomp.h */ -API int seccomp_rule_add_array(scmp_filter_ctx ctx, - uint32_t action, int syscall, - unsigned int arg_cnt, - const struct scmp_arg_cmp *arg_array) -{ - /* arg_cnt is unsigned, so no need to check the lower bound */ - if (arg_cnt > ARG_COUNT_MAX) - return -EINVAL; - - return _seccomp_rule_add((struct db_filter_col *)ctx, - 0, action, syscall, arg_cnt, arg_array); + return db_col_rule_add(col, 0, action, syscall, arg_cnt, arg_array); } /* NOTE - function header comment in include/seccomp.h */ @@ -558,12 +360,27 @@ API int seccomp_rule_add_exact_array(scmp_filter_ctx ctx, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array) { - /* arg_cnt is unsigned, so no need to check the lower bound */ + int rc; + struct db_filter_col *col = (struct db_filter_col *)ctx; + if (arg_cnt > ARG_COUNT_MAX) return -EINVAL; + if (arg_cnt > 0 && arg_array == NULL) + return -EINVAL; + + if (db_col_valid(col) || _syscall_valid(syscall)) + return -EINVAL; + + rc = db_action_valid(action); + if (rc < 0) + return rc; + if (action == col->attr.act_default) + return -EPERM; + + if (col->filter_cnt > 1) + return -EOPNOTSUPP; - return _seccomp_rule_add((struct db_filter_col *)ctx, - 1, action, syscall, arg_cnt, arg_array); + return db_col_rule_add(col, 1, action, syscall, arg_cnt, arg_array); } /* NOTE - function header comment in include/seccomp.h */ @@ -347,27 +347,132 @@ next: } /** - * Validate the seccomp action - * @param action the seccomp action + * Free and reset the seccomp filter DB + * @param db the seccomp filter DB + * + * This function frees any existing filters and resets the filter DB to a + * default state; only the DB architecture is preserved. * - * Verify that the given action is a valid seccomp action; return zero if - * valid, -EINVAL if invalid. */ -int db_action_valid(uint32_t action) +static void _db_reset(struct db_filter *db) { - if (action == SCMP_ACT_KILL) - return 0; - else if (action == SCMP_ACT_TRAP) - return 0; - else if ((action == SCMP_ACT_ERRNO(action & 0x0000ffff)) && - ((action & 0x0000ffff) < MAX_ERRNO)) - return 0; - else if (action == SCMP_ACT_TRACE(action & 0x0000ffff)) - return 0; - else if (action == SCMP_ACT_ALLOW) + struct db_sys_list *s_iter; + + if (db == NULL) + return; + + /* free any filters */ + if (db->syscalls != NULL) { + s_iter = db->syscalls; + while (s_iter != NULL) { + db->syscalls = s_iter->next; + _db_tree_free(s_iter->chains); + free(s_iter); + s_iter = db->syscalls; + } + db->syscalls = NULL; + } +} + +/** + * Intitalize a seccomp filter DB + * @param arch the architecture definition + * + * This function initializes a seccomp filter DB and readies it for use. + * Returns a pointer to the DB on success, NULL on failure. + * + */ +static struct db_filter *_db_init(const struct arch_def *arch) +{ + struct db_filter *db; + + db = malloc(sizeof(*db)); + if (db == NULL) + return NULL; + + /* clear the buffer for the first time and set the arch */ + memset(db, 0, sizeof(*db)); + db->arch = arch; + + /* reset the DB to a known state */ + _db_reset(db); + + return db; +} + +/** + * Destroy a seccomp filter DB + * @param db the seccomp filter DB + * + * This function destroys a seccomp filter DB. After calling this function, + * the filter should no longer be referenced. + * + */ +static void _db_release(struct db_filter *db) +{ + if (db == NULL) + return; + + /* free and reset the DB */ + _db_reset(db); + free(db); +} + +/** + * Update the user specified portion of the syscall priority + * @param db the seccomp filter db + * @param syscall the syscall number + * @param priority the syscall priority + * + * This function sets, or updates, the syscall priority; the highest priority + * value between the existing and specified value becomes the new syscall + * priority. If the syscall entry does not already exist, a new phantom + * syscall entry is created as a placeholder. Returns zero on success, + * negative values on failure. + * + */ +static int _db_syscall_priority(struct db_filter *db, + int syscall, uint8_t priority) +{ + unsigned int sys_pri = _DB_PRI_USER(priority); + struct db_sys_list *s_new, *s_iter, *s_prev = NULL; + + assert(db != NULL); + + s_iter = db->syscalls; + while (s_iter != NULL && s_iter->num < syscall) { + s_prev = s_iter; + s_iter = s_iter->next; + } + + /* matched an existing syscall entry */ + if (s_iter != NULL && s_iter->num == syscall) { + if (sys_pri > (s_iter->priority & _DB_PRI_MASK_USER)) { + s_iter->priority &= (~_DB_PRI_MASK_USER); + s_iter->priority |= sys_pri; + } return 0; + } - return -EINVAL; + /* no existing syscall entry - create a phantom entry */ + s_new = malloc(sizeof(*s_new)); + if (s_new == NULL) + return -ENOMEM; + memset(s_new, 0, sizeof(*s_new)); + s_new->num = syscall; + s_new->priority = sys_pri; + s_new->valid = false; + + /* add it before s_iter */ + if (s_prev != NULL) { + s_new->next = s_prev->next; + s_prev->next = s_new; + } else { + s_new->next = db->syscalls; + db->syscalls = s_new; + } + + return 0; } /** @@ -376,19 +481,22 @@ int db_action_valid(uint32_t action) * @param def_action the default filter action * * This function frees any existing filter DBs and resets the collection to a - * default state. + * default state. In the case of failure the filter collection may be in an + * unknown state and should be released. Returns zero on success, negative + * values on failure. * */ -void db_col_reset(struct db_filter_col *col, uint32_t def_action) +int db_col_reset(struct db_filter_col *col, uint32_t def_action) { unsigned int iter; + struct db_filter *db; if (col == NULL) - return; + return -EINVAL; /* free any filters */ for (iter = 0; iter < col->filter_cnt; iter++) - db_release(col->filters[iter]); + _db_release(col->filters[iter]); col->filter_cnt = 0; if (col->filters) free(col->filters); @@ -405,6 +513,17 @@ void db_col_reset(struct db_filter_col *col, uint32_t def_action) /* set the state */ col->state = _DB_STA_VALID; + + /* reset the initial db */ + db = _db_init(arch_def_native); + if (db == NULL) + return -ENOMEM; + if (db_col_db_add(col, db) < 0) { + _db_release(db); + return -ENOMEM; + } + + return 0; } /** @@ -427,9 +546,14 @@ struct db_filter_col *db_col_init(uint32_t def_action) memset(col, 0, sizeof(*col)); /* reset the DB to a known state */ - db_col_reset(col, def_action); + if (db_col_reset(col, def_action) < 0) + goto init_failure; return col; + +init_failure: + db_col_release(col); + return NULL; } /** @@ -442,18 +566,51 @@ struct db_filter_col *db_col_init(uint32_t def_action) */ void db_col_release(struct db_filter_col *col) { + unsigned int iter; + if (col == NULL) return; /* set the state, just in case */ col->state = _DB_STA_FREED; - /* free and reset the DB */ - db_col_reset(col, 0); + /* free any filters */ + for (iter = 0; iter < col->filter_cnt; iter++) + _db_release(col->filters[iter]); + col->filter_cnt = 0; + if (col->filters) + free(col->filters); + col->filters = NULL; + + /* free the collection */ free(col); } /** + * Validate the seccomp action + * @param action the seccomp action + * + * Verify that the given action is a valid seccomp action; return zero if + * valid, -EINVAL if invalid. + */ +int db_action_valid(uint32_t action) +{ + if (action == SCMP_ACT_KILL) + return 0; + else if (action == SCMP_ACT_TRAP) + return 0; + else if ((action == SCMP_ACT_ERRNO(action & 0x0000ffff)) && + ((action & 0x0000ffff) < MAX_ERRNO)) + return 0; + else if (action == SCMP_ACT_TRACE(action & 0x0000ffff)) + return 0; + else if (action == SCMP_ACT_ALLOW) + return 0; + + return -EINVAL; +} + +/** * Validate a filter collection * @param col the seccomp filter collection * @@ -619,6 +776,31 @@ int db_col_attr_set(struct db_filter_col *col, } /** + * Add a new architecture filter to a filter collection + * @param col the seccomp filter collection + * @param arch the architecture + * + * This function adds a new architecture filter DB to an existing seccomp + * filter collection assuming there isn't a filter DB already present with the + * same architecture. Returns zero on success, negative values on failure. + * + */ +int db_col_db_new(struct db_filter_col *col, const struct arch_def *arch) +{ + int rc; + struct db_filter *db; + + db = _db_init(arch); + if (db == NULL) + return -ENOMEM; + rc = db_col_db_add(col, db); + if (rc < 0) + _db_release(db); + + return rc; +} + +/** * Add a new filter DB to a filter collection * @param col the seccomp filter collection * @param db the seccomp filter DB @@ -673,7 +855,7 @@ int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token) if (found) col->filters[iter - 1] = col->filters[iter]; else if (col->filters[iter]->arch->token == arch_token) { - db_release(col->filters[iter]); + _db_release(col->filters[iter]); found = 1; } } @@ -698,134 +880,6 @@ int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token) } /** - * Free and reset the seccomp filter DB - * @param db the seccomp filter DB - * - * This function frees any existing filters and resets the filter DB to a - * default state; only the DB architecture is preserved. - * - */ -void db_reset(struct db_filter *db) -{ - struct db_sys_list *s_iter; - - if (db == NULL) - return; - - /* free any filters */ - if (db->syscalls != NULL) { - s_iter = db->syscalls; - while (s_iter != NULL) { - db->syscalls = s_iter->next; - _db_tree_free(s_iter->chains); - free(s_iter); - s_iter = db->syscalls; - } - db->syscalls = NULL; - } -} - -/** - * Intitalize a seccomp filter DB - * @param arch the architecture definition - * - * This function initializes a seccomp filter DB and readies it for use. - * Returns a pointer to the DB on success, NULL on failure. - * - */ -struct db_filter *db_init(const struct arch_def *arch) -{ - struct db_filter *db; - - db = malloc(sizeof(*db)); - if (db == NULL) - return NULL; - - /* clear the buffer for the first time and set the arch */ - memset(db, 0, sizeof(*db)); - db->arch = arch; - - /* reset the DB to a known state */ - db_reset(db); - - return db; -} - -/** - * Destroy a seccomp filter DB - * @param db the seccomp filter DB - * - * This function destroys a seccomp filter DB. After calling this function, - * the filter should no longer be referenced. - * - */ -void db_release(struct db_filter *db) -{ - if (db == NULL) - return; - - /* free and reset the DB */ - db_reset(db); - free(db); -} - -/** - * Update the user specified portion of the syscall priority - * @param db the seccomp filter db - * @param syscall the syscall number - * @param priority the syscall priority - * - * This function sets, or updates, the syscall priority; the highest priority - * value between the existing and specified value becomes the new syscall - * priority. If the syscall entry does not already exist, a new phantom - * syscall entry is created as a placeholder. Returns zero on success, - * negative values on failure. - * - */ -int db_syscall_priority(struct db_filter *db, int syscall, uint8_t priority) -{ - unsigned int sys_pri = _DB_PRI_USER(priority); - struct db_sys_list *s_new, *s_iter, *s_prev = NULL; - - assert(db != NULL); - - s_iter = db->syscalls; - while (s_iter != NULL && s_iter->num < syscall) { - s_prev = s_iter; - s_iter = s_iter->next; - } - - /* matched an existing syscall entry */ - if (s_iter != NULL && s_iter->num == syscall) { - if (sys_pri > (s_iter->priority & _DB_PRI_MASK_USER)) { - s_iter->priority &= (~_DB_PRI_MASK_USER); - s_iter->priority |= sys_pri; - } - return 0; - } - - /* no existing syscall entry - create a phantom entry */ - s_new = malloc(sizeof(*s_new)); - if (s_new == NULL) - return -ENOMEM; - memset(s_new, 0, sizeof(*s_new)); - s_new->num = syscall; - s_new->priority = sys_pri; - s_new->valid = false; - - /* add it before s_iter */ - if (s_prev != NULL) { - s_new->next = s_prev->next; - s_prev->next = s_new; - } else { - s_new->next = db->syscalls; - db->syscalls = s_new; - } - - return 0; -} - -/** * Test if the argument filter can be skipped because it's a tautology * @param arg argument filter * @@ -1129,8 +1183,8 @@ gen_32_failure: * filter DB. Returns zero on success, negative values on failure. * */ -int db_rule_add(struct db_filter *db, uint32_t action, int syscall, - struct db_api_arg *chain) +int _db_rule_add(struct db_filter *db, uint32_t action, int syscall, + struct db_api_arg *chain) { int rc = -ENOMEM; struct db_sys_list *s_new, *s_iter, *s_prev = NULL; @@ -1385,3 +1439,176 @@ add_priority_update: } return rc; } + +/** + * Set the priority of a given syscall + * @param col the filter collection + * @param syscall the syscall number + * @param priority priority value, higher value == higher priority + * + * This function sets the priority of the given syscall; this value is used + * when generating the seccomp filter code such that higher priority syscalls + * will incur less filter code overhead than the lower priority syscalls in the + * filter. Returns zero on success, negative values on failure. + * + */ +int db_col_syscall_priority(struct db_filter_col *col, + int syscall, uint8_t priority) +{ + int rc = 0, rc_tmp; + unsigned int iter; + int sc_tmp; + struct db_filter *filter; + + for (iter = 0; iter < col->filter_cnt; iter++) { + filter = col->filters[iter]; + sc_tmp = syscall; + + rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); + if (rc_tmp < 0) + goto priority_failure; + + /* if this is a pseudo syscall (syscall < 0) then we need to + * rewrite the syscall for some arch specific reason */ + if (sc_tmp < 0) { + /* we set this as a strict op - we don't really care + * since priorities are a "best effort" thing - as we + * want to catch the -EDOM error and bail on this + * architecture */ + rc_tmp = arch_syscall_rewrite(filter->arch, &sc_tmp); + if (rc_tmp == -EDOM) + continue; + if (rc_tmp < 0) + goto priority_failure; + } + + rc_tmp = _db_syscall_priority(filter, sc_tmp, priority); + +priority_failure: + if (rc == 0 && rc_tmp < 0) + rc = rc_tmp; + } + + return rc; +} + +/** + * Add a new rule to the current filter + * @param col the filter collection + * @param strict the strict flag + * @param action the filter action + * @param syscall the syscall number + * @param arg_cnt the number of argument filters in the argument filter chain + * @param arg_array the argument filter chain, (uint, enum scmp_compare, ulong) + * + * This function adds a new argument/comparison/value to the seccomp filter for + * a syscall; multiple arguments can be specified and they will be chained + * together (essentially AND'd together) in the filter. When the strict flag + * is true the function will fail if the exact rule can not be added to the + * filter, if the strict flag is false the function will not fail if the + * function needs to adjust the rule due to architecture specifics. Returns + * zero on success, negative values on failure. + * + */ +int db_col_rule_add(struct db_filter_col *col, + bool strict, uint32_t action, int syscall, + unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array) +{ + int rc = 0, rc_tmp; + int sc_tmp; + unsigned int iter; + unsigned int chain_len; + unsigned int arg_num; + size_t chain_size; + struct db_filter *filter; + struct db_api_arg *chain = NULL, *chain_tmp; + struct scmp_arg_cmp arg_data; + + /* collect the arguments for the filter rule */ + chain_len = ARG_COUNT_MAX; + chain_size = sizeof(*chain) * chain_len; + chain = malloc(chain_size); + if (chain == NULL) + return -ENOMEM; + memset(chain, 0, chain_size); + for (iter = 0; iter < arg_cnt; iter++) { + arg_data = arg_array[iter]; + arg_num = arg_data.arg; + if (arg_num < chain_len && chain[arg_num].valid == 0) { + chain[arg_num].valid = 1; + chain[arg_num].arg = arg_num; + chain[arg_num].op = arg_data.op; + /* XXX - we should check datum/mask size against the + * arch definition, e.g. 64 bit datum on x86 */ + switch (chain[arg_num].op) { + case SCMP_CMP_NE: + case SCMP_CMP_LT: + case SCMP_CMP_LE: + case SCMP_CMP_EQ: + case SCMP_CMP_GE: + case SCMP_CMP_GT: + chain[arg_num].mask = DATUM_MAX; + chain[arg_num].datum = arg_data.datum_a; + break; + case SCMP_CMP_MASKED_EQ: + chain[arg_num].mask = arg_data.datum_a; + chain[arg_num].datum = arg_data.datum_b; + break; + default: + rc = -EINVAL; + goto add_return; + } + } else { + rc = -EINVAL; + goto add_return; + } + } + + for (iter = 0; iter < col->filter_cnt; iter++) { + filter = col->filters[iter]; + sc_tmp = syscall; + + rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); + if (rc_tmp < 0) + goto add_failure; + + /* if this is a pseudo syscall (syscall < 0) then we need to + * rewrite the rule for some arch specific reason */ + if (sc_tmp < 0) { + /* make a private copy of the chain */ + chain_tmp = malloc(chain_size); + if (chain_tmp == NULL) { + rc = -ENOMEM; + goto add_failure; + } + memcpy(chain_tmp, chain, chain_size); + + /* mangle the private chain copy */ + rc_tmp = arch_filter_rewrite(filter->arch, strict, + &sc_tmp, chain_tmp); + if ((rc_tmp == -EDOM) && (!strict)) { + free(chain_tmp); + continue; + } + if (rc_tmp < 0) { + free(chain_tmp); + goto add_failure; + } + + /* add the new rule to the existing filter */ + rc_tmp = _db_rule_add(filter, action, sc_tmp, chain_tmp); + free(chain_tmp); + } else + /* add the new rule to the existing filter */ + rc_tmp = _db_rule_add(filter, action, sc_tmp, chain); + +add_failure: + if (rc == 0 && rc_tmp < 0) + rc = rc_tmp; + } + +add_return: + if (chain != NULL) + free(chain); + return rc; +} @@ -167,7 +167,7 @@ struct db_filter_col { int db_action_valid(uint32_t action); struct db_filter_col *db_col_init(uint32_t def_action); -void db_col_reset(struct db_filter_col *col, uint32_t def_action); +int db_col_reset(struct db_filter_col *col, uint32_t def_action); void db_col_release(struct db_filter_col *col); int db_col_valid(struct db_filter_col *col); @@ -181,16 +181,15 @@ int db_col_attr_get(const struct db_filter_col *col, int db_col_attr_set(struct db_filter_col *col, enum scmp_filter_attr attr, uint32_t value); +int db_col_db_new(struct db_filter_col *col, const struct arch_def *arch); int db_col_db_add(struct db_filter_col *col, struct db_filter *db); int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token); -struct db_filter *db_init(const struct arch_def *arch); -void db_reset(struct db_filter *db); -void db_release(struct db_filter *db); +int db_col_rule_add(struct db_filter_col *col, + bool strict, uint32_t action, int syscall, + unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array); -int db_syscall_priority(struct db_filter *db, int syscall, uint8_t priority); - -int db_rule_add(struct db_filter *db, uint32_t action, int syscall, - struct db_api_arg *chain); +int db_col_syscall_priority(struct db_filter_col *col, + int syscall, uint8_t priority); #endif |