diff --git a/README b/README index fa5e3409..1b60e280 100644 --- a/README +++ b/README @@ -168,6 +168,8 @@ CHECK IDS S-008: Unquoted gen_require block S-009: Permission macro suffix does not match class name S-010: Permission macro usage suggested + S-011: Interface should be decalred as template + S-012: Template can be declared as interface W-001: Type or attribute referenced without explicit declaration W-002: Type, attribute or role used but not listed in require block in interface diff --git a/src/check_hooks.h b/src/check_hooks.h index c5db22c7..86b600a8 100644 --- a/src/check_hooks.h +++ b/src/check_hooks.h @@ -41,6 +41,8 @@ enum style_ids { S_ID_UNQUOTE_GENREQ = 8, S_ID_PERM_SUFFIX = 9, S_ID_PERMMACRO = 10, + S_ID_TEXT_IF_PARAM = 11, + S_ID_VOID_TEMP_DECL = 12, S_END }; diff --git a/src/if_checks.c b/src/if_checks.c index d22c9f35..d381f514 100644 --- a/src/if_checks.c +++ b/src/if_checks.c @@ -232,6 +232,80 @@ struct check_result *check_unquoted_gen_require_block(__attribute__((unused)) co return NULL; } +struct check_result *check_text_param_in_interface(__attribute__((unused)) const struct + check_data *data, + const struct + policy_node *node) +{ + const char *if_name = node->data.str; + const struct interface_trait *trait = look_up_in_if_traits_map(if_name); + if (!trait || !trait->is_inferred) { + return NULL; + } + + for (int i = 0; i < TRAIT_MAX_PARAMETERS; i++) { + if (trait->parameters[i] == PARAM_TEXT) { + return make_check_result('S', S_ID_TEXT_IF_PARAM, + "Interface %s should be a template, due to parameter %d", + if_name, + i); + } + + if (trait->parameters[i] == PARAM_INITIAL) { + break; + } + } + + return NULL; +} + +struct check_result *check_unnecessary_template_definition(__attribute__((unused)) const struct + check_data *data, + const struct + policy_node *node) +{ + const char *temp_name = node->data.str; + const struct interface_trait *trait = look_up_in_if_traits_map(temp_name); + if (!trait || !trait->is_inferred) { + return NULL; + } + + for (int i = 0; i < TRAIT_MAX_PARAMETERS; i++) { + if (trait->parameters[i] == PARAM_TEXT) { + return NULL; + } + + if (trait->parameters[i] == PARAM_INITIAL) { + break; + } + } + + for (const struct policy_node *cur = node->first_child; cur; cur = dfs_next(cur)) { + if (cur == node || cur == node->next) { + break; + } + + if (cur->flavor == NODE_GEN_REQ || cur->flavor == NODE_REQUIRE) { + cur = cur->next; + } + + if (cur->flavor == NODE_DECL) { + return NULL; + } + + if (cur->flavor == NODE_IF_CALL) { + const struct if_call_data *ic_data = cur->data.ic_data; + if (look_up_in_template_map(ic_data->name)) { + return NULL; + } + } + } + + return make_check_result('S', S_ID_VOID_TEMP_DECL, + "Template %s might be declared as an interface", + temp_name); +} + struct check_result *check_name_used_but_not_required_in_if(const struct check_data *data, const struct diff --git a/src/if_checks.h b/src/if_checks.h index e93a2c19..bb01b53d 100644 --- a/src/if_checks.h +++ b/src/if_checks.h @@ -81,6 +81,30 @@ struct check_result *check_unquoted_gen_require_block(const struct const struct policy_node *node); +/********************************************* +* Check that an interface has no text parameter +* Called on NODE_INTERFACE_DEF nodes +* data - metadata about the file +* node - the node to check +* returns NULL if passed or check_result for issue S-011 +*********************************************/ +struct check_result *check_text_param_in_interface(const struct + check_data *data, + const struct + policy_node *node); + +/********************************************* +* Check for templates that can be declared as interface +* Called on NODE_TEMP_DEF nodes +* data - metadata about the file +* node - the node to check +* returns NULL if passed or check_result for issue S-012 +*********************************************/ +struct check_result *check_unnecessary_template_definition(const struct + check_data *data, + const struct + policy_node *node); + /********************************************* * Check that all names referenced in interface are listed in its require block * (or declared in that template) diff --git a/src/runner.c b/src/runner.c index 13927575..0fb4935c 100644 --- a/src/runner.c +++ b/src/runner.c @@ -189,6 +189,14 @@ struct checks *register_checks(char level, add_check(NODE_AV_RULE, ck, "S-010", check_perm_macro_available); } + if (CHECK_ENABLED("S-011")) { + add_check(NODE_INTERFACE_DEF, ck, "S-011", + check_text_param_in_interface); + } + if (CHECK_ENABLED("S-012")) { + add_check(NODE_TEMP_DEF, ck, "S-012", + check_unnecessary_template_definition); + } // FALLTHRU case 'W': if (CHECK_ENABLED("W-001")) { diff --git a/tests/Makefile.am b/tests/Makefile.am index bafd3e40..381b3448 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -157,6 +157,8 @@ FUNCTIONAL_TEST_FILES=functional/end-to-end.bats \ functional/policies/check_triggers/s08.if \ functional/policies/check_triggers/s09.pass.te \ functional/policies/check_triggers/s09.warn.te \ + functional/policies/check_triggers/s11.if \ + functional/policies/check_triggers/s12.if \ functional/policies/check_triggers/w01_other.te \ functional/policies/check_triggers/w01.te \ functional/policies/check_triggers/w02.if \ diff --git a/tests/functional/end-to-end.bats b/tests/functional/end-to-end.bats index b66cf5ae..e97b3abb 100644 --- a/tests/functional/end-to-end.bats +++ b/tests/functional/end-to-end.bats @@ -188,6 +188,14 @@ test_parse_error_impl() { test_one_check_expect "S-009" "s09.warn.te" 6 } +@test "S-011" { + test_one_check "S-011" "s11.if" +} + +@test "S-012" { + test_one_check "S-012" "s12.if" +} + @test "W-001" { test_one_check_expect "W-001" "w01*" 5 } diff --git a/tests/functional/policies/check_triggers/s11.if b/tests/functional/policies/check_triggers/s11.if new file mode 100644 index 00000000..d86815cb --- /dev/null +++ b/tests/functional/policies/check_triggers/s11.if @@ -0,0 +1,20 @@ +interface(`foo1', ` + gen_require(` + type foo_t; + ') + + allow $1 foo_t:file read; +') + +interface(`foo2', ` + gen_require(` + type foo_t; + ') + + allow $1_t foo_t:file read; +') + +interface(`foo3', ` + type foo_t; + allow $1 foo_t:file read; +') diff --git a/tests/functional/policies/check_triggers/s12.if b/tests/functional/policies/check_triggers/s12.if new file mode 100644 index 00000000..3148cf16 --- /dev/null +++ b/tests/functional/policies/check_triggers/s12.if @@ -0,0 +1,20 @@ +template(`foo1', ` + gen_require(` + type foo_t; + ') + + allow $1 foo_t:file read; +') + +template(`foo2', ` + gen_require(` + type foo_t; + ') + + allow $1_t foo_t:file read; +') + +template(`foo3', ` + type foo_t; + allow $1 foo_t:file read; +')