Skip to content

Commit

Permalink
libsepol/cil: Allow duplicate optional blocks in most cases
Browse files Browse the repository at this point in the history
The commit d155b41 (libsepol/cil:
Check for duplicate blocks, optionals, and macros) fixed a bug
that allowed duplicate blocks, optionals, and macros with the same
name in the same namespace. For blocks and macros, a duplicate
is always a problem, but optional block names are only used for
in-statement resolution. If no in-statement refers to an optional
block, then it does not matter if more than one with same name
exists.

One easy way to generate multiple optional blocks with the same
name declaration is to call a macro with an optional block multiple
times in the same namespace.

As an example, here is a portion of CIL policy
  (macro m1 ((type t))
    (optional op1
      (allow t self (CLASS (PERM)))
    )
  )
  (type t1)
  (call m1 (t1))
  (type t2)
  (call m1 (t2))
This will result in two optional blocks with the name op1.

There are three parts to allowing multiple optional blocks with
the same name declaration.

1) Track an optional block's enabled status in a different way.

   One hinderance to allowing multiple optional blocks with the same
   name declaration is that they cannot share the same datum. This is
   because the datum is used to get the struct cil_optional which has
   the enabled field and each block's enabled status is independent of
   the others.

   Remove the enabled field from struct cil_optional, so it only contains
   the datum. Use a stack to track which optional blocks are being
   disabled, so they can be deleted in the right order.

2) Allow multiple declarations of optional blocks.

   Update cil_allow_multiple_decls() so that a flavor of CIL_OPTIONAL
   will return CIL_TRUE. Also remove the check in cil_copy_optional().

3) Check if an in-statement refers to an optional with multiple
   declarations and exit with an error if it does.

Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
  • Loading branch information
jwcart2 committed Jun 24, 2021
1 parent 9fb8df7 commit 67a8dc8
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 34 deletions.
1 change: 0 additions & 1 deletion libsepol/cil/src/cil.c
Expand Up @@ -2752,7 +2752,6 @@ void cil_call_init(struct cil_call **call)
void cil_optional_init(struct cil_optional **optional)
{
*optional = cil_malloc(sizeof(**optional));
(*optional)->enabled = CIL_TRUE;
cil_symtab_datum_init(&(*optional)->datum);
}

Expand Down
3 changes: 3 additions & 0 deletions libsepol/cil/src/cil_build_ast.c
Expand Up @@ -96,6 +96,9 @@ static int cil_allow_multiple_decls(struct cil_db *db, enum cil_flavor f_new, en
return CIL_TRUE;
}
break;
case CIL_OPTIONAL:
return CIL_TRUE;
break;
default:
break;
}
Expand Down
11 changes: 1 addition & 10 deletions libsepol/cil/src/cil_copy_ast.c
Expand Up @@ -1529,19 +1529,10 @@ int cil_copy_macro(__attribute__((unused)) struct cil_db *db, void *data, void *
return SEPOL_OK;
}

