1/*
2 * Author: Karl MacMillan <kmacmillan@tresys.com>
3 *
4 * Copyright (C) 2006 Tresys Technology, LLC
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2.1 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21#include "test-deps.h"
22#include "parse_util.h"
23#include "helpers.h"
24
25#include <sepol/policydb/policydb.h>
26#include <sepol/policydb/link.h>
27
28#include <stdlib.h>
29
30/* Tests for dependency checking / handling, specifically:
31 *
32 * 1 type in module global.
33 * 2 attribute in module global.
34 * 3 object class / perm in module global.
35 * 4 boolean in module global.
36 * 5 role in module global.
37 *
38 * 6 type in module optional.
39 * 7 attribute in module optional.
40 * 8 object class / perm in module optional.
41 * 9 boolean in module optional.
42 * 10 role in module optional.
43 *
44 * 11 type in base optional.
45 * 12 attribute in base optional.
46 * 13 object class / perm in base optional.
47 * 14 boolean in base optional.
48 * 15 role in base optional.
49 *
50 * Each of these tests are done with the dependency met and not
51 * met. Additionally, each of the required symbols is used in the
52 * scope it is required.
53 *
54 * In addition to the simple tests, we have test with more complex
55 * modules that test:
56 *
57 * 17 mutual dependencies between two modules.
58 * 18 circular dependency between three modules.
59 * 19 large number of dependencies in a module with a more complex base.
60 * 20 nested optionals with requires.
61 *
62 * Again, each of these tests is done with the requirements met and not
63 * met.
64 */
65
66#include <sepol/debug.h>
67#include <sepol/handle.h>
68
69#include "helpers.h"
70
71#define BASE_MODREQ_TYPE_GLOBAL    0
72#define BASE_MODREQ_ATTR_GLOBAL    1
73#define BASE_MODREQ_OBJ_GLOBAL     2
74#define BASE_MODREQ_BOOL_GLOBAL    3
75#define BASE_MODREQ_ROLE_GLOBAL    4
76#define BASE_MODREQ_PERM_GLOBAL    5
77#define BASE_MODREQ_TYPE_OPT       6
78#define BASE_MODREQ_ATTR_OPT       7
79#define BASE_MODREQ_OBJ_OPT        8
80#define BASE_MODREQ_BOOL_OPT       9
81#define BASE_MODREQ_ROLE_OPT       10
82#define BASE_MODREQ_PERM_OPT       11
83#define NUM_BASES                  12
84
85static policydb_t bases_met[NUM_BASES];
86static policydb_t bases_notmet[NUM_BASES];
87
88extern int mls;
89
90int deps_test_init(void)
91{
92	int i;
93
94	/* To test linking we need 1 base per link test and in
95	 * order to load them in the init function we have
96	 * to keep them all around. Not ideal, but it shouldn't
97	 * matter too much.
98	 */
99	for (i = 0; i < NUM_BASES; i++) {
100		if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
101			return -1;
102	}
103
104	for (i = 0; i < NUM_BASES; i++) {
105		if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
106			return -1;
107	}
108
109	return 0;
110}
111
112int deps_test_cleanup(void)
113{
114	int i;
115
116	for (i = 0; i < NUM_BASES; i++) {
117		policydb_destroy(&bases_met[i]);
118	}
119
120	for (i = 0; i < NUM_BASES; i++) {
121		policydb_destroy(&bases_notmet[i]);
122	}
123
124	return 0;
125}
126
127/* This function performs testing of the dependency handles for module global
128 * symbols. It is capable of testing 2 scenarios - the dependencies are met
129 * and the dependencies are not met.
130 *
131 * Parameters:
132 *  req_met            boolean indicating whether the base policy meets the
133 *                       requirements for the modules global block.
134 *  b                  index of the base policy in the global bases_met array.
135 *
136 *  policy             name of the policy module to load for this test.
137 *  decl_type          name of the unique type found in the module's global
138 *                       section is to find that avrule_decl.
139 */
140static void do_deps_modreq_global(int req_met, int b, const char *policy, const char *decl_type)
141{
142	policydb_t *base;
143	policydb_t mod;
144	policydb_t *mods[] = { &mod };
145	avrule_decl_t *decl;
146	int ret, link_ret;
147	sepol_handle_t *h;
148
149	/* suppress error reporting - this is because we know that we
150	 * are going to get errors and don't want libsepol complaining
151	 * about it constantly. */
152	h = sepol_handle_create();
153	CU_ASSERT_FATAL(h != NULL);
154	sepol_msg_set_callback(h, NULL, NULL);
155
156	if (req_met) {
157		base = &bases_met[b];
158		link_ret = 0;
159	} else {
160		base = &bases_notmet[b];
161		link_ret = -3;
162	}
163
164	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
165
166	/* link the modules and check for the correct return value.
167	 */
168	ret = link_modules(h, base, mods, 1, 0);
169	CU_ASSERT_FATAL(ret == link_ret);
170	policydb_destroy(&mod);
171	sepol_handle_destroy(h);
172
173	if (!req_met)
174		return;
175
176	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
177	CU_ASSERT_FATAL(decl != NULL);
178
179	CU_ASSERT(decl->enabled == 1);
180}
181
182/* Test that symbol require statements in the global scope of a module
183 * work correctly. This will cover tests 1 - 5 (described above).
184 *
185 * Each of these policies will require as few symbols as possible to
186 * use the required symbol in addition requiring (for example, the type
187 * test also requires an object class for an allow rule).
188 */
189static void deps_modreq_global(void)
190{
191	/* object classes */
192	do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
193	do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
194	/* types */
195	do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
196	do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
197	/* attributes */
198	do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
199	do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
200	/* booleans */
201	do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
202	do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
203	/* roles */
204	do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
205	do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
206	do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
207	do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
208}
209
210/* This function performs testing of the dependency handles for module optional
211 * symbols. It is capable of testing 2 scenarios - the dependencies are met
212 * and the dependencies are not met.
213 *
214 * Parameters:
215 *  req_met            boolean indicating whether the base policy meets the
216 *                       requirements for the modules global block.
217 *  b                  index of the base policy in the global bases_met array.
218 *
219 *  policy             name of the policy module to load for this test.
220 *  decl_type          name of the unique type found in the module's global
221 *                       section is to find that avrule_decl.
222 */
223static void do_deps_modreq_opt(int req_met, int ret_val, int b, const char *policy, const char *decl_type)
224{
225	policydb_t *base;
226	policydb_t mod;
227	policydb_t *mods[] = { &mod };
228	avrule_decl_t *decl;
229	int ret;
230	sepol_handle_t *h;
231
232	/* suppress error reporting - this is because we know that we
233	 * are going to get errors and don't want libsepol complaining
234	 * about it constantly. */
235	h = sepol_handle_create();
236	CU_ASSERT_FATAL(h != NULL);
237	sepol_msg_set_callback(h, NULL, NULL);
238
239	if (req_met) {
240		base = &bases_met[b];
241	} else {
242		base = &bases_notmet[b];
243	}
244
245	CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
246
247	/* link the modules and check for the correct return value.
248	 */
249	ret = link_modules(h, base, mods, 1, 0);
250	CU_ASSERT_FATAL(ret == ret_val);
251	policydb_destroy(&mod);
252	sepol_handle_destroy(h);
253	if (ret_val < 0)
254		return;
255
256	decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
257	CU_ASSERT_FATAL(decl != NULL);
258
259	if (req_met) {
260		CU_ASSERT(decl->enabled == 1);
261	} else {
262		CU_ASSERT(decl->enabled == 0);
263	}
264}
265
266/* Test that symbol require statements in the global scope of a module
267 * work correctly. This will cover tests 6 - 10 (described above).
268 *
269 * Each of these policies will require as few symbols as possible to
270 * use the required symbol in addition requiring (for example, the type
271 * test also requires an object class for an allow rule).
272 */
273static void deps_modreq_opt(void)
274{
275	/* object classes */
276	do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
277	do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
278	/* types */
279	do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
280	do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
281	/* attributes */
282	do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
283	do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
284	/* booleans */
285	do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
286	do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
287	/* roles */
288	do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
289	do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
290	/* permissions */
291	do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
292	do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
293}
294
295int deps_add_tests(CU_pSuite suite)
296{
297	if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
298		return CU_get_error();
299	}
300
301	if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
302		return CU_get_error();
303	}
304
305	return 0;
306}
307