/* * Author: Mary Garvin <mgarvin@tresys.com> * * 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 compatability 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; }