/** * @file * * Test the new domain transition analysis code introduced in SETools * 3.3. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * * Copyright (C) 2007 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #define POLICY TEST_POLICIES "/setools-3.3/apol/dta_test.policy.conf" static apol_policy_t *p = NULL; static void dta_forward(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_start_type(p, d, "tuna_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); apol_domain_trans_analysis_destroy(&d); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_PTR_NOT_NULL(v); qpol_policy_t *q = apol_policy_get_qpol(p); size_t i; for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name, *ep_name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "tuna_t"); qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(strcmp(name, "boat_t") == 0 || strcmp(name, "sand_t") == 0); qt = apol_domain_trans_result_get_entrypoint_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &ep_name); CU_ASSERT_EQUAL_FATAL(retval, 0); if (strcmp(name, "boat_t") == 0) { CU_ASSERT_STRING_EQUAL(ep_name, "net_t"); } else if (strcmp(name, "sand_t") == 0) { CU_ASSERT(strcmp(ep_name, "reel_t") == 0 || strcmp(ep_name, "wave_t") == 0); } } apol_vector_destroy(&v); } static void dta_forward_multi_end(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_start_type(p, d, "shark_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); apol_domain_trans_analysis_destroy(&d); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_PTR_NOT_NULL(v); CU_ASSERT(apol_vector_get_size(v) == 2); qpol_policy_t *q = apol_policy_get_qpol(p); size_t i; for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name, *ep_name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "shark_t"); qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(strcmp(name, "surf_t") == 0 || strcmp(name, "sand_t") == 0); qt = apol_domain_trans_result_get_entrypoint_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &ep_name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(ep_name, "wave_t"); } apol_vector_destroy(&v); } static void dta_forward_access(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_start_type(p, d, "tuna_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_access_type(p, d, "boat_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_access_type(p, d, "sand_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_access_type(p, d, "wave_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_class(p, d, "file"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_perm(p, d, "write"); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); qpol_policy_t *q = apol_policy_get_qpol(p); size_t i; for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "tuna_t"); qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "boat_t"); const apol_vector_t *rules_v = apol_domain_trans_result_get_access_rules(dtr); CU_ASSERT_FATAL(rules_v != NULL && apol_vector_get_size(rules_v) > 0); size_t j; for (j = 0; j < apol_vector_get_size(rules_v); j++) { const qpol_avrule_t *qa = (const qpol_avrule_t *)apol_vector_get_element(rules_v, j); char *render = apol_avrule_render(p, qa); CU_ASSERT_PTR_NOT_NULL_FATAL(render); CU_ASSERT_STRING_EQUAL(render, "allow boat_t wave_t : file { write getattr execute } ;"); free(render); } } apol_vector_destroy(&v); retval = apol_domain_trans_analysis_set_start_type(p, d, "boat_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_access_type(p, d, NULL); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_class(p, d, NULL); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_append_perm(p, d, NULL); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_policy_reset_domain_trans_table(p); retval = apol_domain_trans_analysis_do(p, d, &v); apol_domain_trans_analysis_destroy(&d); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "boat_t"); qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(strcmp(name, "sand_t") == 0 || strcmp(name, "dock_t") == 0); } apol_vector_destroy(&v); } static void dta_reverse(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval; retval = apol_domain_trans_analysis_set_start_type(p, d, "sand_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_REVERSE); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); apol_domain_trans_analysis_destroy(&d); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); qpol_policy_t *q = apol_policy_get_qpol(p); size_t i; for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "sand_t"); qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(strcmp(name, "boat_t") == 0 || strcmp(name, "grouper_t") == 0 || strcmp(name, "shark_t") == 0 || strcmp(name, "tuna_t") == 0); } apol_vector_destroy(&v); } static void dta_reverse_regexp(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval; retval = apol_domain_trans_analysis_set_start_type(p, d, "sand_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_REVERSE); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_result_regex(p, d, "u"); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); apol_domain_trans_analysis_destroy(&d); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); qpol_policy_t *q = apol_policy_get_qpol(p); size_t i; bool found_tuna_wave = false, found_grouper_reel = false, found_grouper_wave = false; for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name, *ep_name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(name, "sand_t"); qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(strcmp(name, "tuna_t") == 0 || strcmp(name, "grouper_t") == 0); qt = apol_domain_trans_result_get_entrypoint_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &ep_name); CU_ASSERT_EQUAL_FATAL(retval, 0); if (strcmp(name, "tuna_t") == 0) { if (strcmp(ep_name, "wave_t") == 0) { found_tuna_wave = true; } } else if (strcmp(name, "grouper_t") == 0) { if (strcmp(ep_name, "reel_t") == 0) { found_grouper_reel = true; } else if (strcmp(ep_name, "wave_t") == 0) { found_grouper_wave = true; } } } CU_ASSERT(found_tuna_wave && found_grouper_reel && found_grouper_wave); apol_vector_destroy(&v); } static void dta_reflexive(void) { apol_policy_reset_domain_trans_table(p); apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_start_type(p, d, "sand_t"); CU_ASSERT_EQUAL_FATAL(retval, 0); apol_vector_t *v = NULL; retval = apol_domain_trans_analysis_do(p, d, &v); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) == 0); apol_vector_destroy(&v); retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_REVERSE); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_do(p, d, &v); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); size_t i; qpol_policy_t *q = apol_policy_get_qpol(p); for (i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); const char *name; retval = qpol_type_get_name(q, qt, &name); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_NOT_EQUAL(name, "sand_t"); } apol_vector_destroy(&v); apol_domain_trans_analysis_destroy(&d); } struct dta_invalid_item { const char *start_type; const char *end_type; const char *entrypoint_type; const bool missing_proc_trans; const bool missing_entrypoint; const bool missing_exec; const bool missing_setexec; const bool missing_type_trans; bool used; }; static void dta_invalid(void) { struct dta_invalid_item items[] = { {"boat_t", "dock_t", "net_t", false, false, true, false, false, false}, {"boat_t", "sand_t", "reel_t", false, false, true, false, false, false}, {"crab_t", "dock_t", "net_t", false, false, false, true, false, false}, {"crab_t", "dock_t", "rope_t", false, false, true, true, false, false}, {"crab_t", "dock_t", "wave_t", false, true, true, false, false, false}, {"gull_t", "dock_t", "net_t", false, false, false, true, true, false}, {"gull_t", "dock_t", "rope_t", false, false, true, true, true, false}, {"gull_t", "sand_t", "net_t", true, true, false, false, false, false}, {"marlin_t", "boat_t", "line_t", false, false, true, false, false, false}, {"marlin_t", "boat_t", "net_t", false, false, true, false, false, false}, {"ray_t", "boat_t", "line_t", true, false, true, false, false, false}, {"ray_t", "sand_t", "wave_t", true, false, false, false, false, false}, {"shark_t", "sand_t", "reel_t", false, false, true, false, false, false}, {"tuna_t", "boat_t", "line_t", false, false, true, false, false, false}, {"tuna_t", "boat_t", "reel_t", false, true, false, false, false, false}, {NULL, NULL, NULL, false, false, false, false, false, false} }; const char *start_types[] = { "boat_t", "crab_t", "gull_t", "marlin_t", "ray_t", "shark_t", "tuna_t", NULL }; apol_domain_trans_analysis_t *d = apol_domain_trans_analysis_create(); CU_ASSERT_PTR_NOT_NULL_FATAL(d); int retval = apol_domain_trans_analysis_set_direction(p, d, APOL_DOMAIN_TRANS_DIRECTION_FORWARD); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_set_valid(p, d, APOL_DOMAIN_TRANS_SEARCH_INVALID); CU_ASSERT_EQUAL_FATAL(retval, 0); qpol_policy_t *q = apol_policy_get_qpol(p); apol_vector_t *v = NULL; struct dta_invalid_item *item; for (const char **start = start_types; *start != NULL; start++) { apol_policy_reset_domain_trans_table(p); retval = apol_domain_trans_analysis_set_start_type(p, d, *start); CU_ASSERT_EQUAL_FATAL(retval, 0); retval = apol_domain_trans_analysis_do(p, d, &v); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(v != NULL && apol_vector_get_size(v) > 0); for (size_t i = 0; i < apol_vector_get_size(v); i++) { const apol_domain_trans_result_t *dtr = (const apol_domain_trans_result_t *)apol_vector_get_element(v, i); const char *result_start, *result_end, *result_entry; const qpol_type_t *qt = apol_domain_trans_result_get_start_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &result_start); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT_STRING_EQUAL(result_start, *start); qt = apol_domain_trans_result_get_end_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &result_end); CU_ASSERT_EQUAL_FATAL(retval, 0); qt = apol_domain_trans_result_get_entrypoint_type(dtr); CU_ASSERT_PTR_NOT_NULL(qt); retval = qpol_type_get_name(q, qt, &result_entry); CU_ASSERT_EQUAL_FATAL(retval, 0); CU_ASSERT(apol_domain_trans_result_is_trans_valid(dtr) == 0); for (item = items + 0; item->start_type != NULL; item++) { if (strcmp(result_start, item->start_type) == 0 && strcmp(result_end, item->end_type) == 0 && strcmp(result_entry, item->entrypoint_type) == 0 && !item->used) { item->used = true; const apol_vector_t *cv; if (item->missing_proc_trans) { cv = apol_domain_trans_result_get_proc_trans_rules(dtr); CU_ASSERT(cv != NULL && apol_vector_get_size(cv) == 0); } if (item->missing_entrypoint) { cv = apol_domain_trans_result_get_entrypoint_rules(dtr); CU_ASSERT(cv != NULL && apol_vector_get_size(cv) == 0); } if (item->missing_exec) { cv = apol_domain_trans_result_get_exec_rules(dtr); CU_ASSERT(cv != NULL && apol_vector_get_size(cv) == 0); } if (item->missing_setexec) { cv = apol_domain_trans_result_get_setexec_rules(dtr); CU_ASSERT(cv != NULL && apol_vector_get_size(cv) == 0); } if (item->missing_type_trans) { cv = apol_domain_trans_result_get_type_trans_rules(dtr); CU_ASSERT(cv != NULL && apol_vector_get_size(cv) == 0); } break; } } if (item->start_type == NULL) { CU_FAIL(); } } apol_vector_destroy(&v); } for (item = items + 0; item->start_type != NULL; item++) { CU_ASSERT(item->used); } apol_domain_trans_analysis_destroy(&d); } CU_TestInfo dta_tests[] = { {"dta forward", dta_forward} , {"dta forward + access", dta_forward_access} , {"dta forward with multiple endpoints for same entrypoint", dta_forward_multi_end} , {"dta reverse", dta_reverse} , {"dta reverse + regexp", dta_reverse_regexp} , {"dta reflexive", dta_reflexive} , {"dta invalid transitions", dta_invalid} , CU_TEST_INFO_NULL }; int dta_init() { apol_policy_path_t *ppath = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, POLICY, NULL); if (ppath == NULL) { return 1; } if ((p = apol_policy_create_from_policy_path(ppath, QPOL_POLICY_OPTION_NO_NEVERALLOWS, NULL, NULL)) == NULL) { apol_policy_path_destroy(&ppath); return 1; } apol_policy_path_destroy(&ppath); int retval = apol_policy_build_domain_trans_table(p); if (retval != 0) { return 1; } return 0; } int dta_cleanup() { apol_policy_destroy(&p); return 0; }