Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFE: add support for comparisons against 32-bit arguments #384

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
98 changes: 37 additions & 61 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,18 @@ static void _db_node_mask_fixup(struct db_arg_chain_tree *node)
node->datum &= node->mask;
}

/**
* Generate tree nodes for a 64 bit argument comparison
* @param s_new the syscall filter
* @param arch the architecture definition
* @param api_arg the argument comparison
* @param prev_nodes a NULL terminated array of tree nodes to link to
* @param tf_flag whether to link to the nxt_t or nxt_f branch of prev_nodes
*
* This function generates tree nodes representing a 64 bit argument
* comparison. Returns zero on success, negative values on failure.
*
*/
static int _db_rule_gen_arg_64(struct db_sys_list *s_new,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a comment block describing the function, see the others for an example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so it looks like it is added in 0936a72 ("db: merge _db_rule_gen_64 and _db_rule_gen_32"); it would be best to add the comment block in the first appearance of the function.

const struct arch_def *arch,
const struct db_api_arg *api_arg,
Expand Down Expand Up @@ -1892,57 +1904,17 @@ static int _db_rule_gen_arg_64(struct db_sys_list *s_new,
}

/**
* Generate a new filter rule for a 64 bit system
* Generate tree nodes for a 32 bit argument comparison
* @param s_new the syscall filter
* @param arch the architecture definition
* @param rule the new filter rule
* @param api_arg the argument comparison
* @param prev_nodes a NULL terminated array of tree nodes to link to
* @param tf_flag whether to link to the nxt_t or nxt_f branch of prev_nodes
*
* This function generates a new syscall filter for a 64 bit system. Returns
* zero on success, negative values on failure.
* This function generates tree nodes representing a 32 bit argument
* comparison. Returns zero on success, negative values on failure.
*
*/
static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch,
const struct db_api_rule_list *rule)
{
unsigned int iter;
struct db_sys_list *s_new;
const struct db_api_arg *chain = rule->args;
struct db_arg_chain_tree *prev_nodes[4] = { NULL, };
bool tf_flag = false;

s_new = zmalloc(sizeof(*s_new));
if (s_new == NULL)
return NULL;
s_new->num = rule->syscall;
s_new->valid = true;
/* run through the argument chain */
for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
if (_db_rule_gen_arg_64(s_new, arch, &chain[iter],
prev_nodes, &tf_flag) < 0)
goto gen_64_failure;
}
if (s_new->chains != NULL) {
/* set the actions on the last layer */
for (iter = 0; prev_nodes[iter] != NULL; iter++) {
if (tf_flag) {
prev_nodes[iter]->act_t_flg = true;
prev_nodes[iter]->act_t = rule->action;
} else {
prev_nodes[iter]->act_f_flg = true;
prev_nodes[iter]->act_f = rule->action;
}
}
} else
s_new->action = rule->action;

return s_new;

gen_64_failure:
/* free the new chain and its syscall struct */
_db_tree_put(&s_new->chains);
free(s_new);
return NULL;
}

static int _db_rule_gen_arg_32(struct db_sys_list *s_new,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self as much as anything - I don't see this function having any code coverage even though it's getting called 500,000+ times.

https://coveralls.io/builds/49252361/source?filename=src%2Fdb.c#L1918

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think something is broken for me and coveralls.io, I'm not able to see the marked-up source anymore ... :/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, it looks like I just needed to re-auth to coveralls.io.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Back to the original comment ... yes, something is odd here, both the 64-bit and 32-bit variants of this function appear to have zero code coverage, which is not right ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function also needs a comment block at the top like all the other functions in libseccomp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as with the 64-bit variant, it looks like the comment block is added in 0936a72 ("db: merge _db_rule_gen_64 and _db_rule_gen_32"); it would be best to add the comment block in the first appearance of the function.

const struct arch_def *arch,
const struct db_api_arg *api_arg,
Expand Down Expand Up @@ -2010,21 +1982,22 @@ static int _db_rule_gen_arg_32(struct db_sys_list *s_new,
}

/**
* Generate a new filter rule for a 32 bit system
* Generate a new filter rule
* @param arch the architecture definition
* @param rule the new filter rule
*
* This function generates a new syscall filter for a 32 bit system. Returns
* zero on success, negative values on failure.
* This function generates a new syscall filter. Returns
* an allocated db_sys_struct on success, NULL on failure.
*
*/
static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,
const struct db_api_rule_list *rule)
static struct db_sys_list *_db_rule_gen(const struct arch_def *arch,
const struct db_api_rule_list *rule)
{
unsigned int iter;
struct db_sys_list *s_new;
const struct db_api_arg *chain = rule->args;
struct db_arg_chain_tree *prev_nodes[4] = { NULL, };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another note to self - the prev_nodes[] change will become important in later commits. This commit is (slightly) more than just a refactoring of code to a separate function.

Copy link
Member

@pcmoore pcmoore Jul 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fixed 4 is very "magic" too, which makes me uneasy. At the very least that needs a comment (why 4?), but a much better approach would be a macro definition and and comment with the macro.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I now understand where the 4 comes from, and to be fair we have similar constants in the current _db_rule_gen_64() function, but the important difference is that in the current implementation the magic numbers are contained as local variables within the function, here they are part of the function's signature and are thus much more important.

Copy link
Member

@pcmoore pcmoore Jul 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hoping that as I get farther into this review we can revisit how this code was extracted, because I'm not really liking this right now.

bool is_32bit = arch->size == ARCH_SIZE_32;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since is_32bit is only used once below, why not just drop the dedicated local variable and just do the arch->size comparison where needed?

bool tf_flag = false;

s_new = zmalloc(sizeof(*s_new));
Expand All @@ -2034,9 +2007,15 @@ static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,
s_new->valid = true;
/* run through the argument chain */
for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
if (_db_rule_gen_arg_32(s_new, arch, &chain[iter],
prev_nodes, &tf_flag) < 0)
goto gen_32_failure;
if (is_32bit) {
if (_db_rule_gen_arg_32(s_new, arch, &chain[iter],
prev_nodes, &tf_flag) < 0)
goto gen_failure;
} else {
if (_db_rule_gen_arg_64(s_new, arch, &chain[iter],
prev_nodes, &tf_flag) < 0)
goto gen_failure;
}
}
if (s_new->chains != NULL) {
for (iter = 0; prev_nodes[iter] != NULL; iter++) {
Expand All @@ -2053,7 +2032,7 @@ static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,

return s_new;

gen_32_failure:
gen_failure:
/* free the new chain and its syscall struct */
_db_tree_put(&s_new->chains);
free(s_new);
Expand Down Expand Up @@ -2088,12 +2067,9 @@ int db_rule_add(struct db_filter *db, const struct db_api_rule_list *rule)
/* do all our possible memory allocation up front so we don't have to
* worry about failure once we get to the point where we start updating
* the filter db */
if (db->arch->size == ARCH_SIZE_64)
s_new = _db_rule_gen_64(db->arch, rule);
else if (db->arch->size == ARCH_SIZE_32)
s_new = _db_rule_gen_32(db->arch, rule);
else
if (db->arch->size != ARCH_SIZE_64 && db->arch->size != ARCH_SIZE_32)
return -EFAULT;
s_new = _db_rule_gen(db->arch, rule);
if (s_new == NULL)
return -ENOMEM;

Expand Down