• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Author: Mary Garvin <mgarvin@tresys.com>
3  *
4  * Copyright (C) 2007-2008 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-downgrade.h"
22 #include "parse_util.h"
23 #include "helpers.h"
24 
25 #include <sepol/debug.h>
26 #include <sepol/handle.h>
27 #include <sepol/policydb/policydb.h>
28 #include <sepol/policydb/link.h>
29 #include <sepol/policydb/expand.h>
30 #include <sepol/policydb/conditional.h>
31 #include <limits.h>
32 #include <CUnit/Basic.h>
33 
34 #define POLICY_BIN_HI	"policies/test-downgrade/policy.hi"
35 #define POLICY_BIN_LO	"policies/test-downgrade/policy.lo"
36 
37 static policydb_t policydb;
38 
39 /*
40  * Function Name:  downgrade_test_init
41  *
42  * Input: None
43  *
44  * Output: None
45  *
46  * Description: Initialize the policydb (policy data base structure)
47  */
downgrade_test_init(void)48 int downgrade_test_init(void)
49 {
50 	/* Initialize the policydb_t structure */
51 	if (policydb_init(&policydb)) {
52 		fprintf(stderr, "%s:  Out of memory!\n", __FUNCTION__);
53 		return -1;
54 	}
55 
56 	return 0;
57 }
58 
59 /*
60  * Function Name:  downgrade_test_cleanup
61  *
62  * Input: None
63  *
64  * Output: None
65  *
66  * Description: Destroys policydb structure
67  */
downgrade_test_cleanup(void)68 int downgrade_test_cleanup(void)
69 {
70 	policydb_destroy(&policydb);
71 
72 	return 0;
73 }
74 
75 /*
76  * Function Name: downgrade_add_tests
77  *
78  * Input: CU_pSuite
79  *
80  * Output: Returns 0 upon success.  Returns a CUnit error value on failure.
81  *
82  * Description:  Add the given downgrade tests to the downgrade suite.
83  */
downgrade_add_tests(CU_pSuite suite)84 int downgrade_add_tests(CU_pSuite suite)
85 {
86 	if (CU_add_test(suite, "downgrade", test_downgrade) == NULL)
87 		return CU_get_error();
88 
89 	return 0;
90 }
91 
92 /*
93  * Function Name:  test_downgrade_possible
94  *
95  * Input: None
96  *
97  * Output: None
98  *
99  * Description:
100  * Tests the backward compatibility of MLS and Non-MLS binary policy versions.
101  */
test_downgrade(void)102 void test_downgrade(void)
103 {
104 	if (do_downgrade_test(0) < 0)
105 		fprintf(stderr,
106 		        "\nError during downgrade testing of Non-MLS policy\n");
107 
108 
109 	if (do_downgrade_test(1) < 0)
110 		fprintf(stderr,
111 			"\nError during downgrade testing of MLS policy\n");
112 }
113 
114 /*
115  * Function Name:  do_downgrade_test
116  *
117  * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing
118  *
119  * Output: 0 on success, negative number upon failure
120  *
121  * Description: This function handles the downgrade testing.
122  *              A binary policy is read into the policydb structure, the
123  *              policy version is decreased by a specific amount, written
124  *              back out and then read back in again.  The process is
125  *              repeated until the minimum policy version is reached.
126  */
do_downgrade_test(int mls)127 int do_downgrade_test(int mls)
128 {
129 	policydb_t policydb_tmp;
130 	int hi, lo, version;
131 
132 	/* Reset policydb for re-use */
133 	policydb_destroy(&policydb);
134 	downgrade_test_init();
135 
136 	/* Read in the hi policy from file */
137 	if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) {
138 		fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : "");
139 		CU_FAIL("Unable to read the binary policy");
140 		return -1;
141 	}
142 
143 	/* Change MLS value based on parameter */
144 	policydb.mls = mls ? 1 : 0;
145 
146 	for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) {
147 		/* Stash old version number */
148 		version = policydb.policyvers;
149 
150 		/* Try downgrading to each possible version. */
151 		for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) {
152 
153 			/* Reduce policy version */
154 			policydb.policyvers = lo;
155 
156 			/* Write out modified binary policy */
157 			if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) {
158 				/*
159 				 * Error from MLS to pre-MLS is expected due
160 				 * to MLS re-implementation in version 19.
161 				 */
162 				if (mls && lo < POLICYDB_VERSION_MLS)
163 					continue;
164 
165 				fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
166 				CU_FAIL("Failed to write downgraded binary policy");
167 					return -1;
168 			}
169 
170 			/* Make sure we can read back what we wrote. */
171 			if (policydb_init(&policydb_tmp)) {
172 				fprintf(stderr, "%s:  Out of memory!\n",
173 					__FUNCTION__);
174 				return -1;
175 			}
176 			if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) {
177 				fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi);
178 				CU_FAIL("Unable to read downgraded binary policy");
179 				return -1;
180 			}
181 			policydb_destroy(&policydb_tmp);
182 		}
183 		/* Restore version number */
184 		policydb.policyvers = version;
185     }
186 
187     return 0;
188 }
189 
190 /*
191  * Function Name: read_binary_policy
192  *
193  * Input: char * which is the path to the file containing the binary policy
194  *
195  * Output: Returns 0 upon success.  Upon failure, -1 is returned.
196  *	   Possible failures are, filename with given path does not exist,
197  *	   a failure to open the file, or a failure from prolicydb_read
198  *	   function call.
199  *
200  * Description:  Get a filename, open file and read binary policy into policydb
201  * 				 structure.
202  */
read_binary_policy(const char * path,policydb_t * p)203 int read_binary_policy(const char *path, policydb_t *p)
204 {
205 	FILE *in_fp = NULL;
206 	struct policy_file f;
207 	int rc;
208 
209 	/* Open the binary policy file */
210 	if ((in_fp = fopen(path, "rb")) == NULL) {
211 		fprintf(stderr, "Unable to open %s: %s\n", path,
212 			strerror(errno));
213 		return -1;
214 	}
215 
216 	/* Read in the binary policy.  */
217 	memset(&f, 0, sizeof(struct policy_file));
218 	f.type = PF_USE_STDIO;
219 	f.fp = in_fp;
220 	rc = policydb_read(p, &f, 0);
221 
222 	fclose(in_fp);
223 	return rc;
224 }
225 
226 /*
227  * Function Name: write_binary_policy
228  *
229  * Input: char * which is the path to the file containing the binary policy
230  *
231  * Output: Returns 0 upon success.  Upon failure, -1 is returned.
232  *	   Possible failures are, filename with given path does not exist,
233  *	   a failure to open the file, or a failure from prolicydb_read
234  *	   function call.
235  *
236  * Description:  open file and write the binary policy from policydb structure.
237  */
write_binary_policy(const char * path,policydb_t * p)238 int write_binary_policy(const char *path, policydb_t *p)
239 {
240 	FILE *out_fp = NULL;
241 	struct policy_file f;
242 	sepol_handle_t *handle;
243 	int rc;
244 
245 	/* We don't want libsepol to print warnings to stderr */
246 	handle = sepol_handle_create();
247 	if (handle == NULL) {
248 		fprintf(stderr, "Out of memory!\n");
249 		return -1;
250 	}
251 	sepol_msg_set_callback(handle, NULL, NULL);
252 
253 	/* Open the binary policy file for writing */
254 	if ((out_fp = fopen(path, "w" )) == NULL) {
255 		fprintf(stderr, "Unable to open %s: %s\n", path,
256 			strerror(errno));
257 		sepol_handle_destroy(handle);
258 		return -1;
259 	}
260 
261 	/* Write the binary policy */
262 	memset(&f, 0, sizeof(struct policy_file));
263 	f.type = PF_USE_STDIO;
264 	f.fp = out_fp;
265 	f.handle = handle;
266 	rc = policydb_write(p, &f);
267 
268 	sepol_handle_destroy(f.handle);
269 	fclose(out_fp);
270 	return rc;
271 }
272