| /* |
| * Author: Mary Garvin <[email protected]> |
| * |
| * Copyright (C) 2007-2008 Tresys Technology, LLC |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "test-downgrade.h" |
| #include "parse_util.h" |
| #include "helpers.h" |
| |
| #include <sepol/debug.h> |
| #include <sepol/handle.h> |
| #include <sepol/policydb/policydb.h> |
| #include <sepol/policydb/link.h> |
| #include <sepol/policydb/expand.h> |
| #include <sepol/policydb/conditional.h> |
| #include <limits.h> |
| #include <CUnit/Basic.h> |
| |
| #define POLICY_BIN_HI "policies/test-downgrade/policy.hi" |
| #define POLICY_BIN_LO "policies/test-downgrade/policy.lo" |
| |
| static policydb_t policydb; |
| |
| /* |
| * Function Name: downgrade_test_init |
| * |
| * Input: None |
| * |
| * Output: None |
| * |
| * Description: Initialize the policydb (policy data base structure) |
| */ |
| int downgrade_test_init(void) |
| { |
| /* Initialize the policydb_t structure */ |
| if (policydb_init(&policydb)) { |
| fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Function Name: downgrade_test_cleanup |
| * |
| * Input: None |
| * |
| * Output: None |
| * |
| * Description: Destroys policydb structure |
| */ |
| int downgrade_test_cleanup(void) |
| { |
| policydb_destroy(&policydb); |
| |
| return 0; |
| } |
| |
| /* |
| * Function Name: downgrade_add_tests |
| * |
| * Input: CU_pSuite |
| * |
| * Output: Returns 0 upon success. Returns a CUnit error value on failure. |
| * |
| * Description: Add the given downgrade tests to the downgrade suite. |
| */ |
| int downgrade_add_tests(CU_pSuite suite) |
| { |
| if (CU_add_test(suite, "downgrade", test_downgrade) == NULL) |
| return CU_get_error(); |
| |
| return 0; |
| } |
| |
| /* |
| * Function Name: test_downgrade_possible |
| * |
| * Input: None |
| * |
| * Output: None |
| * |
| * Description: |
| * Tests the backward compatibility of MLS and Non-MLS binary policy versions. |
| */ |
| void test_downgrade(void) |
| { |
| if (do_downgrade_test(0) < 0) |
| fprintf(stderr, |
| "\nError during downgrade testing of Non-MLS policy\n"); |
| |
| |
| if (do_downgrade_test(1) < 0) |
| fprintf(stderr, |
| "\nError during downgrade testing of MLS policy\n"); |
| } |
| |
| /* |
| * Function Name: do_downgrade_test |
| * |
| * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing |
| * |
| * Output: 0 on success, negative number upon failure |
| * |
| * Description: This function handles the downgrade testing. |
| * A binary policy is read into the policydb structure, the |
| * policy version is decreased by a specific amount, written |
| * back out and then read back in again. The process is |
| * repeated until the minimum policy version is reached. |
| */ |
| int do_downgrade_test(int mls) |
| { |
| policydb_t policydb_tmp; |
| int hi, lo, version; |
| |
| /* Reset policydb for re-use */ |
| policydb_destroy(&policydb); |
| downgrade_test_init(); |
| |
| /* Read in the hi policy from file */ |
| if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) { |
| fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : ""); |
| CU_FAIL("Unable to read the binary policy"); |
| return -1; |
| } |
| |
| /* Change MLS value based on parameter */ |
| policydb.mls = mls ? 1 : 0; |
| |
| for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) { |
| /* Stash old version number */ |
| version = policydb.policyvers; |
| |
| /* Try downgrading to each possible version. */ |
| for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) { |
| |
| /* Reduce policy version */ |
| policydb.policyvers = lo; |
| |
| /* Write out modified binary policy */ |
| if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) { |
| /* |
| * Error from MLS to pre-MLS is expected due |
| * to MLS re-implementation in version 19. |
| */ |
| if (mls && lo < POLICYDB_VERSION_MLS) |
| continue; |
| |
| fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); |
| CU_FAIL("Failed to write downgraded binary policy"); |
| return -1; |
| } |
| |
| /* Make sure we can read back what we wrote. */ |
| if (policydb_init(&policydb_tmp)) { |
| fprintf(stderr, "%s: Out of memory!\n", |
| __FUNCTION__); |
| return -1; |
| } |
| if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) { |
| fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); |
| CU_FAIL("Unable to read downgraded binary policy"); |
| return -1; |
| } |
| policydb_destroy(&policydb_tmp); |
| } |
| /* Restore version number */ |
| policydb.policyvers = version; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Function Name: read_binary_policy |
| * |
| * Input: char * which is the path to the file containing the binary policy |
| * |
| * Output: Returns 0 upon success. Upon failure, -1 is returned. |
| * Possible failures are, filename with given path does not exist, |
| * a failure to open the file, or a failure from prolicydb_read |
| * function call. |
| * |
| * Description: Get a filename, open file and read binary policy into policydb |
| * structure. |
| */ |
| int read_binary_policy(const char *path, policydb_t *p) |
| { |
| FILE *in_fp = NULL; |
| struct policy_file f; |
| int rc; |
| |
| /* Open the binary policy file */ |
| if ((in_fp = fopen(path, "rb")) == NULL) { |
| fprintf(stderr, "Unable to open %s: %s\n", path, |
| strerror(errno)); |
| return -1; |
| } |
| |
| /* Read in the binary policy. */ |
| memset(&f, 0, sizeof(struct policy_file)); |
| f.type = PF_USE_STDIO; |
| f.fp = in_fp; |
| rc = policydb_read(p, &f, 0); |
| |
| fclose(in_fp); |
| return rc; |
| } |
| |
| /* |
| * Function Name: write_binary_policy |
| * |
| * Input: char * which is the path to the file containing the binary policy |
| * |
| * Output: Returns 0 upon success. Upon failure, -1 is returned. |
| * Possible failures are, filename with given path does not exist, |
| * a failure to open the file, or a failure from prolicydb_read |
| * function call. |
| * |
| * Description: open file and write the binary policy from policydb structure. |
| */ |
| int write_binary_policy(const char *path, policydb_t *p) |
| { |
| FILE *out_fp = NULL; |
| struct policy_file f; |
| sepol_handle_t *handle; |
| int rc; |
| |
| /* We don't want libsepol to print warnings to stderr */ |
| handle = sepol_handle_create(); |
| if (handle == NULL) { |
| fprintf(stderr, "Out of memory!\n"); |
| return -1; |
| } |
| sepol_msg_set_callback(handle, NULL, NULL); |
| |
| /* Open the binary policy file for writing */ |
| if ((out_fp = fopen(path, "w" )) == NULL) { |
| fprintf(stderr, "Unable to open %s: %s\n", path, |
| strerror(errno)); |
| sepol_handle_destroy(handle); |
| return -1; |
| } |
| |
| /* Write the binary policy */ |
| memset(&f, 0, sizeof(struct policy_file)); |
| f.type = PF_USE_STDIO; |
| f.fp = out_fp; |
| f.handle = handle; |
| rc = policydb_write(p, &f); |
| |
| sepol_handle_destroy(f.handle); |
| fclose(out_fp); |
| return rc; |
| } |