libsepol: Refactored neverallow checking.
Instead of creating an expanded avtab, generating all of the avtab keys corresponding to a neverallow rule and searching for a match, walk the nodes in the avtab and use the attr_type_map and ebitmap functions to find matching rules. Memory usage is reduced from 370M to 125M and time is reduced from 14 sec to 2 sec. (Bounds checking commented out in both cases.) Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
This commit is contained in:
parent
88d09b6979
commit
9e6840e6a2
2 changed files with 194 additions and 82 deletions
|
@ -649,7 +649,7 @@ extern void level_datum_init(level_datum_t * x);
|
|||
extern void level_datum_destroy(level_datum_t * x);
|
||||
extern void cat_datum_init(cat_datum_t * x);
|
||||
extern void cat_datum_destroy(cat_datum_t * x);
|
||||
|
||||
extern int check_assertion(policydb_t *p, avrule_t *avrule);
|
||||
extern int check_assertions(sepol_handle_t * handle,
|
||||
policydb_t * p, avrule_t * avrules);
|
||||
|
||||
|
|
|
@ -27,11 +27,16 @@
|
|||
|
||||
#include "debug.h"
|
||||
|
||||
static void report_failure(sepol_handle_t *handle, policydb_t *p,
|
||||
const avrule_t * avrule,
|
||||
struct avtab_match_args {
|
||||
sepol_handle_t *handle;
|
||||
policydb_t *p;
|
||||
avrule_t *avrule;
|
||||
unsigned long errors;
|
||||
};
|
||||
|
||||
static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const class_perm_node_t *curperm,
|
||||
const avtab_ptr_t node)
|
||||
const class_perm_node_t *curperm, uint32_t perms)
|
||||
{
|
||||
if (avrule->source_filename) {
|
||||
ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };",
|
||||
|
@ -39,69 +44,208 @@ static void report_failure(sepol_handle_t *handle, policydb_t *p,
|
|||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
} else if (avrule->line) {
|
||||
ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
|
||||
avrule->line, p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
} else {
|
||||
ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long check_assertion_helper(sepol_handle_t * handle,
|
||||
policydb_t * p,
|
||||
avtab_t * te_avtab, avtab_t * te_cond_avtab,
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const avrule_t * avrule)
|
||||
static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
|
||||
{
|
||||
avtab_key_t avkey;
|
||||
avtab_ptr_t node;
|
||||
class_perm_node_t *curperm;
|
||||
unsigned long errors = 0;
|
||||
|
||||
for (curperm = avrule->perms; curperm != NULL; curperm = curperm->next) {
|
||||
avkey.source_type = stype + 1;
|
||||
avkey.target_type = ttype + 1;
|
||||
avkey.target_class = curperm->tclass;
|
||||
avkey.specified = AVTAB_ALLOWED;
|
||||
for (node = avtab_search_node(te_avtab, &avkey);
|
||||
node != NULL;
|
||||
node = avtab_search_node_next(node, avkey.specified)) {
|
||||
if (node->datum.data & curperm->data) {
|
||||
report_failure(handle, p, avrule, stype, ttype, curperm, node);
|
||||
errors++;
|
||||
}
|
||||
for (; cp; cp = cp->next) {
|
||||
if ((cp->tclass == class) && (cp->data & data)) {
|
||||
break;
|
||||
}
|
||||
for (node = avtab_search_node(te_cond_avtab, &avkey);
|
||||
node != NULL;
|
||||
node = avtab_search_node_next(node, avkey.specified)) {
|
||||
if (node->datum.data & curperm->data) {
|
||||
report_failure(handle, p, avrule, stype, ttype, curperm, node);
|
||||
errors++;
|
||||
}
|
||||
if (!cp)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
|
||||
{
|
||||
int rc = 0;
|
||||
struct avtab_match_args *a = (struct avtab_match_args *)args;
|
||||
sepol_handle_t *handle = a->handle;
|
||||
policydb_t *p = a->p;
|
||||
avrule_t *avrule = a->avrule;
|
||||
class_perm_node_t *cp;
|
||||
uint32_t perms;
|
||||
ebitmap_t src_matches, tgt_matches, matches;
|
||||
ebitmap_node_t *snode, *tnode;
|
||||
unsigned int i, j;
|
||||
|
||||
if (k->specified != AVTAB_ALLOWED)
|
||||
return 0;
|
||||
|
||||
if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
|
||||
return 0;
|
||||
|
||||
ebitmap_init(&src_matches);
|
||||
ebitmap_init(&tgt_matches);
|
||||
ebitmap_init(&matches);
|
||||
|
||||
rc = ebitmap_and(&src_matches, &avrule->stypes.types,
|
||||
&p->attr_type_map[k->source_type - 1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
if (ebitmap_length(&src_matches) == 0)
|
||||
goto exit;
|
||||
|
||||
if (avrule->flags == RULE_SELF) {
|
||||
rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
|
||||
if (rc)
|
||||
goto oom;
|
||||
} else {
|
||||
rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (ebitmap_length(&tgt_matches) == 0)
|
||||
goto exit;
|
||||
|
||||
for (cp = avrule->perms; cp; cp = cp->next) {
|
||||
perms = cp->data & d->data;
|
||||
if ((cp->tclass != k->target_class) || !perms) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ebitmap_for_each_bit(&src_matches, snode, i) {
|
||||
if (!ebitmap_node_get_bit(snode, i))
|
||||
continue;
|
||||
ebitmap_for_each_bit(&tgt_matches, tnode, j) {
|
||||
if (!ebitmap_node_get_bit(tnode, j))
|
||||
continue;
|
||||
a->errors++;
|
||||
report_failure(handle, p, avrule, i, j, cp, perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
goto exit;
|
||||
|
||||
oom:
|
||||
ERR(NULL, "Out of memory - unable to check neverallows");
|
||||
|
||||
exit:
|
||||
ebitmap_destroy(&src_matches);
|
||||
ebitmap_destroy(&tgt_matches);
|
||||
ebitmap_destroy(&matches);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args args;
|
||||
|
||||
args.handle = handle;
|
||||
args.p = p;
|
||||
args.avrule = avrule;
|
||||
args.errors = 0;
|
||||
|
||||
rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
return args.errors;
|
||||
|
||||
oom:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args *a = (struct avtab_match_args *)args;
|
||||
policydb_t *p = a->p;
|
||||
avrule_t *avrule = a->avrule;
|
||||
|
||||
if (k->specified != AVTAB_ALLOWED)
|
||||
goto exit;
|
||||
|
||||
if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
|
||||
goto exit;
|
||||
|
||||
rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
|
||||
if (rc == 0)
|
||||
goto exit;
|
||||
|
||||
if (avrule->flags == RULE_SELF) {
|
||||
/* If the neverallow uses SELF, then it is not enough that the
|
||||
* neverallow's source matches the src and tgt of the rule being checked.
|
||||
* It must match the same thing in the src and tgt, so AND the source
|
||||
* and target together and check for a match on the result.
|
||||
*/
|
||||
ebitmap_t match;
|
||||
rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] );
|
||||
if (rc) {
|
||||
ebitmap_destroy(&match);
|
||||
goto oom;
|
||||
}
|
||||
rc = ebitmap_match_any(&avrule->stypes.types, &match);
|
||||
ebitmap_destroy(&match);
|
||||
} else {
|
||||
rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
|
||||
}
|
||||
if (rc == 0)
|
||||
goto exit;
|
||||
|
||||
return 1;
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
ERR(NULL, "Out of memory - unable to check neverallows");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_assertion(policydb_t *p, avrule_t *avrule)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args args;
|
||||
|
||||
args.handle = NULL;
|
||||
args.p = p;
|
||||
args.avrule = avrule;
|
||||
args.errors = 0;
|
||||
|
||||
rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_assertions(sepol_handle_t * handle, policydb_t * p,
|
||||
avrule_t * avrules)
|
||||
{
|
||||
int rc;
|
||||
avrule_t *a;
|
||||
avtab_t te_avtab, te_cond_avtab;
|
||||
ebitmap_node_t *snode, *tnode;
|
||||
unsigned int i, j;
|
||||
unsigned long errors = 0;
|
||||
|
||||
if (!avrules) {
|
||||
|
@ -111,54 +255,22 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (avrules) {
|
||||
if (avtab_init(&te_avtab))
|
||||
goto oom;
|
||||
if (avtab_init(&te_cond_avtab)) {
|
||||
avtab_destroy(&te_avtab);
|
||||
goto oom;
|
||||
}
|
||||
if (expand_avtab(p, &p->te_avtab, &te_avtab) ||
|
||||
expand_avtab(p, &p->te_cond_avtab, &te_cond_avtab)) {
|
||||
avtab_destroy(&te_avtab);
|
||||
avtab_destroy(&te_cond_avtab);
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = avrules; a != NULL; a = a->next) {
|
||||
ebitmap_t *stypes = &a->stypes.types;
|
||||
ebitmap_t *ttypes = &a->ttypes.types;
|
||||
|
||||
if (!(a->specified & AVRULE_NEVERALLOW))
|
||||
continue;
|
||||
|
||||
ebitmap_for_each_bit(stypes, snode, i) {
|
||||
if (!ebitmap_node_get_bit(snode, i))
|
||||
continue;
|
||||
if (a->flags & RULE_SELF) {
|
||||
errors += check_assertion_helper
|
||||
(handle, p, &te_avtab, &te_cond_avtab, i, i,
|
||||
a);
|
||||
}
|
||||
ebitmap_for_each_bit(ttypes, tnode, j) {
|
||||
if (!ebitmap_node_get_bit(tnode, j))
|
||||
continue;
|
||||
errors += check_assertion_helper
|
||||
(handle, p, &te_avtab, &te_cond_avtab, i, j,
|
||||
a);
|
||||
rc = check_assertion(p, a);
|
||||
if (rc) {
|
||||
rc = report_assertion_failures(handle, p, a);
|
||||
if (rc < 0) {
|
||||
ERR(handle, "Error occurred while checking neverallows");
|
||||
return -1;
|
||||
}
|
||||
errors += rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors)
|
||||
ERR(handle, "%lu neverallow failures occurred", errors);
|
||||
|
||||
avtab_destroy(&te_avtab);
|
||||
avtab_destroy(&te_cond_avtab);
|
||||
return errors ? -1 : 0;
|
||||
|
||||
oom:
|
||||
ERR(handle, "Out of memory - unable to check neverallows");
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue