Home | History | Annotate | Download | only in tests
      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