16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Author: Mary Garvin <mgarvin@tresys.com> 36cd6a6acSopenharmony_ci * 46cd6a6acSopenharmony_ci * Copyright (C) 2007-2008 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-downgrade.h" 226cd6a6acSopenharmony_ci#include "parse_util.h" 236cd6a6acSopenharmony_ci#include "helpers.h" 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci#include <sepol/debug.h> 266cd6a6acSopenharmony_ci#include <sepol/handle.h> 276cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h> 286cd6a6acSopenharmony_ci#include <sepol/policydb/link.h> 296cd6a6acSopenharmony_ci#include <sepol/policydb/expand.h> 306cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h> 316cd6a6acSopenharmony_ci#include <limits.h> 326cd6a6acSopenharmony_ci#include <CUnit/Basic.h> 336cd6a6acSopenharmony_ci 346cd6a6acSopenharmony_ci#define POLICY_BIN_HI "policies/test-downgrade/policy.hi" 356cd6a6acSopenharmony_ci#define POLICY_BIN_LO "policies/test-downgrade/policy.lo" 366cd6a6acSopenharmony_ci 376cd6a6acSopenharmony_cistatic policydb_t policydb; 386cd6a6acSopenharmony_ci 396cd6a6acSopenharmony_ci/* 406cd6a6acSopenharmony_ci * Function Name: downgrade_test_init 416cd6a6acSopenharmony_ci * 426cd6a6acSopenharmony_ci * Input: None 436cd6a6acSopenharmony_ci * 446cd6a6acSopenharmony_ci * Output: None 456cd6a6acSopenharmony_ci * 466cd6a6acSopenharmony_ci * Description: Initialize the policydb (policy data base structure) 476cd6a6acSopenharmony_ci */ 486cd6a6acSopenharmony_ciint downgrade_test_init(void) 496cd6a6acSopenharmony_ci{ 506cd6a6acSopenharmony_ci /* Initialize the policydb_t structure */ 516cd6a6acSopenharmony_ci if (policydb_init(&policydb)) { 526cd6a6acSopenharmony_ci fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); 536cd6a6acSopenharmony_ci return -1; 546cd6a6acSopenharmony_ci } 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci return 0; 576cd6a6acSopenharmony_ci} 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_ci/* 606cd6a6acSopenharmony_ci * Function Name: downgrade_test_cleanup 616cd6a6acSopenharmony_ci * 626cd6a6acSopenharmony_ci * Input: None 636cd6a6acSopenharmony_ci * 646cd6a6acSopenharmony_ci * Output: None 656cd6a6acSopenharmony_ci * 666cd6a6acSopenharmony_ci * Description: Destroys policydb structure 676cd6a6acSopenharmony_ci */ 686cd6a6acSopenharmony_ciint downgrade_test_cleanup(void) 696cd6a6acSopenharmony_ci{ 706cd6a6acSopenharmony_ci policydb_destroy(&policydb); 716cd6a6acSopenharmony_ci 726cd6a6acSopenharmony_ci return 0; 736cd6a6acSopenharmony_ci} 746cd6a6acSopenharmony_ci 756cd6a6acSopenharmony_ci/* 766cd6a6acSopenharmony_ci * Function Name: downgrade_add_tests 776cd6a6acSopenharmony_ci * 786cd6a6acSopenharmony_ci * Input: CU_pSuite 796cd6a6acSopenharmony_ci * 806cd6a6acSopenharmony_ci * Output: Returns 0 upon success. Returns a CUnit error value on failure. 816cd6a6acSopenharmony_ci * 826cd6a6acSopenharmony_ci * Description: Add the given downgrade tests to the downgrade suite. 836cd6a6acSopenharmony_ci */ 846cd6a6acSopenharmony_ciint downgrade_add_tests(CU_pSuite suite) 856cd6a6acSopenharmony_ci{ 866cd6a6acSopenharmony_ci if (CU_add_test(suite, "downgrade", test_downgrade) == NULL) 876cd6a6acSopenharmony_ci return CU_get_error(); 886cd6a6acSopenharmony_ci 896cd6a6acSopenharmony_ci return 0; 906cd6a6acSopenharmony_ci} 916cd6a6acSopenharmony_ci 926cd6a6acSopenharmony_ci/* 936cd6a6acSopenharmony_ci * Function Name: test_downgrade_possible 946cd6a6acSopenharmony_ci * 956cd6a6acSopenharmony_ci * Input: None 966cd6a6acSopenharmony_ci * 976cd6a6acSopenharmony_ci * Output: None 986cd6a6acSopenharmony_ci * 996cd6a6acSopenharmony_ci * Description: 1006cd6a6acSopenharmony_ci * Tests the backward compatibility of MLS and Non-MLS binary policy versions. 1016cd6a6acSopenharmony_ci */ 1026cd6a6acSopenharmony_civoid test_downgrade(void) 1036cd6a6acSopenharmony_ci{ 1046cd6a6acSopenharmony_ci if (do_downgrade_test(0) < 0) 1056cd6a6acSopenharmony_ci fprintf(stderr, 1066cd6a6acSopenharmony_ci "\nError during downgrade testing of Non-MLS policy\n"); 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci 1096cd6a6acSopenharmony_ci if (do_downgrade_test(1) < 0) 1106cd6a6acSopenharmony_ci fprintf(stderr, 1116cd6a6acSopenharmony_ci "\nError during downgrade testing of MLS policy\n"); 1126cd6a6acSopenharmony_ci} 1136cd6a6acSopenharmony_ci 1146cd6a6acSopenharmony_ci/* 1156cd6a6acSopenharmony_ci * Function Name: do_downgrade_test 1166cd6a6acSopenharmony_ci * 1176cd6a6acSopenharmony_ci * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing 1186cd6a6acSopenharmony_ci * 1196cd6a6acSopenharmony_ci * Output: 0 on success, negative number upon failure 1206cd6a6acSopenharmony_ci * 1216cd6a6acSopenharmony_ci * Description: This function handles the downgrade testing. 1226cd6a6acSopenharmony_ci * A binary policy is read into the policydb structure, the 1236cd6a6acSopenharmony_ci * policy version is decreased by a specific amount, written 1246cd6a6acSopenharmony_ci * back out and then read back in again. The process is 1256cd6a6acSopenharmony_ci * repeated until the minimum policy version is reached. 1266cd6a6acSopenharmony_ci */ 1276cd6a6acSopenharmony_ciint do_downgrade_test(int mls) 1286cd6a6acSopenharmony_ci{ 1296cd6a6acSopenharmony_ci policydb_t policydb_tmp; 1306cd6a6acSopenharmony_ci int hi, lo, version; 1316cd6a6acSopenharmony_ci 1326cd6a6acSopenharmony_ci /* Reset policydb for re-use */ 1336cd6a6acSopenharmony_ci policydb_destroy(&policydb); 1346cd6a6acSopenharmony_ci downgrade_test_init(); 1356cd6a6acSopenharmony_ci 1366cd6a6acSopenharmony_ci /* Read in the hi policy from file */ 1376cd6a6acSopenharmony_ci if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) { 1386cd6a6acSopenharmony_ci fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : ""); 1396cd6a6acSopenharmony_ci CU_FAIL("Unable to read the binary policy"); 1406cd6a6acSopenharmony_ci return -1; 1416cd6a6acSopenharmony_ci } 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ci /* Change MLS value based on parameter */ 1446cd6a6acSopenharmony_ci policydb.mls = mls ? 1 : 0; 1456cd6a6acSopenharmony_ci 1466cd6a6acSopenharmony_ci for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) { 1476cd6a6acSopenharmony_ci /* Stash old version number */ 1486cd6a6acSopenharmony_ci version = policydb.policyvers; 1496cd6a6acSopenharmony_ci 1506cd6a6acSopenharmony_ci /* Try downgrading to each possible version. */ 1516cd6a6acSopenharmony_ci for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) { 1526cd6a6acSopenharmony_ci 1536cd6a6acSopenharmony_ci /* Reduce policy version */ 1546cd6a6acSopenharmony_ci policydb.policyvers = lo; 1556cd6a6acSopenharmony_ci 1566cd6a6acSopenharmony_ci /* Write out modified binary policy */ 1576cd6a6acSopenharmony_ci if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) { 1586cd6a6acSopenharmony_ci /* 1596cd6a6acSopenharmony_ci * Error from MLS to pre-MLS is expected due 1606cd6a6acSopenharmony_ci * to MLS re-implementation in version 19. 1616cd6a6acSopenharmony_ci */ 1626cd6a6acSopenharmony_ci if (mls && lo < POLICYDB_VERSION_MLS) 1636cd6a6acSopenharmony_ci continue; 1646cd6a6acSopenharmony_ci 1656cd6a6acSopenharmony_ci fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); 1666cd6a6acSopenharmony_ci CU_FAIL("Failed to write downgraded binary policy"); 1676cd6a6acSopenharmony_ci return -1; 1686cd6a6acSopenharmony_ci } 1696cd6a6acSopenharmony_ci 1706cd6a6acSopenharmony_ci /* Make sure we can read back what we wrote. */ 1716cd6a6acSopenharmony_ci if (policydb_init(&policydb_tmp)) { 1726cd6a6acSopenharmony_ci fprintf(stderr, "%s: Out of memory!\n", 1736cd6a6acSopenharmony_ci __FUNCTION__); 1746cd6a6acSopenharmony_ci return -1; 1756cd6a6acSopenharmony_ci } 1766cd6a6acSopenharmony_ci if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) { 1776cd6a6acSopenharmony_ci fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); 1786cd6a6acSopenharmony_ci CU_FAIL("Unable to read downgraded binary policy"); 1796cd6a6acSopenharmony_ci return -1; 1806cd6a6acSopenharmony_ci } 1816cd6a6acSopenharmony_ci policydb_destroy(&policydb_tmp); 1826cd6a6acSopenharmony_ci } 1836cd6a6acSopenharmony_ci /* Restore version number */ 1846cd6a6acSopenharmony_ci policydb.policyvers = version; 1856cd6a6acSopenharmony_ci } 1866cd6a6acSopenharmony_ci 1876cd6a6acSopenharmony_ci return 0; 1886cd6a6acSopenharmony_ci} 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ci/* 1916cd6a6acSopenharmony_ci * Function Name: read_binary_policy 1926cd6a6acSopenharmony_ci * 1936cd6a6acSopenharmony_ci * Input: char * which is the path to the file containing the binary policy 1946cd6a6acSopenharmony_ci * 1956cd6a6acSopenharmony_ci * Output: Returns 0 upon success. Upon failure, -1 is returned. 1966cd6a6acSopenharmony_ci * Possible failures are, filename with given path does not exist, 1976cd6a6acSopenharmony_ci * a failure to open the file, or a failure from prolicydb_read 1986cd6a6acSopenharmony_ci * function call. 1996cd6a6acSopenharmony_ci * 2006cd6a6acSopenharmony_ci * Description: Get a filename, open file and read binary policy into policydb 2016cd6a6acSopenharmony_ci * structure. 2026cd6a6acSopenharmony_ci */ 2036cd6a6acSopenharmony_ciint read_binary_policy(const char *path, policydb_t *p) 2046cd6a6acSopenharmony_ci{ 2056cd6a6acSopenharmony_ci FILE *in_fp = NULL; 2066cd6a6acSopenharmony_ci struct policy_file f; 2076cd6a6acSopenharmony_ci int rc; 2086cd6a6acSopenharmony_ci 2096cd6a6acSopenharmony_ci /* Open the binary policy file */ 2106cd6a6acSopenharmony_ci if ((in_fp = fopen(path, "rb")) == NULL) { 2116cd6a6acSopenharmony_ci fprintf(stderr, "Unable to open %s: %s\n", path, 2126cd6a6acSopenharmony_ci strerror(errno)); 2136cd6a6acSopenharmony_ci return -1; 2146cd6a6acSopenharmony_ci } 2156cd6a6acSopenharmony_ci 2166cd6a6acSopenharmony_ci /* Read in the binary policy. */ 2176cd6a6acSopenharmony_ci memset(&f, 0, sizeof(struct policy_file)); 2186cd6a6acSopenharmony_ci f.type = PF_USE_STDIO; 2196cd6a6acSopenharmony_ci f.fp = in_fp; 2206cd6a6acSopenharmony_ci rc = policydb_read(p, &f, 0); 2216cd6a6acSopenharmony_ci 2226cd6a6acSopenharmony_ci fclose(in_fp); 2236cd6a6acSopenharmony_ci return rc; 2246cd6a6acSopenharmony_ci} 2256cd6a6acSopenharmony_ci 2266cd6a6acSopenharmony_ci/* 2276cd6a6acSopenharmony_ci * Function Name: write_binary_policy 2286cd6a6acSopenharmony_ci * 2296cd6a6acSopenharmony_ci * Input: char * which is the path to the file containing the binary policy 2306cd6a6acSopenharmony_ci * 2316cd6a6acSopenharmony_ci * Output: Returns 0 upon success. Upon failure, -1 is returned. 2326cd6a6acSopenharmony_ci * Possible failures are, filename with given path does not exist, 2336cd6a6acSopenharmony_ci * a failure to open the file, or a failure from prolicydb_read 2346cd6a6acSopenharmony_ci * function call. 2356cd6a6acSopenharmony_ci * 2366cd6a6acSopenharmony_ci * Description: open file and write the binary policy from policydb structure. 2376cd6a6acSopenharmony_ci */ 2386cd6a6acSopenharmony_ciint write_binary_policy(const char *path, policydb_t *p) 2396cd6a6acSopenharmony_ci{ 2406cd6a6acSopenharmony_ci FILE *out_fp = NULL; 2416cd6a6acSopenharmony_ci struct policy_file f; 2426cd6a6acSopenharmony_ci sepol_handle_t *handle; 2436cd6a6acSopenharmony_ci int rc; 2446cd6a6acSopenharmony_ci 2456cd6a6acSopenharmony_ci /* We don't want libsepol to print warnings to stderr */ 2466cd6a6acSopenharmony_ci handle = sepol_handle_create(); 2476cd6a6acSopenharmony_ci if (handle == NULL) { 2486cd6a6acSopenharmony_ci fprintf(stderr, "Out of memory!\n"); 2496cd6a6acSopenharmony_ci return -1; 2506cd6a6acSopenharmony_ci } 2516cd6a6acSopenharmony_ci sepol_msg_set_callback(handle, NULL, NULL); 2526cd6a6acSopenharmony_ci 2536cd6a6acSopenharmony_ci /* Open the binary policy file for writing */ 2546cd6a6acSopenharmony_ci if ((out_fp = fopen(path, "w" )) == NULL) { 2556cd6a6acSopenharmony_ci fprintf(stderr, "Unable to open %s: %s\n", path, 2566cd6a6acSopenharmony_ci strerror(errno)); 2576cd6a6acSopenharmony_ci sepol_handle_destroy(handle); 2586cd6a6acSopenharmony_ci return -1; 2596cd6a6acSopenharmony_ci } 2606cd6a6acSopenharmony_ci 2616cd6a6acSopenharmony_ci /* Write the binary policy */ 2626cd6a6acSopenharmony_ci memset(&f, 0, sizeof(struct policy_file)); 2636cd6a6acSopenharmony_ci f.type = PF_USE_STDIO; 2646cd6a6acSopenharmony_ci f.fp = out_fp; 2656cd6a6acSopenharmony_ci f.handle = handle; 2666cd6a6acSopenharmony_ci rc = policydb_write(p, &f); 2676cd6a6acSopenharmony_ci 2686cd6a6acSopenharmony_ci sepol_handle_destroy(f.handle); 2696cd6a6acSopenharmony_ci fclose(out_fp); 2706cd6a6acSopenharmony_ci return rc; 2716cd6a6acSopenharmony_ci} 272