/* * Author: Karl MacMillan <kmacmillan@tresys.com> * * Copyright (C) 2006 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 "test-deps.h" #include "parse_util.h" #include "helpers.h" #include <sepol/policydb/policydb.h> #include <sepol/policydb/link.h> #include <stdlib.h> /* Tests for dependency checking / handling, specifically: * * 1 type in module global. * 2 attribute in module global. * 3 object class / perm in module global. * 4 boolean in module global. * 5 role in module global. * * 6 type in module optional. * 7 attribute in module optional. * 8 object class / perm in module optional. * 9 boolean in module optional. * 10 role in module optional. * * 11 type in base optional. * 12 attribute in base optional. * 13 object class / perm in base optional. * 14 boolean in base optional. * 15 role in base optional. * * Each of these tests are done with the dependency met and not * met. Additionally, each of the required symbols is used in the * scope it is required. * * In addition to the simple tests, we have test with more complex * modules that test: * * 17 mutual dependencies between two modules. * 18 circular dependency between three modules. * 19 large number of dependencies in a module with a more complex base. * 20 nested optionals with requires. * * Again, each of these tests is done with the requirements met and not * met. */ #include <sepol/debug.h> #include <sepol/handle.h> #define BASE_MODREQ_TYPE_GLOBAL 0 #define BASE_MODREQ_ATTR_GLOBAL 1 #define BASE_MODREQ_OBJ_GLOBAL 2 #define BASE_MODREQ_BOOL_GLOBAL 3 #define BASE_MODREQ_ROLE_GLOBAL 4 #define BASE_MODREQ_PERM_GLOBAL 5 #define BASE_MODREQ_TYPE_OPT 6 #define BASE_MODREQ_ATTR_OPT 7 #define BASE_MODREQ_OBJ_OPT 8 #define BASE_MODREQ_BOOL_OPT 9 #define BASE_MODREQ_ROLE_OPT 10 #define BASE_MODREQ_PERM_OPT 11 #define NUM_BASES 12 static policydb_t bases_met[NUM_BASES]; static policydb_t bases_notmet[NUM_BASES]; extern int mls; int deps_test_init(void) { int i; /* To test linking we need 1 base per link test and in * order to load them in the init function we have * to keep them all around. Not ideal, but it shouldn't * matter too much. */ for (i = 0; i < NUM_BASES; i++) { if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf")) return -1; } for (i = 0; i < NUM_BASES; i++) { if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf")) return -1; } return 0; } int deps_test_cleanup(void) { int i; for (i = 0; i < NUM_BASES; i++) { policydb_destroy(&bases_met[i]); } for (i = 0; i < NUM_BASES; i++) { policydb_destroy(&bases_notmet[i]); } return 0; } /* This function performs testing of the dependency handles for module global * symbols. It is capable of testing 2 scenarios - the dependencies are met * and the dependencies are not met. * * Paramaters: * req_met boolean indicating whether the base policy meets the * requirements for the modules global block. * b index of the base policy in the global bases_met array. * * policy name of the policy module to load for this test. * decl_type name of the unique type found in the module's global * section is to find that avrule_decl. */ static void do_deps_modreq_global(int req_met, int b, char *policy, char *decl_type) { policydb_t *base; policydb_t mod; policydb_t *mods[] = { &mod }; avrule_decl_t *decl; int ret, link_ret; sepol_handle_t *h; /* suppress error reporting - this is because we know that we * are going to get errors and don't want libsepol complaining * about it constantly. */ h = sepol_handle_create(); CU_ASSERT_FATAL(h != NULL); sepol_msg_set_callback(h, NULL, NULL); if (req_met) { base = &bases_met[b]; link_ret = 0; } else { base = &bases_notmet[b]; link_ret = -3; } CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0); /* link the modules and check for the correct return value. */ ret = link_modules(h, base, mods, 1, 0); CU_ASSERT_FATAL(ret == link_ret); policydb_destroy(&mod); if (!req_met) return; decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type); CU_ASSERT_FATAL(decl != NULL); CU_ASSERT(decl->enabled == 1); } /* Test that symbol require statements in the global scope of a module * work correctly. This will cover tests 1 - 5 (described above). * * Each of these policies will require as few symbols as possible to * use the required symbol in addition requiring (for example, the type * test also requires an object class for an allow rule). */ static void deps_modreq_global(void) { /* object classes */ do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t"); /* types */ do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t"); /* attributes */ do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t"); /* booleans */ do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t"); /* roles */ do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t"); do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t"); } /* This function performs testing of the dependency handles for module optional * symbols. It is capable of testing 2 scenarios - the dependencies are met * and the dependencies are not met. * * Paramaters: * req_met boolean indicating whether the base policy meets the * requirements for the modules global block. * b index of the base policy in the global bases_met array. * * policy name of the policy module to load for this test. * decl_type name of the unique type found in the module's global * section is to find that avrule_decl. */ static void do_deps_modreq_opt(int req_met, int ret_val, int b, char *policy, char *decl_type) { policydb_t *base; policydb_t mod; policydb_t *mods[] = { &mod }; avrule_decl_t *decl; int ret; sepol_handle_t *h; /* suppress error reporting - this is because we know that we * are going to get errors and don't want libsepol complaining * about it constantly. */ h = sepol_handle_create(); CU_ASSERT_FATAL(h != NULL); sepol_msg_set_callback(h, NULL, NULL); if (req_met) { base = &bases_met[b]; } else { base = &bases_notmet[b]; } CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0); /* link the modules and check for the correct return value. */ ret = link_modules(h, base, mods, 1, 0); CU_ASSERT_FATAL(ret == ret_val); policydb_destroy(&mod); if (ret_val < 0) return; decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type); CU_ASSERT_FATAL(decl != NULL); if (req_met) { CU_ASSERT(decl->enabled == 1); } else { CU_ASSERT(decl->enabled == 0); } } /* Test that symbol require statements in the global scope of a module * work correctly. This will cover tests 6 - 10 (described above). * * Each of these policies will require as few symbols as possible to * use the required symbol in addition requiring (for example, the type * test also requires an object class for an allow rule). */ static void deps_modreq_opt(void) { /* object classes */ do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t"); /* types */ do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t"); /* attributes */ do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t"); /* booleans */ do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t"); /* roles */ do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t"); /* permissions */ do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t"); } int deps_add_tests(CU_pSuite suite) { if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) { return CU_get_error(); } if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) { return CU_get_error(); } return 0; }