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
140 changes: 79 additions & 61 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -1944,6 +1944,72 @@ static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch,
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,
struct db_arg_chain_tree *prev_nodes[4],
Copy link
Member

Choose a reason for hiding this comment

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

I'm thinking out-loud here, but I wonder if the readability would be better if the prev_nodes[] array was expanded into individual variables with more descriptive names?

Copy link
Member

Choose a reason for hiding this comment

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

Also, this function only appears to ever use one prev_nodes[] array slot, right?

bool *tf_flag)
{
struct db_arg_chain_tree *c_iter = NULL;
struct db_arg_chain_tree **node;

if (api_arg->valid == 0)
return 0;

/* skip generating instructions which are no-ops */
if (!_db_arg_cmp_need_lo(api_arg))
return 0;

c_iter = zmalloc(sizeof(*c_iter));
if (c_iter == NULL)
return -1;

c_iter->arg = api_arg->arg;
c_iter->arg_h_flg = false;
c_iter->arg_offset = arch_arg_offset(arch, c_iter->arg);
c_iter->op = api_arg->op;
c_iter->op_orig = api_arg->op;
/* implicitly strips off the upper 32 bit */
c_iter->mask = api_arg->mask;
c_iter->datum = api_arg->datum;
c_iter->datum_full = api_arg->datum;

/* link in the new node and update the chain */
for (node = prev_nodes; *node != NULL; node++)
if (*tf_flag)
(*node)->nxt_t = _db_node_get(c_iter);
else
(*node)->nxt_f = _db_node_get(c_iter);
Copy link
Member

Choose a reason for hiding this comment

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

I know braces ("{ ... }") aren't strictly required for this for-loop body, but please add them to help readability and prevent silly mistakes in the future.

prev_nodes[0] = c_iter;
prev_nodes[1] = NULL;
if (s_new->chains == NULL)
s_new->chains = _db_node_get(c_iter);
s_new->node_cnt++;

/* rewrite the op to reduce the op/datum combos */
switch (c_iter->op) {
case SCMP_CMP_NE:
c_iter->op = SCMP_CMP_EQ;
*tf_flag = false;
break;
case SCMP_CMP_LT:
c_iter->op = SCMP_CMP_GE;
*tf_flag = false;
break;
case SCMP_CMP_LE:
c_iter->op = SCMP_CMP_GT;
tf_flag = false;
break;
default:
*tf_flag = true;
}

/* fixup the mask/datum */
_db_node_mask_fixup(c_iter);

return 0;
}

/**
* Generate a new filter rule for a 32 bit system
* @param arch the architecture definition
Expand All @@ -1959,8 +2025,8 @@ static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,
unsigned int iter;
struct db_sys_list *s_new;
const struct db_api_arg *chain = rule->args;
struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL;
bool tf_flag;
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 tf_flag = false;

s_new = zmalloc(sizeof(*s_new));
if (s_new == NULL)
Expand All @@ -1969,67 +2035,19 @@ 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 (chain[iter].valid == 0)
continue;

/* skip generating instructions which are no-ops */
if (!_db_arg_cmp_need_lo(&chain[iter]))
continue;

c_iter = zmalloc(sizeof(*c_iter));
if (c_iter == NULL)
if (_db_rule_gen_arg_32(s_new, arch, &chain[iter],
prev_nodes, &tf_flag) < 0)
goto gen_32_failure;
c_iter->arg = chain[iter].arg;
c_iter->arg_h_flg = false;
c_iter->arg_offset = arch_arg_offset(arch, c_iter->arg);
c_iter->op = chain[iter].op;
c_iter->op_orig = chain[iter].op;
/* implicitly strips off the upper 32 bit */
c_iter->mask = chain[iter].mask;
c_iter->datum = chain[iter].datum;
c_iter->datum_full = chain[iter].datum;

/* link in the new node and update the chain */
if (c_prev != NULL) {
if (tf_flag)
c_prev->nxt_t = _db_node_get(c_iter);
else
c_prev->nxt_f = _db_node_get(c_iter);
} else
s_new->chains = _db_node_get(c_iter);
s_new->node_cnt++;

/* rewrite the op to reduce the op/datum combos */
switch (c_iter->op) {
case SCMP_CMP_NE:
c_iter->op = SCMP_CMP_EQ;
tf_flag = false;
break;
case SCMP_CMP_LT:
c_iter->op = SCMP_CMP_GE;
tf_flag = false;
break;
case SCMP_CMP_LE:
c_iter->op = SCMP_CMP_GT;
tf_flag = false;
break;
default:
tf_flag = true;
}

/* fixup the mask/datum */
_db_node_mask_fixup(c_iter);

c_prev = c_iter;
}
if (c_iter != NULL) {
/* set the leaf node */
if (tf_flag) {
c_iter->act_t_flg = true;
c_iter->act_t = rule->action;
} else {
c_iter->act_f_flg = true;
c_iter->act_f = rule->action;
if (s_new->chains != NULL) {
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;
Expand Down