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