summaryrefslogtreecommitdiff
path: root/tests/test-downgrade.c
blob: 1ee7ff4c7e7f3941ed67eca7e5868158dcd5e374 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/*
 * 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));
		sepol_handle_destroy(f.handle);
		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);

	sepol_handle_destroy(f.handle);
	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(f.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;
}