1 /* 2 * Author: Mary Garvin <mgarvin (at) 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 */ 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 */ 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 */ 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 compatability of MLS and Non-MLS binary policy versions. 101 */ 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 */ 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 */ 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 sepol_handle_destroy(f.handle); 214 return -1; 215 } 216 217 /* Read in the binary policy. */ 218 memset(&f, 0, sizeof(struct policy_file)); 219 f.type = PF_USE_STDIO; 220 f.fp = in_fp; 221 rc = policydb_read(p, &f, 0); 222 223 sepol_handle_destroy(f.handle); 224 fclose(in_fp); 225 return rc; 226 } 227 228 /* 229 * Function Name: write_binary_policy 230 * 231 * Input: char * which is the path to the file containing the binary policy 232 * 233 * Output: Returns 0 upon success. Upon failure, -1 is returned. 234 * Possible failures are, filename with given path does not exist, 235 * a failure to open the file, or a failure from prolicydb_read 236 * function call. 237 * 238 * Description: open file and write the binary policy from policydb structure. 239 */ 240 int write_binary_policy(const char *path, policydb_t *p) 241 { 242 FILE *out_fp = NULL; 243 struct policy_file f; 244 sepol_handle_t *handle; 245 int rc; 246 247 /* We don't want libsepol to print warnings to stderr */ 248 handle = sepol_handle_create(); 249 if (handle == NULL) { 250 fprintf(stderr, "Out of memory!\n"); 251 return -1; 252 } 253 sepol_msg_set_callback(handle, NULL, NULL); 254 255 /* Open the binary policy file for writing */ 256 if ((out_fp = fopen(path, "w" )) == NULL) { 257 fprintf(stderr, "Unable to open %s: %s\n", path, 258 strerror(errno)); 259 sepol_handle_destroy(f.handle); 260 return -1; 261 } 262 263 /* Write the binary policy */ 264 memset(&f, 0, sizeof(struct policy_file)); 265 f.type = PF_USE_STDIO; 266 f.fp = out_fp; 267 f.handle = handle; 268 rc = policydb_write(p, &f); 269 270 sepol_handle_destroy(f.handle); 271 fclose(out_fp); 272 return rc; 273 } 274