int cil_copy_optional(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
int cil_copy_optional(__attribute__((unused)) struct cil_db *db, __attribute__((unused)) void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
{
struct cil_optional *orig = data;
char *key = orig->datum.name;
struct cil_symtab_datum *datum = NULL;
struct cil_optional *new;

cil_symtab_get_datum(symtab, key, &datum);
if (datum != NULL) {
cil_tree_log(NODE(datum), CIL_ERR, "Re-declaration of %s %s", cil_node_to_string(NODE(datum)), key);
return SEPOL_ERR;
}

cil_optional_init(&new);
*copy = new;

Expand Down
1 change: 0 additions & 1 deletion libsepol/cil/src/cil_internal.h
Expand Up @@ -358,7 +358,6 @@ struct cil_in {

struct cil_optional {
struct cil_symtab_datum datum;
int enabled;
};

struct cil_perm {
Expand Down
55 changes: 33 additions & 22 deletions libsepol/cil/src/cil_resolve_ast.c
Expand Up @@ -46,12 +46,13 @@
#include "cil_verify.h"
#include "cil_strpool.h"
#include "cil_symtab.h"
#include "cil_stack.h"

struct cil_args_resolve {
struct cil_db *db;
enum cil_pass pass;
uint32_t *changed;
struct cil_list *disabled_optionals;
struct cil_list *to_destroy;
struct cil_tree_node *block;
struct cil_tree_node *macro;
struct cil_tree_node *optional;
Expand All @@ -62,6 +63,7 @@ struct cil_args_resolve {
struct cil_list *catorder_lists;
struct cil_list *sensitivityorder_lists;
struct cil_list *in_list;
struct cil_stack *disabled_optionals;
};

static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node)
Expand Down Expand Up @@ -2552,6 +2554,15 @@ int cil_resolve_in(struct cil_tree_node *current, void *extra_args)

block_node = NODE(block_datum);

if (block_node->flavor == CIL_OPTIONAL) {
if (block_datum->nodes && block_datum->nodes->head != block_datum->nodes->tail) {
cil_tree_log(current, CIL_ERR, "Multiple optional blocks referred to by in-statement");
cil_tree_log(block_node, CIL_ERR, "First optional block");
rc = SEPOL_ERR;
goto exit;
}
}

rc = cil_copy_ast(db, current, block_node);
if (rc != SEPOL_OK) {
cil_tree_log(current, CIL_ERR, "Failed to copy in-statement");
Expand Down Expand Up @@ -3874,6 +3885,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished
struct cil_tree_node *macro = args->macro;
struct cil_tree_node *optional = args->optional;
struct cil_tree_node *boolif = args->boolif;
struct cil_stack *disabled_optionals = args->disabled_optionals;

if (node == NULL) {
goto exit;
Expand Down Expand Up @@ -3953,22 +3965,14 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, uint32_t *finished

rc = __cil_resolve_ast_node(node, extra_args);
if (rc == SEPOL_ENOENT) {
enum cil_log_level lvl = CIL_ERR;

if (optional != NULL) {
struct cil_optional *opt = (struct cil_optional *)optional->data;
struct cil_tree_node *opt_node = NODE(opt);

lvl = CIL_INFO;
/* disable an optional if something failed to resolve */
opt->enabled = CIL_FALSE;
cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node));
cil_tree_log(opt_node, lvl, "Disabling optional '%s'", opt->datum.name);
if (optional == NULL) {
cil_tree_log(node, CIL_ERR, "Failed to resolve %s statement", cil_node_to_string(node));
} else {
cil_stack_push(disabled_optionals, CIL_NODE, optional);
cil_tree_log(node, CIL_INFO, "Failed to resolve %s statement", cil_node_to_string(node));
cil_tree_log(optional, CIL_INFO, "Disabling optional '%s'", DATUM(optional->data)->name);
rc = SEPOL_OK;
goto exit;
}

cil_tree_log(node, lvl, "Failed to resolve %s statement", cil_node_to_string(node));
goto exit;
}

Expand Down Expand Up @@ -4011,6 +4015,7 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext
{
int rc = SEPOL_ERR;
struct cil_args_resolve *args = extra_args;
struct cil_stack *disabled_optionals = args->disabled_optionals;
struct cil_tree_node *parent = NULL;

if (current == NULL || extra_args == NULL) {
Expand All @@ -4033,9 +4038,11 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext
args->macro = NULL;
} else if (parent->flavor == CIL_OPTIONAL) {
struct cil_tree_node *n = parent->parent;
if (((struct cil_optional *)parent->data)->enabled == CIL_FALSE) {
struct cil_stack_item *item = cil_stack_peek(disabled_optionals);
if (item && item->data == parent) {
cil_stack_pop(disabled_optionals);
*(args->changed) = CIL_TRUE;
cil_list_append(args->disabled_optionals, CIL_NODE, parent);
cil_list_append(args->to_destroy, CIL_NODE, parent);
}
args->optional = NULL;
while (n && n->flavor != CIL_ROOT) {
Expand Down Expand Up @@ -4079,14 +4086,17 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
extra_args.catorder_lists = NULL;
extra_args.sensitivityorder_lists = NULL;
extra_args.in_list = NULL;
extra_args.disabled_optionals = NULL;

cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
cil_list_init(&extra_args.to_destroy, CIL_NODE);
cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.in_list, CIL_IN);
cil_stack_init(&extra_args.disabled_optionals);

for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
extra_args.pass = pass;
rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args);
Expand Down Expand Up @@ -4179,11 +4189,11 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
goto exit;
}
}
cil_list_for_each(item, extra_args.disabled_optionals) {
cil_list_for_each(item, extra_args.to_destroy) {
cil_tree_children_destroy(item->data);
}
cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
cil_list_destroy(&extra_args.to_destroy, CIL_FALSE);
cil_list_init(&extra_args.to_destroy, CIL_NODE);
changed = 0;
}
}
Expand All @@ -4200,8 +4210,9 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
__cil_ordered_lists_destroy(&extra_args.catorder_lists);
__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
__cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists);
cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
cil_list_destroy(&extra_args.to_destroy, CIL_FALSE);
cil_list_destroy(&extra_args.in_list, CIL_FALSE);
cil_stack_destroy(&extra_args.disabled_optionals);

return rc;
}
Expand Down

0 comments on commit 67a8dc8

Please sign in to comment.