16cd6a6acSopenharmony_ci/*
26cd6a6acSopenharmony_ci * Author: Karl MacMillan <kmacmillan@tresys.com>
36cd6a6acSopenharmony_ci *
46cd6a6acSopenharmony_ci * Copyright (C) 2006 Tresys Technology, LLC
56cd6a6acSopenharmony_ci *
66cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
76cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
86cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
96cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
106cd6a6acSopenharmony_ci *
116cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
126cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
136cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
156cd6a6acSopenharmony_ci *
166cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
176cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
186cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
196cd6a6acSopenharmony_ci */
206cd6a6acSopenharmony_ci
216cd6a6acSopenharmony_ci#include "test-deps.h"
226cd6a6acSopenharmony_ci#include "parse_util.h"
236cd6a6acSopenharmony_ci#include "helpers.h"
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
266cd6a6acSopenharmony_ci#include <sepol/policydb/link.h>
276cd6a6acSopenharmony_ci
286cd6a6acSopenharmony_ci#include <stdlib.h>
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci/* Tests for dependency checking / handling, specifically:
316cd6a6acSopenharmony_ci *
326cd6a6acSopenharmony_ci * 1 type in module global.
336cd6a6acSopenharmony_ci * 2 attribute in module global.
346cd6a6acSopenharmony_ci * 3 object class / perm in module global.
356cd6a6acSopenharmony_ci * 4 boolean in module global.
366cd6a6acSopenharmony_ci * 5 role in module global.
376cd6a6acSopenharmony_ci *
386cd6a6acSopenharmony_ci * 6 type in module optional.
396cd6a6acSopenharmony_ci * 7 attribute in module optional.
406cd6a6acSopenharmony_ci * 8 object class / perm in module optional.
416cd6a6acSopenharmony_ci * 9 boolean in module optional.
426cd6a6acSopenharmony_ci * 10 role in module optional.
436cd6a6acSopenharmony_ci *
446cd6a6acSopenharmony_ci * 11 type in base optional.
456cd6a6acSopenharmony_ci * 12 attribute in base optional.
466cd6a6acSopenharmony_ci * 13 object class / perm in base optional.
476cd6a6acSopenharmony_ci * 14 boolean in base optional.
486cd6a6acSopenharmony_ci * 15 role in base optional.
496cd6a6acSopenharmony_ci *
506cd6a6acSopenharmony_ci * Each of these tests are done with the dependency met and not
516cd6a6acSopenharmony_ci * met. Additionally, each of the required symbols is used in the
526cd6a6acSopenharmony_ci * scope it is required.
536cd6a6acSopenharmony_ci *
546cd6a6acSopenharmony_ci * In addition to the simple tests, we have test with more complex
556cd6a6acSopenharmony_ci * modules that test:
566cd6a6acSopenharmony_ci *
576cd6a6acSopenharmony_ci * 17 mutual dependencies between two modules.
586cd6a6acSopenharmony_ci * 18 circular dependency between three modules.
596cd6a6acSopenharmony_ci * 19 large number of dependencies in a module with a more complex base.
606cd6a6acSopenharmony_ci * 20 nested optionals with requires.
616cd6a6acSopenharmony_ci *
626cd6a6acSopenharmony_ci * Again, each of these tests is done with the requirements met and not
636cd6a6acSopenharmony_ci * met.
646cd6a6acSopenharmony_ci */
656cd6a6acSopenharmony_ci
666cd6a6acSopenharmony_ci#include <sepol/debug.h>
676cd6a6acSopenharmony_ci#include <sepol/handle.h>
686cd6a6acSopenharmony_ci
696cd6a6acSopenharmony_ci#include "helpers.h"
706cd6a6acSopenharmony_ci
716cd6a6acSopenharmony_ci#define BASE_MODREQ_TYPE_GLOBAL    0
726cd6a6acSopenharmony_ci#define BASE_MODREQ_ATTR_GLOBAL    1
736cd6a6acSopenharmony_ci#define BASE_MODREQ_OBJ_GLOBAL     2
746cd6a6acSopenharmony_ci#define BASE_MODREQ_BOOL_GLOBAL    3
756cd6a6acSopenharmony_ci#define BASE_MODREQ_ROLE_GLOBAL    4
766cd6a6acSopenharmony_ci#define BASE_MODREQ_PERM_GLOBAL    5
776cd6a6acSopenharmony_ci#define BASE_MODREQ_TYPE_OPT       6
786cd6a6acSopenharmony_ci#define BASE_MODREQ_ATTR_OPT       7
796cd6a6acSopenharmony_ci#define BASE_MODREQ_OBJ_OPT        8
806cd6a6acSopenharmony_ci#define BASE_MODREQ_BOOL_OPT       9
816cd6a6acSopenharmony_ci#define BASE_MODREQ_ROLE_OPT       10
826cd6a6acSopenharmony_ci#define BASE_MODREQ_PERM_OPT       11
836cd6a6acSopenharmony_ci#define NUM_BASES                  12
846cd6a6acSopenharmony_ci
856cd6a6acSopenharmony_cistatic policydb_t bases_met[NUM_BASES];
866cd6a6acSopenharmony_cistatic policydb_t bases_notmet[NUM_BASES];
876cd6a6acSopenharmony_ci
886cd6a6acSopenharmony_ciextern int mls;
896cd6a6acSopenharmony_ci
906cd6a6acSopenharmony_ciint deps_test_init(void)
916cd6a6acSopenharmony_ci{
926cd6a6acSopenharmony_ci	int i;
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	/* To test linking we need 1 base per link test and in
956cd6a6acSopenharmony_ci	 * order to load them in the init function we have
966cd6a6acSopenharmony_ci	 * to keep them all around. Not ideal, but it shouldn't
976cd6a6acSopenharmony_ci	 * matter too much.
986cd6a6acSopenharmony_ci	 */
996cd6a6acSopenharmony_ci	for (i = 0; i < NUM_BASES; i++) {
1006cd6a6acSopenharmony_ci		if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
1016cd6a6acSopenharmony_ci			return -1;
1026cd6a6acSopenharmony_ci	}
1036cd6a6acSopenharmony_ci
1046cd6a6acSopenharmony_ci	for (i = 0; i < NUM_BASES; i++) {
1056cd6a6acSopenharmony_ci		if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
1066cd6a6acSopenharmony_ci			return -1;
1076cd6a6acSopenharmony_ci	}
1086cd6a6acSopenharmony_ci
1096cd6a6acSopenharmony_ci	return 0;
1106cd6a6acSopenharmony_ci}
1116cd6a6acSopenharmony_ci
1126cd6a6acSopenharmony_ciint deps_test_cleanup(void)
1136cd6a6acSopenharmony_ci{
1146cd6a6acSopenharmony_ci	int i;
1156cd6a6acSopenharmony_ci
1166cd6a6acSopenharmony_ci	for (i = 0; i < NUM_BASES; i++) {
1176cd6a6acSopenharmony_ci		policydb_destroy(&bases_met[i]);
1186cd6a6acSopenharmony_ci	}
1196cd6a6acSopenharmony_ci
1206cd6a6acSopenharmony_ci	for (i = 0; i < NUM_BASES; i++) {
1216cd6a6acSopenharmony_ci		policydb_destroy(&bases_notmet[i]);
1226cd6a6acSopenharmony_ci	}
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ci	return 0;
1256cd6a6acSopenharmony_ci}
1266cd6a6acSopenharmony_ci
1276cd6a6acSopenharmony_ci/* This function performs testing of the dependency handles for module global
1286cd6a6acSopenharmony_ci * symbols. It is capable of testing 2 scenarios - the dependencies are met
1296cd6a6acSopenharmony_ci * and the dependencies are not met.
1306cd6a6acSopenharmony_ci *
1316cd6a6acSopenharmony_ci * Parameters:
1326cd6a6acSopenharmony_ci *  req_met            boolean indicating whether the base policy meets the
1336cd6a6acSopenharmony_ci *                       requirements for the modules global block.
1346cd6a6acSopenharmony_ci *  b                  index of the base policy in the global bases_met array.
1356cd6a6acSopenharmony_ci *
1366cd6a6acSopenharmony_ci *  policy             name of the policy module to load for this test.
1376cd6a6acSopenharmony_ci *  decl_type          name of the unique type found in the module's global
1386cd6a6acSopenharmony_ci *                       section is to find that avrule_decl.
1396cd6a6acSopenharmony_ci */
1406cd6a6acSopenharmony_cistatic void do_deps_modreq_global(int req_met, int b, const char *policy, const char *decl_type)
1416cd6a6acSopenharmony_ci{
1426cd6a6acSopenharmony_ci	policydb_t *base;
1436cd6a6acSopenharmony_ci	policydb_t mod;
1446cd6a6acSopenharmony_ci	policydb_t *mods[] = { &mod };
1456cd6a6acSopenharmony_ci	avrule_decl_t *decl;
1466cd6a6acSopenharmony_ci	int ret, link_ret;
1476cd6a6acSopenharmony_ci	sepol_handle_t *h;
1486cd6a6acSopenharmony_ci
1496cd6a6acSopenharmony_ci	/* suppress error reporting - this is because we know that we
1506cd6a6acSopenharmony_ci	 * are going to get errors and don't want libsepol complaining
1516cd6a6acSopenharmony_ci	 * about it constantly. */
1526cd6a6acSopenharmony_ci	h = sepol_handle_create();
1536cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(h != NULL);
1546cd6a6acSopenharmony_ci	sepol_msg_set_callback(h, NULL, NULL);
1556cd6a6acSopenharmony_ci
1566cd6a6acSopenharmony_ci	if (req_met) {
1576cd6a6acSopenharmony_ci		base = &bases_met[b];
1586cd6a6acSopenharmony_ci		link_ret = 0;
1596cd6a6acSopenharmony_ci	} else {
1606cd6a6acSopenharmony_ci		base = &bases_notmet[b];
1616cd6a6acSopenharmony_ci		link_ret = -3;
1626cd6a6acSopenharmony_ci	}
1636cd6a6acSopenharmony_ci
1646cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
1656cd6a6acSopenharmony_ci
1666cd6a6acSopenharmony_ci	/* link the modules and check for the correct return value.
1676cd6a6acSopenharmony_ci	 */
1686cd6a6acSopenharmony_ci	ret = link_modules(h, base, mods, 1, 0);
1696cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(ret == link_ret);
1706cd6a6acSopenharmony_ci	policydb_destroy(&mod);
1716cd6a6acSopenharmony_ci	sepol_handle_destroy(h);
1726cd6a6acSopenharmony_ci
1736cd6a6acSopenharmony_ci	if (!req_met)
1746cd6a6acSopenharmony_ci		return;
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
1776cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(decl != NULL);
1786cd6a6acSopenharmony_ci
1796cd6a6acSopenharmony_ci	CU_ASSERT(decl->enabled == 1);
1806cd6a6acSopenharmony_ci}
1816cd6a6acSopenharmony_ci
1826cd6a6acSopenharmony_ci/* Test that symbol require statements in the global scope of a module
1836cd6a6acSopenharmony_ci * work correctly. This will cover tests 1 - 5 (described above).
1846cd6a6acSopenharmony_ci *
1856cd6a6acSopenharmony_ci * Each of these policies will require as few symbols as possible to
1866cd6a6acSopenharmony_ci * use the required symbol in addition requiring (for example, the type
1876cd6a6acSopenharmony_ci * test also requires an object class for an allow rule).
1886cd6a6acSopenharmony_ci */
1896cd6a6acSopenharmony_cistatic void deps_modreq_global(void)
1906cd6a6acSopenharmony_ci{
1916cd6a6acSopenharmony_ci	/* object classes */
1926cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
1936cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
1946cd6a6acSopenharmony_ci	/* types */
1956cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
1966cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
1976cd6a6acSopenharmony_ci	/* attributes */
1986cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
1996cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
2006cd6a6acSopenharmony_ci	/* booleans */
2016cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
2026cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
2036cd6a6acSopenharmony_ci	/* roles */
2046cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
2056cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
2066cd6a6acSopenharmony_ci	do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
2076cd6a6acSopenharmony_ci	do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
2086cd6a6acSopenharmony_ci}
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci/* This function performs testing of the dependency handles for module optional
2116cd6a6acSopenharmony_ci * symbols. It is capable of testing 2 scenarios - the dependencies are met
2126cd6a6acSopenharmony_ci * and the dependencies are not met.
2136cd6a6acSopenharmony_ci *
2146cd6a6acSopenharmony_ci * Parameters:
2156cd6a6acSopenharmony_ci *  req_met            boolean indicating whether the base policy meets the
2166cd6a6acSopenharmony_ci *                       requirements for the modules global block.
2176cd6a6acSopenharmony_ci *  b                  index of the base policy in the global bases_met array.
2186cd6a6acSopenharmony_ci *
2196cd6a6acSopenharmony_ci *  policy             name of the policy module to load for this test.
2206cd6a6acSopenharmony_ci *  decl_type          name of the unique type found in the module's global
2216cd6a6acSopenharmony_ci *                       section is to find that avrule_decl.
2226cd6a6acSopenharmony_ci */
2236cd6a6acSopenharmony_cistatic void do_deps_modreq_opt(int req_met, int ret_val, int b, const char *policy, const char *decl_type)
2246cd6a6acSopenharmony_ci{
2256cd6a6acSopenharmony_ci	policydb_t *base;
2266cd6a6acSopenharmony_ci	policydb_t mod;
2276cd6a6acSopenharmony_ci	policydb_t *mods[] = { &mod };
2286cd6a6acSopenharmony_ci	avrule_decl_t *decl;
2296cd6a6acSopenharmony_ci	int ret;
2306cd6a6acSopenharmony_ci	sepol_handle_t *h;
2316cd6a6acSopenharmony_ci
2326cd6a6acSopenharmony_ci	/* suppress error reporting - this is because we know that we
2336cd6a6acSopenharmony_ci	 * are going to get errors and don't want libsepol complaining
2346cd6a6acSopenharmony_ci	 * about it constantly. */
2356cd6a6acSopenharmony_ci	h = sepol_handle_create();
2366cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(h != NULL);
2376cd6a6acSopenharmony_ci	sepol_msg_set_callback(h, NULL, NULL);
2386cd6a6acSopenharmony_ci
2396cd6a6acSopenharmony_ci	if (req_met) {
2406cd6a6acSopenharmony_ci		base = &bases_met[b];
2416cd6a6acSopenharmony_ci	} else {
2426cd6a6acSopenharmony_ci		base = &bases_notmet[b];
2436cd6a6acSopenharmony_ci	}
2446cd6a6acSopenharmony_ci
2456cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
2466cd6a6acSopenharmony_ci
2476cd6a6acSopenharmony_ci	/* link the modules and check for the correct return value.
2486cd6a6acSopenharmony_ci	 */
2496cd6a6acSopenharmony_ci	ret = link_modules(h, base, mods, 1, 0);
2506cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(ret == ret_val);
2516cd6a6acSopenharmony_ci	policydb_destroy(&mod);
2526cd6a6acSopenharmony_ci	sepol_handle_destroy(h);
2536cd6a6acSopenharmony_ci	if (ret_val < 0)
2546cd6a6acSopenharmony_ci		return;
2556cd6a6acSopenharmony_ci
2566cd6a6acSopenharmony_ci	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
2576cd6a6acSopenharmony_ci	CU_ASSERT_FATAL(decl != NULL);
2586cd6a6acSopenharmony_ci
2596cd6a6acSopenharmony_ci	if (req_met) {
2606cd6a6acSopenharmony_ci		CU_ASSERT(decl->enabled == 1);
2616cd6a6acSopenharmony_ci	} else {
2626cd6a6acSopenharmony_ci		CU_ASSERT(decl->enabled == 0);
2636cd6a6acSopenharmony_ci	}
2646cd6a6acSopenharmony_ci}
2656cd6a6acSopenharmony_ci
2666cd6a6acSopenharmony_ci/* Test that symbol require statements in the global scope of a module
2676cd6a6acSopenharmony_ci * work correctly. This will cover tests 6 - 10 (described above).
2686cd6a6acSopenharmony_ci *
2696cd6a6acSopenharmony_ci * Each of these policies will require as few symbols as possible to
2706cd6a6acSopenharmony_ci * use the required symbol in addition requiring (for example, the type
2716cd6a6acSopenharmony_ci * test also requires an object class for an allow rule).
2726cd6a6acSopenharmony_ci */
2736cd6a6acSopenharmony_cistatic void deps_modreq_opt(void)
2746cd6a6acSopenharmony_ci{
2756cd6a6acSopenharmony_ci	/* object classes */
2766cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
2776cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
2786cd6a6acSopenharmony_ci	/* types */
2796cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
2806cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
2816cd6a6acSopenharmony_ci	/* attributes */
2826cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
2836cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
2846cd6a6acSopenharmony_ci	/* booleans */
2856cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
2866cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
2876cd6a6acSopenharmony_ci	/* roles */
2886cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
2896cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
2906cd6a6acSopenharmony_ci	/* permissions */
2916cd6a6acSopenharmony_ci	do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
2926cd6a6acSopenharmony_ci	do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
2936cd6a6acSopenharmony_ci}
2946cd6a6acSopenharmony_ci
2956cd6a6acSopenharmony_ciint deps_add_tests(CU_pSuite suite)
2966cd6a6acSopenharmony_ci{
2976cd6a6acSopenharmony_ci	if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
2986cd6a6acSopenharmony_ci		return CU_get_error();
2996cd6a6acSopenharmony_ci	}
3006cd6a6acSopenharmony_ci
3016cd6a6acSopenharmony_ci	if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
3026cd6a6acSopenharmony_ci		return CU_get_error();
3036cd6a6acSopenharmony_ci	}
3046cd6a6acSopenharmony_ci
3056cd6a6acSopenharmony_ci	return 0;
3066cd6a6acSopenharmony_ci}
307