xref: /third_party/selinux/libsepol/src/write.c (revision 6cd6a6ac)
1
2/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
3
4/*
5 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
6 *
7 *	Support for enhanced MLS infrastructure.
8 *
9 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
10 *
11 * 	Added conditional policy language extensions
12 *
13 * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org>
14 *
15 *	Module writing support
16 *
17 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
18 * Copyright (C) 2003-2005 Tresys Technology, LLC
19 * Copyright (C) 2017 Mellanox Technologies Inc.
20 *
21 *  This library is free software; you can redistribute it and/or
22 *  modify it under the terms of the GNU Lesser General Public
23 *  License as published by the Free Software Foundation; either
24 *  version 2.1 of the License, or (at your option) any later version.
25 *
26 *  This library is distributed in the hope that it will be useful,
27 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29 *  Lesser General Public License for more details.
30 *
31 *  You should have received a copy of the GNU Lesser General Public
32 *  License along with this library; if not, write to the Free Software
33 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
34 */
35#include <assert.h>
36#include <stdlib.h>
37
38#include <sepol/policydb/ebitmap.h>
39#include <sepol/policydb/avtab.h>
40#include <sepol/policydb/policydb.h>
41#include <sepol/policydb/conditional.h>
42#include <sepol/policydb/expand.h>
43
44#include "debug.h"
45#include "private.h"
46#include "mls.h"
47
48#define glblub_version ((p->policy_type == POLICY_KERN && \
49		     p->policyvers >= POLICYDB_VERSION_GLBLUB) || \
50		    (p->policy_type == POLICY_BASE && \
51		     p->policyvers >= MOD_POLICYDB_VERSION_GLBLUB))
52
53struct policy_data {
54	struct policy_file *fp;
55	struct policydb *p;
56};
57
58static int avrule_write_list(policydb_t *p,
59			     avrule_t * avrules, struct policy_file *fp);
60
61static int ebitmap_write(ebitmap_t * e, struct policy_file *fp)
62{
63	ebitmap_node_t *n;
64	uint32_t buf[32], bit, count;
65	uint64_t map;
66	size_t items;
67
68	buf[0] = cpu_to_le32(MAPSIZE);
69	buf[1] = cpu_to_le32(e->highbit);
70
71	count = 0;
72	for (n = e->node; n; n = n->next)
73		count++;
74	buf[2] = cpu_to_le32(count);
75
76	items = put_entry(buf, sizeof(uint32_t), 3, fp);
77	if (items != 3)
78		return POLICYDB_ERROR;
79
80	for (n = e->node; n; n = n->next) {
81		bit = cpu_to_le32(n->startbit);
82		items = put_entry(&bit, sizeof(uint32_t), 1, fp);
83		if (items != 1)
84			return POLICYDB_ERROR;
85		map = cpu_to_le64(n->map);
86		items = put_entry(&map, sizeof(uint64_t), 1, fp);
87		if (items != 1)
88			return POLICYDB_ERROR;
89
90	}
91
92	return POLICYDB_SUCCESS;
93}
94
95/* Ordering of datums in the original avtab format in the policy file. */
96static uint16_t spec_order[] = {
97	AVTAB_ALLOWED,
98	AVTAB_AUDITDENY,
99	AVTAB_AUDITALLOW,
100	AVTAB_TRANSITION,
101	AVTAB_CHANGE,
102	AVTAB_MEMBER
103};
104
105static int avtab_write_item(policydb_t * p,
106			    avtab_ptr_t cur, struct policy_file *fp,
107			    unsigned merge, unsigned commit, uint32_t * nel)
108{
109	avtab_ptr_t node;
110	uint8_t buf8;
111	uint16_t buf16[4];
112	uint32_t buf32[10], lookup, val;
113	size_t items, items2;
114	unsigned set;
115	unsigned int oldvers = (p->policy_type == POLICY_KERN
116				&& p->policyvers < POLICYDB_VERSION_AVTAB);
117	unsigned int i;
118
119	if (oldvers) {
120		/* Generate the old avtab format.
121		   Requires merging similar entries if uncond avtab. */
122		if (merge) {
123			if (cur->merged)
124				return POLICYDB_SUCCESS;	/* already merged by prior merge */
125		}
126
127		items = 1;	/* item 0 is used for the item count */
128		val = cur->key.source_type;
129		buf32[items++] = cpu_to_le32(val);
130		val = cur->key.target_type;
131		buf32[items++] = cpu_to_le32(val);
132		val = cur->key.target_class;
133		buf32[items++] = cpu_to_le32(val);
134
135		val = cur->key.specified & ~AVTAB_ENABLED;
136		if (cur->key.specified & AVTAB_ENABLED)
137			val |= AVTAB_ENABLED_OLD;
138		set = 1;
139
140		if (merge) {
141			/* Merge specifier values for all similar (av or type)
142			   entries that have the same key. */
143			if (val & AVTAB_AV)
144				lookup = AVTAB_AV;
145			else if (val & AVTAB_TYPE)
146				lookup = AVTAB_TYPE;
147			else
148				return POLICYDB_ERROR;
149			for (node = avtab_search_node_next(cur, lookup);
150			     node;
151			     node = avtab_search_node_next(node, lookup)) {
152				val |= (node->key.specified & ~AVTAB_ENABLED);
153				set++;
154				if (node->key.specified & AVTAB_ENABLED)
155					val |= AVTAB_ENABLED_OLD;
156			}
157		}
158
159		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
160			ERR(fp->handle, "null entry");
161			return POLICYDB_ERROR;
162		}
163		if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
164			ERR(fp->handle, "entry has both access "
165			    "vectors and types");
166			return POLICYDB_ERROR;
167		}
168
169		buf32[items++] = cpu_to_le32(val);
170
171		if (merge) {
172			/* Include datums for all similar (av or type)
173			   entries that have the same key. */
174			for (i = 0;
175			     i < (sizeof(spec_order) / sizeof(spec_order[0]));
176			     i++) {
177				if (val & spec_order[i]) {
178					if (cur->key.specified & spec_order[i])
179						node = cur;
180					else {
181						node =
182						    avtab_search_node_next(cur,
183									   spec_order
184									   [i]);
185						if (nel)
186							(*nel)--;	/* one less node */
187					}
188
189					if (!node) {
190						ERR(fp->handle, "missing node");
191						return POLICYDB_ERROR;
192					}
193					buf32[items++] =
194					    cpu_to_le32(node->datum.data);
195					set--;
196					node->merged = 1;
197				}
198			}
199		} else {
200			buf32[items++] = cpu_to_le32(cur->datum.data);
201			cur->merged = 1;
202			set--;
203		}
204
205		if (set) {
206			ERR(fp->handle, "data count wrong");
207			return POLICYDB_ERROR;
208		}
209
210		buf32[0] = cpu_to_le32(items - 1);
211
212		if (commit) {
213			/* Commit this item to the policy file. */
214			items2 = put_entry(buf32, sizeof(uint32_t), items, fp);
215			if (items != items2)
216				return POLICYDB_ERROR;
217		}
218
219		return POLICYDB_SUCCESS;
220	}
221
222	/* Generate the new avtab format. */
223	buf16[0] = cpu_to_le16(cur->key.source_type);
224	buf16[1] = cpu_to_le16(cur->key.target_type);
225	buf16[2] = cpu_to_le16(cur->key.target_class);
226	buf16[3] = cpu_to_le16(cur->key.specified);
227	items = put_entry(buf16, sizeof(uint16_t), 4, fp);
228	if (items != 4)
229		return POLICYDB_ERROR;
230	if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
231			(cur->key.specified & AVTAB_XPERMS)) {
232		ERR(fp->handle, "policy version %u does not support ioctl extended"
233				"permissions rules and one was specified", p->policyvers);
234		return POLICYDB_ERROR;
235	}
236
237	if (p->target_platform != SEPOL_TARGET_SELINUX &&
238			(cur->key.specified & AVTAB_XPERMS)) {
239		ERR(fp->handle, "Target platform %s does not support ioctl "
240				"extended permissions rules and one was specified",
241				policydb_target_strings[p->target_platform]);
242		return POLICYDB_ERROR;
243	}
244
245	if (cur->key.specified & AVTAB_XPERMS) {
246		buf8 = cur->datum.xperms->specified;
247		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
248		if (items != 1)
249			return POLICYDB_ERROR;
250		buf8 = cur->datum.xperms->driver;
251		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
252		if (items != 1)
253			return POLICYDB_ERROR;
254		for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
255			buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
256		items = put_entry(buf32, sizeof(uint32_t),8,fp);
257		if (items != 8)
258			return POLICYDB_ERROR;
259	} else {
260		buf32[0] = cpu_to_le32(cur->datum.data);
261		items = put_entry(buf32, sizeof(uint32_t), 1, fp);
262		if (items != 1)
263			return POLICYDB_ERROR;
264	}
265
266	return POLICYDB_SUCCESS;
267}
268
269static inline void avtab_reset_merged(avtab_t * a)
270{
271	unsigned int i;
272	avtab_ptr_t cur;
273	for (i = 0; i < a->nslot; i++) {
274		for (cur = a->htable[i]; cur; cur = cur->next)
275			cur->merged = 0;
276	}
277}
278
279static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
280{
281	unsigned int i;
282	int rc;
283	avtab_t expa;
284	avtab_ptr_t cur;
285	uint32_t nel;
286	size_t items;
287	unsigned int oldvers = (p->policy_type == POLICY_KERN
288				&& p->policyvers < POLICYDB_VERSION_AVTAB);
289
290	if (oldvers) {
291		/* Old avtab format.
292		   First, we need to expand attributes.  Then, we need to
293		   merge similar entries, so we need to track merged nodes
294		   and compute the final nel. */
295		if (avtab_init(&expa))
296			return POLICYDB_ERROR;
297		if (expand_avtab(p, a, &expa)) {
298			rc = -1;
299			goto out;
300		}
301		a = &expa;
302		avtab_reset_merged(a);
303		nel = a->nel;
304	} else {
305		/* New avtab format.  nel is good to go. */
306		nel = cpu_to_le32(a->nel);
307		items = put_entry(&nel, sizeof(uint32_t), 1, fp);
308		if (items != 1)
309			return POLICYDB_ERROR;
310	}
311
312	for (i = 0; i < a->nslot; i++) {
313		for (cur = a->htable[i]; cur; cur = cur->next) {
314			/* If old format, compute final nel.
315			   If new format, write out the items. */
316			if (avtab_write_item(p, cur, fp, 1, !oldvers, &nel)) {
317				rc = -1;
318				goto out;
319			}
320		}
321	}
322
323	if (oldvers) {
324		/* Old avtab format.
325		   Write the computed nel value, then write the items. */
326		nel = cpu_to_le32(nel);
327		items = put_entry(&nel, sizeof(uint32_t), 1, fp);
328		if (items != 1) {
329			rc = -1;
330			goto out;
331		}
332		avtab_reset_merged(a);
333		for (i = 0; i < a->nslot; i++) {
334			for (cur = a->htable[i]; cur; cur = cur->next) {
335				if (avtab_write_item(p, cur, fp, 1, 1, NULL)) {
336					rc = -1;
337					goto out;
338				}
339			}
340		}
341	}
342
343	rc = 0;
344      out:
345	if (oldvers)
346		avtab_destroy(&expa);
347	return rc;
348}
349
350/*
351 * Write a semantic MLS level structure to a policydb binary
352 * representation file.
353 */
354static int mls_write_semantic_level_helper(mls_semantic_level_t * l,
355					   struct policy_file *fp)
356{
357	uint32_t buf[2], ncat = 0;
358	size_t items;
359	mls_semantic_cat_t *cat;
360
361	for (cat = l->cat; cat; cat = cat->next)
362		ncat++;
363
364	buf[0] = cpu_to_le32(l->sens);
365	buf[1] = cpu_to_le32(ncat);
366	items = put_entry(buf, sizeof(uint32_t), 2, fp);
367	if (items != 2)
368		return POLICYDB_ERROR;
369
370	for (cat = l->cat; cat; cat = cat->next) {
371		buf[0] = cpu_to_le32(cat->low);
372		buf[1] = cpu_to_le32(cat->high);
373		items = put_entry(buf, sizeof(uint32_t), 2, fp);
374		if (items != 2)
375			return POLICYDB_ERROR;
376	}
377
378	return POLICYDB_SUCCESS;
379}
380
381/*
382 * Read a semantic MLS range structure to a policydb binary
383 * representation file.
384 */
385static int mls_write_semantic_range_helper(mls_semantic_range_t * r,
386					   struct policy_file *fp)
387{
388	int rc;
389
390	rc = mls_write_semantic_level_helper(&r->level[0], fp);
391	if (rc)
392		return rc;
393
394	rc = mls_write_semantic_level_helper(&r->level[1], fp);
395
396	return rc;
397}
398
399/*
400 * Write a MLS level structure to a policydb binary
401 * representation file.
402 */
403static int mls_write_level(mls_level_t * l, struct policy_file *fp)
404{
405	uint32_t sens;
406	size_t items;
407
408	sens = cpu_to_le32(l->sens);
409	items = put_entry(&sens, sizeof(uint32_t), 1, fp);
410	if (items != 1)
411		return POLICYDB_ERROR;
412
413	if (ebitmap_write(&l->cat, fp))
414		return POLICYDB_ERROR;
415
416	return POLICYDB_SUCCESS;
417}
418
419/*
420 * Write a MLS range structure to a policydb binary
421 * representation file.
422 */
423static int mls_write_range_helper(mls_range_t * r, struct policy_file *fp)
424{
425	uint32_t buf[3];
426	size_t items, items2;
427	int eq;
428
429	eq = mls_level_eq(&r->level[1], &r->level[0]);
430
431	items = 1;		/* item 0 is used for the item count */
432	buf[items++] = cpu_to_le32(r->level[0].sens);
433	if (!eq)
434		buf[items++] = cpu_to_le32(r->level[1].sens);
435	buf[0] = cpu_to_le32(items - 1);
436
437	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
438	if (items2 != items)
439		return POLICYDB_ERROR;
440
441	if (ebitmap_write(&r->level[0].cat, fp))
442		return POLICYDB_ERROR;
443	if (!eq)
444		if (ebitmap_write(&r->level[1].cat, fp))
445			return POLICYDB_ERROR;
446
447	return POLICYDB_SUCCESS;
448}
449
450static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
451{
452	level_datum_t *levdatum;
453	uint32_t buf[32];
454	size_t items, items2, len;
455	struct policy_data *pd = ptr;
456	struct policy_file *fp = pd->fp;
457
458	levdatum = (level_datum_t *) datum;
459
460	len = strlen(key);
461	items = 0;
462	buf[items++] = cpu_to_le32(len);
463	buf[items++] = cpu_to_le32(levdatum->isalias);
464	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
465	if (items != items2)
466		return POLICYDB_ERROR;
467
468	items = put_entry(key, 1, len, fp);
469	if (items != len)
470		return POLICYDB_ERROR;
471
472	if (mls_write_level(levdatum->level, fp))
473		return POLICYDB_ERROR;
474
475	return POLICYDB_SUCCESS;
476}
477
478static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
479{
480	cat_datum_t *catdatum;
481	uint32_t buf[32];
482	size_t items, items2, len;
483	struct policy_data *pd = ptr;
484	struct policy_file *fp = pd->fp;
485
486	catdatum = (cat_datum_t *) datum;
487
488	len = strlen(key);
489	items = 0;
490	buf[items++] = cpu_to_le32(len);
491	buf[items++] = cpu_to_le32(catdatum->s.value);
492	buf[items++] = cpu_to_le32(catdatum->isalias);
493	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
494	if (items != items2)
495		return POLICYDB_ERROR;
496
497	items = put_entry(key, 1, len, fp);
498	if (items != len)
499		return POLICYDB_ERROR;
500
501	return POLICYDB_SUCCESS;
502}
503
504static int role_trans_write(policydb_t *p, struct policy_file *fp)
505{
506	role_trans_t *r = p->role_tr;
507	role_trans_t *tr;
508	uint32_t buf[3];
509	size_t nel, items;
510	int new_roletr = (p->policy_type == POLICY_KERN &&
511			  p->policyvers >= POLICYDB_VERSION_ROLETRANS);
512	int warning_issued = 0;
513
514	nel = 0;
515	for (tr = r; tr; tr = tr->next)
516		if(new_roletr || tr->tclass == p->process_class)
517			nel++;
518
519	buf[0] = cpu_to_le32(nel);
520	items = put_entry(buf, sizeof(uint32_t), 1, fp);
521	if (items != 1)
522		return POLICYDB_ERROR;
523	for (tr = r; tr; tr = tr->next) {
524		if (!new_roletr && tr->tclass != p->process_class) {
525			if (!warning_issued)
526				WARN(fp->handle, "Discarding role_transition "
527				     "rules for security classes other than "
528				     "\"process\"");
529			warning_issued = 1;
530			continue;
531		}
532		buf[0] = cpu_to_le32(tr->role);
533		buf[1] = cpu_to_le32(tr->type);
534		buf[2] = cpu_to_le32(tr->new_role);
535		items = put_entry(buf, sizeof(uint32_t), 3, fp);
536		if (items != 3)
537			return POLICYDB_ERROR;
538		if (new_roletr) {
539			buf[0] = cpu_to_le32(tr->tclass);
540			items = put_entry(buf, sizeof(uint32_t), 1, fp);
541			if (items != 1)
542				return POLICYDB_ERROR;
543		}
544	}
545
546	return POLICYDB_SUCCESS;
547}
548
549static int role_allow_write(role_allow_t * r, struct policy_file *fp)
550{
551	role_allow_t *ra;
552	uint32_t buf[2];
553	size_t nel, items;
554
555	nel = 0;
556	for (ra = r; ra; ra = ra->next)
557		nel++;
558	buf[0] = cpu_to_le32(nel);
559	items = put_entry(buf, sizeof(uint32_t), 1, fp);
560	if (items != 1)
561		return POLICYDB_ERROR;
562	for (ra = r; ra; ra = ra->next) {
563		buf[0] = cpu_to_le32(ra->role);
564		buf[1] = cpu_to_le32(ra->new_role);
565		items = put_entry(buf, sizeof(uint32_t), 2, fp);
566		if (items != 2)
567			return POLICYDB_ERROR;
568	}
569	return POLICYDB_SUCCESS;
570}
571
572static int filename_write_one_compat(hashtab_key_t key, void *data, void *ptr)
573{
574	uint32_t bit, buf[4];
575	size_t items, len;
576	filename_trans_key_t *ft = (filename_trans_key_t *)key;
577	filename_trans_datum_t *datum = data;
578	ebitmap_node_t *node;
579	void *fp = ptr;
580
581	len = strlen(ft->name);
582	do {
583		ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
584			buf[0] = cpu_to_le32(len);
585			items = put_entry(buf, sizeof(uint32_t), 1, fp);
586			if (items != 1)
587				return POLICYDB_ERROR;
588
589			items = put_entry(ft->name, sizeof(char), len, fp);
590			if (items != len)
591				return POLICYDB_ERROR;
592
593			buf[0] = cpu_to_le32(bit + 1);
594			buf[1] = cpu_to_le32(ft->ttype);
595			buf[2] = cpu_to_le32(ft->tclass);
596			buf[3] = cpu_to_le32(datum->otype);
597			items = put_entry(buf, sizeof(uint32_t), 4, fp);
598			if (items != 4)
599				return POLICYDB_ERROR;
600		}
601
602		datum = datum->next;
603	} while (datum);
604
605	return 0;
606}
607
608static int filename_write_one(hashtab_key_t key, void *data, void *ptr)
609{
610	uint32_t buf[3];
611	size_t items, len, ndatum;
612	filename_trans_key_t *ft = (filename_trans_key_t *)key;
613	filename_trans_datum_t *datum;
614	void *fp = ptr;
615
616	len = strlen(ft->name);
617	buf[0] = cpu_to_le32(len);
618	items = put_entry(buf, sizeof(uint32_t), 1, fp);
619	if (items != 1)
620		return POLICYDB_ERROR;
621
622	items = put_entry(ft->name, sizeof(char), len, fp);
623	if (items != len)
624		return POLICYDB_ERROR;
625
626	ndatum = 0;
627	datum = data;
628	do {
629		ndatum++;
630		datum = datum->next;
631	} while (datum);
632
633	buf[0] = cpu_to_le32(ft->ttype);
634	buf[1] = cpu_to_le32(ft->tclass);
635	buf[2] = cpu_to_le32(ndatum);
636	items = put_entry(buf, sizeof(uint32_t), 3, fp);
637	if (items != 3)
638		return POLICYDB_ERROR;
639
640	datum = data;
641	do {
642		if (ebitmap_write(&datum->stypes, fp))
643			return POLICYDB_ERROR;
644
645		buf[0] = cpu_to_le32(datum->otype);
646		items = put_entry(buf, sizeof(uint32_t), 1, fp);
647		if (items != 1)
648			return POLICYDB_ERROR;
649
650		datum = datum->next;
651	} while (datum);
652
653	return 0;
654}
655
656static int filename_trans_write(struct policydb *p, void *fp)
657{
658	size_t items;
659	uint32_t buf[1];
660	int rc;
661
662	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
663		return 0;
664
665	if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
666		buf[0] = cpu_to_le32(p->filename_trans_count);
667		items = put_entry(buf, sizeof(uint32_t), 1, fp);
668		if (items != 1)
669			return POLICYDB_ERROR;
670
671		rc = hashtab_map(p->filename_trans, filename_write_one_compat,
672				 fp);
673	} else {
674		buf[0] = cpu_to_le32(p->filename_trans->nel);
675		items = put_entry(buf, sizeof(uint32_t), 1, fp);
676		if (items != 1)
677			return POLICYDB_ERROR;
678
679		rc = hashtab_map(p->filename_trans, filename_write_one, fp);
680	}
681	return rc;
682}
683
684static int role_set_write(role_set_t * x, struct policy_file *fp)
685{
686	size_t items;
687	uint32_t buf[1];
688
689	if (ebitmap_write(&x->roles, fp))
690		return POLICYDB_ERROR;
691
692	buf[0] = cpu_to_le32(x->flags);
693	items = put_entry(buf, sizeof(uint32_t), 1, fp);
694	if (items != 1)
695		return POLICYDB_ERROR;
696
697	return POLICYDB_SUCCESS;
698}
699
700static int type_set_write(type_set_t * x, struct policy_file *fp)
701{
702	size_t items;
703	uint32_t buf[1];
704
705	if (ebitmap_write(&x->types, fp))
706		return POLICYDB_ERROR;
707	if (ebitmap_write(&x->negset, fp))
708		return POLICYDB_ERROR;
709
710	buf[0] = cpu_to_le32(x->flags);
711	items = put_entry(buf, sizeof(uint32_t), 1, fp);
712	if (items != 1)
713		return POLICYDB_ERROR;
714
715	return POLICYDB_SUCCESS;
716}
717
718static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
719{
720	cond_bool_datum_t *booldatum;
721	uint32_t buf[3], len;
722	unsigned int items, items2;
723	struct policy_data *pd = ptr;
724	struct policy_file *fp = pd->fp;
725	struct policydb *p = pd->p;
726
727	booldatum = (cond_bool_datum_t *) datum;
728
729	len = strlen(key);
730	items = 0;
731	buf[items++] = cpu_to_le32(booldatum->s.value);
732	buf[items++] = cpu_to_le32(booldatum->state);
733	buf[items++] = cpu_to_le32(len);
734	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
735	if (items != items2)
736		return POLICYDB_ERROR;
737	items = put_entry(key, 1, len, fp);
738	if (items != len)
739		return POLICYDB_ERROR;
740
741	if (p->policy_type != POLICY_KERN &&
742	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
743		buf[0] = cpu_to_le32(booldatum->flags);
744		items = put_entry(buf, sizeof(uint32_t), 1, fp);
745		if (items != 1)
746			return POLICYDB_ERROR;
747	}
748
749	return POLICYDB_SUCCESS;
750}
751
752/*
753 * cond_write_cond_av_list doesn't write out the av_list nodes.
754 * Instead it writes out the key/value pairs from the avtab. This
755 * is necessary because there is no way to uniquely identifying rules
756 * in the avtab so it is not possible to associate individual rules
757 * in the avtab with a conditional without saving them as part of
758 * the conditional. This means that the avtab with the conditional
759 * rules will not be saved but will be rebuilt on policy load.
760 */
761static int cond_write_av_list(policydb_t * p,
762			      cond_av_list_t * list, struct policy_file *fp)
763{
764	uint32_t buf[4];
765	cond_av_list_t *cur_list, *new_list = NULL;
766	avtab_t expa;
767	uint32_t len, items;
768	unsigned int oldvers = (p->policy_type == POLICY_KERN
769				&& p->policyvers < POLICYDB_VERSION_AVTAB);
770	int rc = -1;
771
772	if (oldvers) {
773		if (avtab_init(&expa))
774			return POLICYDB_ERROR;
775		if (expand_cond_av_list(p, list, &new_list, &expa))
776			goto out;
777		list = new_list;
778	}
779
780	len = 0;
781	for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
782		if (cur_list->node->parse_context)
783			len++;
784	}
785
786	buf[0] = cpu_to_le32(len);
787	items = put_entry(buf, sizeof(uint32_t), 1, fp);
788	if (items != 1)
789		goto out;
790
791	if (len == 0) {
792		rc = 0;
793		goto out;
794	}
795
796	for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
797		if (cur_list->node->parse_context)
798			if (avtab_write_item(p, cur_list->node, fp, 0, 1, NULL))
799				goto out;
800	}
801
802	rc = 0;
803      out:
804	if (oldvers) {
805		cond_av_list_destroy(new_list);
806		avtab_destroy(&expa);
807	}
808
809	return rc;
810}
811
812static int cond_write_node(policydb_t * p,
813			   cond_node_t * node, struct policy_file *fp)
814{
815	cond_expr_t *cur_expr;
816	uint32_t buf[2];
817	uint32_t items, items2, len;
818
819	buf[0] = cpu_to_le32(node->cur_state);
820	items = put_entry(buf, sizeof(uint32_t), 1, fp);
821	if (items != 1)
822		return POLICYDB_ERROR;
823
824	/* expr */
825	len = 0;
826	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
827		len++;
828
829	buf[0] = cpu_to_le32(len);
830	items = put_entry(buf, sizeof(uint32_t), 1, fp);
831	if (items != 1)
832		return POLICYDB_ERROR;
833
834	for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
835		items = 0;
836		buf[items++] = cpu_to_le32(cur_expr->expr_type);
837		buf[items++] = cpu_to_le32(cur_expr->bool);
838		items2 = put_entry(buf, sizeof(uint32_t), items, fp);
839		if (items2 != items)
840			return POLICYDB_ERROR;
841	}
842
843	if (p->policy_type == POLICY_KERN) {
844		if (cond_write_av_list(p, node->true_list, fp) != 0)
845			return POLICYDB_ERROR;
846		if (cond_write_av_list(p, node->false_list, fp) != 0)
847			return POLICYDB_ERROR;
848	} else {
849		if (avrule_write_list(p, node->avtrue_list, fp))
850			return POLICYDB_ERROR;
851		if (avrule_write_list(p, node->avfalse_list, fp))
852			return POLICYDB_ERROR;
853	}
854
855	if (p->policy_type != POLICY_KERN &&
856	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
857		buf[0] = cpu_to_le32(node->flags);
858		items = put_entry(buf, sizeof(uint32_t), 1, fp);
859		if (items != 1)
860			return POLICYDB_ERROR;
861	}
862
863	return POLICYDB_SUCCESS;
864}
865
866static int cond_write_list(policydb_t * p, cond_list_t * list,
867			   struct policy_file *fp)
868{
869	cond_node_t *cur;
870	uint32_t len, items;
871	uint32_t buf[1];
872
873	len = 0;
874	for (cur = list; cur != NULL; cur = cur->next)
875		len++;
876	buf[0] = cpu_to_le32(len);
877	items = put_entry(buf, sizeof(uint32_t), 1, fp);
878	if (items != 1)
879		return POLICYDB_ERROR;
880
881	for (cur = list; cur != NULL; cur = cur->next) {
882		if (cond_write_node(p, cur, fp) != 0)
883			return POLICYDB_ERROR;
884	}
885	return POLICYDB_SUCCESS;
886}
887
888/*
889 * Write a security context structure
890 * to a policydb binary representation file.
891 */
892static int context_write(struct policydb *p, context_struct_t * c,
893			 struct policy_file *fp)
894{
895	uint32_t buf[32];
896	size_t items, items2;
897
898	items = 0;
899	buf[items++] = cpu_to_le32(c->user);
900	buf[items++] = cpu_to_le32(c->role);
901	buf[items++] = cpu_to_le32(c->type);
902	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
903	if (items2 != items)
904		return POLICYDB_ERROR;
905	if ((p->policyvers >= POLICYDB_VERSION_MLS
906	     && p->policy_type == POLICY_KERN)
907	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
908		&& p->policy_type == POLICY_BASE))
909		if (mls_write_range_helper(&c->range, fp))
910			return POLICYDB_ERROR;
911
912	return POLICYDB_SUCCESS;
913}
914
915/*
916 * The following *_write functions are used to
917 * write the symbol data to a policy database
918 * binary representation file.
919 */
920
921static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
922{
923	perm_datum_t *perdatum;
924	uint32_t buf[32];
925	size_t items, items2, len;
926	struct policy_data *pd = ptr;
927	struct policy_file *fp = pd->fp;
928
929	perdatum = (perm_datum_t *) datum;
930
931	len = strlen(key);
932	items = 0;
933	buf[items++] = cpu_to_le32(len);
934	buf[items++] = cpu_to_le32(perdatum->s.value);
935	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
936	if (items != items2)
937		return POLICYDB_ERROR;
938
939	items = put_entry(key, 1, len, fp);
940	if (items != len)
941		return POLICYDB_ERROR;
942
943	return POLICYDB_SUCCESS;
944}
945
946static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
947{
948	common_datum_t *comdatum;
949	uint32_t buf[32];
950	size_t items, items2, len;
951	struct policy_data *pd = ptr;
952	struct policy_file *fp = pd->fp;
953
954	comdatum = (common_datum_t *) datum;
955
956	len = strlen(key);
957	items = 0;
958	buf[items++] = cpu_to_le32(len);
959	buf[items++] = cpu_to_le32(comdatum->s.value);
960	buf[items++] = cpu_to_le32(comdatum->permissions.nprim);
961	buf[items++] = cpu_to_le32(comdatum->permissions.table->nel);
962	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
963	if (items != items2)
964		return POLICYDB_ERROR;
965
966	items = put_entry(key, 1, len, fp);
967	if (items != len)
968		return POLICYDB_ERROR;
969
970	if (hashtab_map(comdatum->permissions.table, perm_write, pd))
971		return POLICYDB_ERROR;
972
973	return POLICYDB_SUCCESS;
974}
975
976static int write_cons_helper(policydb_t * p,
977			     constraint_node_t * node, int allowxtarget,
978			     struct policy_file *fp)
979{
980	constraint_node_t *c;
981	constraint_expr_t *e;
982	uint32_t buf[3], nexpr;
983	int items;
984
985	for (c = node; c; c = c->next) {
986		nexpr = 0;
987		for (e = c->expr; e; e = e->next) {
988			nexpr++;
989		}
990		buf[0] = cpu_to_le32(c->permissions);
991		buf[1] = cpu_to_le32(nexpr);
992		items = put_entry(buf, sizeof(uint32_t), 2, fp);
993		if (items != 2)
994			return POLICYDB_ERROR;
995		for (e = c->expr; e; e = e->next) {
996			buf[0] = cpu_to_le32(e->expr_type);
997			buf[1] = cpu_to_le32(e->attr);
998			buf[2] = cpu_to_le32(e->op);
999			items = put_entry(buf, sizeof(uint32_t), 3, fp);
1000			if (items != 3)
1001				return POLICYDB_ERROR;
1002
1003			switch (e->expr_type) {
1004			case CEXPR_NAMES:
1005				if (!allowxtarget && (e->attr & CEXPR_XTARGET))
1006					return POLICYDB_ERROR;
1007				if (ebitmap_write(&e->names, fp)) {
1008					return POLICYDB_ERROR;
1009				}
1010				if ((p->policy_type != POLICY_KERN &&
1011						type_set_write(e->type_names, fp)) ||
1012						(p->policy_type == POLICY_KERN &&
1013						(p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) &&
1014						type_set_write(e->type_names, fp))) {
1015					return POLICYDB_ERROR;
1016				}
1017				break;
1018			default:
1019				break;
1020			}
1021		}
1022	}
1023
1024	return POLICYDB_SUCCESS;
1025}
1026
1027static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
1028{
1029	class_datum_t *cladatum;
1030	constraint_node_t *c;
1031	uint32_t buf[32], ncons;
1032	size_t items, items2, len, len2;
1033	struct policy_data *pd = ptr;
1034	struct policy_file *fp = pd->fp;
1035	struct policydb *p = pd->p;
1036
1037	cladatum = (class_datum_t *) datum;
1038
1039	len = strlen(key);
1040	if (cladatum->comkey)
1041		len2 = strlen(cladatum->comkey);
1042	else
1043		len2 = 0;
1044
1045	ncons = 0;
1046	for (c = cladatum->constraints; c; c = c->next) {
1047		ncons++;
1048	}
1049
1050	items = 0;
1051	buf[items++] = cpu_to_le32(len);
1052	buf[items++] = cpu_to_le32(len2);
1053	buf[items++] = cpu_to_le32(cladatum->s.value);
1054	buf[items++] = cpu_to_le32(cladatum->permissions.nprim);
1055	if (cladatum->permissions.table)
1056		buf[items++] = cpu_to_le32(cladatum->permissions.table->nel);
1057	else
1058		buf[items++] = 0;
1059	buf[items++] = cpu_to_le32(ncons);
1060	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1061	if (items != items2)
1062		return POLICYDB_ERROR;
1063
1064	items = put_entry(key, 1, len, fp);
1065	if (items != len)
1066		return POLICYDB_ERROR;
1067
1068	if (cladatum->comkey) {
1069		items = put_entry(cladatum->comkey, 1, len2, fp);
1070		if (items != len2)
1071			return POLICYDB_ERROR;
1072	}
1073	if (hashtab_map(cladatum->permissions.table, perm_write, pd))
1074		return POLICYDB_ERROR;
1075
1076	if (write_cons_helper(p, cladatum->constraints, 0, fp))
1077		return POLICYDB_ERROR;
1078
1079	if ((p->policy_type == POLICY_KERN
1080	     && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS)
1081	    || (p->policy_type == POLICY_BASE
1082		&& p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) {
1083		/* write out the validatetrans rule */
1084		ncons = 0;
1085		for (c = cladatum->validatetrans; c; c = c->next) {
1086			ncons++;
1087		}
1088		buf[0] = cpu_to_le32(ncons);
1089		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1090		if (items != 1)
1091			return POLICYDB_ERROR;
1092		if (write_cons_helper(p, cladatum->validatetrans, 1, fp))
1093			return POLICYDB_ERROR;
1094	}
1095
1096	if ((p->policy_type == POLICY_KERN &&
1097	     p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) ||
1098	    (p->policy_type == POLICY_BASE &&
1099	     p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) {
1100		char default_range = cladatum->default_range;
1101
1102		buf[0] = cpu_to_le32(cladatum->default_user);
1103		buf[1] = cpu_to_le32(cladatum->default_role);
1104		if (!glblub_version && default_range == DEFAULT_GLBLUB) {
1105			WARN(fp->handle,
1106			     "class %s default_range set to GLBLUB but policy version is %d (%d required), discarding",
1107			     p->p_class_val_to_name[cladatum->s.value - 1], p->policyvers,
1108			     p->policy_type == POLICY_KERN? POLICYDB_VERSION_GLBLUB:MOD_POLICYDB_VERSION_GLBLUB);
1109			default_range = 0;
1110		}
1111		buf[2] = cpu_to_le32(default_range);
1112		items = put_entry(buf, sizeof(uint32_t), 3, fp);
1113		if (items != 3)
1114			return POLICYDB_ERROR;
1115	}
1116
1117	if ((p->policy_type == POLICY_KERN &&
1118	     p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) ||
1119	    (p->policy_type == POLICY_BASE &&
1120	     p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) {
1121		buf[0] = cpu_to_le32(cladatum->default_type);
1122		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1123		if (items != 1)
1124			return POLICYDB_ERROR;
1125	}
1126
1127	return POLICYDB_SUCCESS;
1128}
1129
1130static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
1131{
1132	role_datum_t *role;
1133	uint32_t buf[32];
1134	size_t items, items2, len;
1135	struct policy_data *pd = ptr;
1136	struct policy_file *fp = pd->fp;
1137	struct policydb *p = pd->p;
1138
1139	role = (role_datum_t *) datum;
1140
1141	/*
1142	 * Role attributes are redundant for policy.X, skip them
1143	 * when writing the roles symbol table. They are also skipped
1144	 * when pp is downgraded.
1145	 *
1146	 * Their numbers would be deducted in policydb_write().
1147	 */
1148	if ((role->flavor == ROLE_ATTRIB) &&
1149	    ((p->policy_type == POLICY_KERN) ||
1150	     (p->policy_type != POLICY_KERN &&
1151	      p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
1152		return POLICYDB_SUCCESS;
1153
1154	len = strlen(key);
1155	items = 0;
1156	buf[items++] = cpu_to_le32(len);
1157	buf[items++] = cpu_to_le32(role->s.value);
1158	if (policydb_has_boundary_feature(p))
1159		buf[items++] = cpu_to_le32(role->bounds);
1160	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1161	if (items != items2)
1162		return POLICYDB_ERROR;
1163
1164	items = put_entry(key, 1, len, fp);
1165	if (items != len)
1166		return POLICYDB_ERROR;
1167
1168	if (ebitmap_write(&role->dominates, fp))
1169		return POLICYDB_ERROR;
1170	if (p->policy_type == POLICY_KERN) {
1171		if (role->s.value == OBJECT_R_VAL) {
1172			/*
1173			 * CIL populates object_r's types map
1174			 * rather than handling it as a special case.
1175			 * However, this creates an inconsistency with
1176			 * the kernel policy read from /sys/fs/selinux/policy
1177			 * because the kernel ignores everything except for
1178			 * object_r's value from the policy file.
1179			 * Make them consistent by writing an empty
1180			 * ebitmap instead.
1181			 */
1182			ebitmap_t empty;
1183			ebitmap_init(&empty);
1184			if (ebitmap_write(&empty, fp))
1185				return POLICYDB_ERROR;
1186		} else {
1187			if (ebitmap_write(&role->types.types, fp))
1188				return POLICYDB_ERROR;
1189		}
1190	} else {
1191		if (type_set_write(&role->types, fp))
1192			return POLICYDB_ERROR;
1193	}
1194
1195	if (p->policy_type != POLICY_KERN &&
1196	    p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) {
1197		buf[0] = cpu_to_le32(role->flavor);
1198		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1199		if (items != 1)
1200			return POLICYDB_ERROR;
1201
1202		if (ebitmap_write(&role->roles, fp))
1203			return POLICYDB_ERROR;
1204	}
1205
1206	return POLICYDB_SUCCESS;
1207}
1208
1209static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
1210{
1211	type_datum_t *typdatum;
1212	uint32_t buf[32];
1213	size_t items, items2, len;
1214	struct policy_data *pd = ptr;
1215	struct policy_file *fp = pd->fp;
1216	struct policydb *p = pd->p;
1217
1218	typdatum = (type_datum_t *) datum;
1219
1220	/*
1221	 * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
1222	 * does not support to load entries of attribute, so we skip to write it.
1223	 */
1224	if (p->policy_type == POLICY_KERN
1225	    && p->policyvers < POLICYDB_VERSION_BOUNDARY
1226	    && typdatum->flavor == TYPE_ATTRIB)
1227		return POLICYDB_SUCCESS;
1228
1229	len = strlen(key);
1230	items = 0;
1231	buf[items++] = cpu_to_le32(len);
1232	buf[items++] = cpu_to_le32(typdatum->s.value);
1233	if (policydb_has_boundary_feature(p)) {
1234		uint32_t properties = 0;
1235
1236		if (p->policy_type != POLICY_KERN
1237		    && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) {
1238			buf[items++] = cpu_to_le32(typdatum->primary);
1239		}
1240
1241		if (typdatum->primary)
1242			properties |= TYPEDATUM_PROPERTY_PRIMARY;
1243
1244		if (typdatum->flavor == TYPE_ATTRIB) {
1245			properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
1246		} else if (typdatum->flavor == TYPE_ALIAS
1247			   && p->policy_type != POLICY_KERN)
1248			properties |= TYPEDATUM_PROPERTY_ALIAS;
1249
1250		if (typdatum->flags & TYPE_FLAGS_PERMISSIVE
1251		    && p->policy_type != POLICY_KERN)
1252			properties |= TYPEDATUM_PROPERTY_PERMISSIVE;
1253
1254		buf[items++] = cpu_to_le32(properties);
1255		buf[items++] = cpu_to_le32(typdatum->bounds);
1256	} else {
1257		buf[items++] = cpu_to_le32(typdatum->primary);
1258
1259		if (p->policy_type != POLICY_KERN) {
1260			buf[items++] = cpu_to_le32(typdatum->flavor);
1261
1262			if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
1263				buf[items++] = cpu_to_le32(typdatum->flags);
1264			else if (typdatum->flags & TYPE_FLAGS_PERMISSIVE)
1265				WARN(fp->handle, "Warning! Module policy "
1266				     "version %d cannot support permissive "
1267				     "types, but one was defined",
1268				     p->policyvers);
1269		}
1270	}
1271	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1272	if (items != items2)
1273		return POLICYDB_ERROR;
1274
1275	if (p->policy_type != POLICY_KERN) {
1276		if (ebitmap_write(&typdatum->types, fp))
1277			return POLICYDB_ERROR;
1278	}
1279
1280	items = put_entry(key, 1, len, fp);
1281	if (items != len)
1282		return POLICYDB_ERROR;
1283
1284	return POLICYDB_SUCCESS;
1285}
1286
1287static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
1288{
1289	user_datum_t *usrdatum;
1290	uint32_t buf[32];
1291	size_t items, items2, len;
1292	struct policy_data *pd = ptr;
1293	struct policy_file *fp = pd->fp;
1294	struct policydb *p = pd->p;
1295
1296	usrdatum = (user_datum_t *) datum;
1297
1298	len = strlen(key);
1299	items = 0;
1300	buf[items++] = cpu_to_le32(len);
1301	buf[items++] = cpu_to_le32(usrdatum->s.value);
1302	if (policydb_has_boundary_feature(p))
1303		buf[items++] = cpu_to_le32(usrdatum->bounds);
1304	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1305	if (items != items2)
1306		return POLICYDB_ERROR;
1307
1308	items = put_entry(key, 1, len, fp);
1309	if (items != len)
1310		return POLICYDB_ERROR;
1311
1312	if (p->policy_type == POLICY_KERN) {
1313		if (ebitmap_write(&usrdatum->roles.roles, fp))
1314			return POLICYDB_ERROR;
1315	} else {
1316		if (role_set_write(&usrdatum->roles, fp))
1317			return POLICYDB_ERROR;
1318	}
1319
1320	if ((p->policyvers >= POLICYDB_VERSION_MLS
1321	     && p->policy_type == POLICY_KERN)
1322	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
1323		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
1324		&& p->policy_type == POLICY_MOD)
1325	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
1326		&& p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS
1327		&& p->policy_type == POLICY_BASE)) {
1328		if (mls_write_range_helper(&usrdatum->exp_range, fp))
1329			return POLICYDB_ERROR;
1330		if (mls_write_level(&usrdatum->exp_dfltlevel, fp))
1331			return POLICYDB_ERROR;
1332	} else if ((p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
1333		    && p->policy_type == POLICY_MOD)
1334		   || (p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS
1335		       && p->policy_type == POLICY_BASE)) {
1336		if (mls_write_semantic_range_helper(&usrdatum->range, fp))
1337			return -1;
1338		if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp))
1339			return -1;
1340	}
1341
1342	return POLICYDB_SUCCESS;
1343}
1344
1345static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
1346				void *datap) = {
1347common_write, class_write, role_write, type_write, user_write,
1348	    cond_write_bool, sens_write, cat_write,};
1349
1350static int ocontext_write_xen(const struct policydb_compat_info *info, policydb_t *p,
1351			  struct policy_file *fp)
1352{
1353	unsigned int i, j;
1354	size_t nel, items, len;
1355	uint32_t buf[32];
1356	ocontext_t *c;
1357	for (i = 0; i < info->ocon_num; i++) {
1358		nel = 0;
1359		for (c = p->ocontexts[i]; c; c = c->next) {
1360			if (i == OCON_XEN_ISID && !c->context[0].user) {
1361				INFO(fp->handle,
1362				     "No context assigned to SID %s, omitting from policy",
1363				     c->u.name);
1364				continue;
1365			}
1366			nel++;
1367		}
1368		buf[0] = cpu_to_le32(nel);
1369		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1370		if (items != 1)
1371			return POLICYDB_ERROR;
1372		for (c = p->ocontexts[i]; c; c = c->next) {
1373			switch (i) {
1374			case OCON_XEN_ISID:
1375				if (!c->context[0].user)
1376					break;
1377				buf[0] = cpu_to_le32(c->sid[0]);
1378				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1379				if (items != 1)
1380					return POLICYDB_ERROR;
1381				if (context_write(p, &c->context[0], fp))
1382					return POLICYDB_ERROR;
1383				break;
1384			case OCON_XEN_PIRQ:
1385				buf[0] = cpu_to_le32(c->u.pirq);
1386				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1387				if (items != 1)
1388					return POLICYDB_ERROR;
1389				if (context_write(p, &c->context[0], fp))
1390					return POLICYDB_ERROR;
1391				break;
1392			case OCON_XEN_IOPORT:
1393				buf[0] = c->u.ioport.low_ioport;
1394				buf[1] = c->u.ioport.high_ioport;
1395				for (j = 0; j < 2; j++)
1396					buf[j] = cpu_to_le32(buf[j]);
1397				items = put_entry(buf, sizeof(uint32_t), 2, fp);
1398				if (items != 2)
1399					return POLICYDB_ERROR;
1400				if (context_write(p, &c->context[0], fp))
1401					return POLICYDB_ERROR;
1402				break;
1403			case OCON_XEN_IOMEM:
1404				if (p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE) {
1405					uint64_t b64[2];
1406					b64[0] = c->u.iomem.low_iomem;
1407					b64[1] = c->u.iomem.high_iomem;
1408					for (j = 0; j < 2; j++)
1409						b64[j] = cpu_to_le64(b64[j]);
1410					items = put_entry(b64, sizeof(uint64_t), 2, fp);
1411					if (items != 2)
1412						return POLICYDB_ERROR;
1413				} else {
1414					if (c->u.iomem.high_iomem > 0xFFFFFFFFULL) {
1415						ERR(fp->handle, "policy version %d"
1416							" cannot represent IOMEM addresses over 16TB",
1417							p->policyvers);
1418						return POLICYDB_ERROR;
1419					}
1420
1421					buf[0] = c->u.iomem.low_iomem;
1422					buf[1] = c->u.iomem.high_iomem;
1423					for (j = 0; j < 2; j++)
1424						buf[j] = cpu_to_le32(buf[j]);
1425					items = put_entry(buf, sizeof(uint32_t), 2, fp);
1426					if (items != 2)
1427						return POLICYDB_ERROR;
1428				}
1429				if (context_write(p, &c->context[0], fp))
1430					return POLICYDB_ERROR;
1431				break;
1432			case OCON_XEN_PCIDEVICE:
1433				buf[0] = cpu_to_le32(c->u.device);
1434				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1435				if (items != 1)
1436					return POLICYDB_ERROR;
1437				if (context_write(p, &c->context[0], fp))
1438					return POLICYDB_ERROR;
1439				break;
1440			case OCON_XEN_DEVICETREE:
1441				len = strlen(c->u.name);
1442				buf[0] = cpu_to_le32(len);
1443				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1444				if (items != 1)
1445					return POLICYDB_ERROR;
1446				items = put_entry(c->u.name, 1, len, fp);
1447				if (items != len)
1448					return POLICYDB_ERROR;
1449				if (context_write(p, &c->context[0], fp))
1450					return POLICYDB_ERROR;
1451				break;
1452			}
1453		}
1454	}
1455	return POLICYDB_SUCCESS;
1456}
1457
1458static int ocontext_write_selinux(const struct policydb_compat_info *info,
1459	policydb_t *p, struct policy_file *fp)
1460{
1461	unsigned int i, j;
1462	size_t nel, items, len;
1463	uint32_t buf[32];
1464	ocontext_t *c;
1465	for (i = 0; i < info->ocon_num; i++) {
1466		nel = 0;
1467		for (c = p->ocontexts[i]; c; c = c->next) {
1468			if (i == OCON_ISID && !c->context[0].user) {
1469				INFO(fp->handle,
1470				     "No context assigned to SID %s, omitting from policy",
1471				     c->u.name);
1472				continue;
1473			}
1474			nel++;
1475		}
1476		buf[0] = cpu_to_le32(nel);
1477		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1478		if (items != 1)
1479			return POLICYDB_ERROR;
1480		for (c = p->ocontexts[i]; c; c = c->next) {
1481			switch (i) {
1482			case OCON_ISID:
1483				if (!c->context[0].user)
1484					break;
1485				buf[0] = cpu_to_le32(c->sid[0]);
1486				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1487				if (items != 1)
1488					return POLICYDB_ERROR;
1489				if (context_write(p, &c->context[0], fp))
1490					return POLICYDB_ERROR;
1491				break;
1492			case OCON_FS:
1493			case OCON_NETIF:
1494				len = strlen(c->u.name);
1495				buf[0] = cpu_to_le32(len);
1496				items = put_entry(buf, sizeof(uint32_t), 1, fp);
1497				if (items != 1)
1498					return POLICYDB_ERROR;
1499				items = put_entry(c->u.name, 1, len, fp);
1500				if (items != len)
1501					return POLICYDB_ERROR;
1502				if (context_write(p, &c->context[0], fp))
1503					return POLICYDB_ERROR;
1504				if (context_write(p, &c->context[1], fp))
1505					return POLICYDB_ERROR;
1506				break;
1507			case OCON_IBPKEY:
1508				 /* The subnet prefix is in network order */
1509				memcpy(buf, &c->u.ibpkey.subnet_prefix,
1510				       sizeof(c->u.ibpkey.subnet_prefix));
1511
1512				buf[2] = cpu_to_le32(c->u.ibpkey.low_pkey);
1513				buf[3] = cpu_to_le32(c->u.ibpkey.high_pkey);
1514
1515				items = put_entry(buf, sizeof(uint32_t), 4, fp);
1516				if (items != 4)
1517					return POLICYDB_ERROR;
1518
1519				if (context_write(p, &c->context[0], fp))
1520					return POLICYDB_ERROR;
1521				break;
1522			case OCON_IBENDPORT:
1523				len = strlen(c->u.ibendport.dev_name);
1524				buf[0] = cpu_to_le32(len);
1525				buf[1] = cpu_to_le32(c->u.ibendport.port);
1526				items = put_entry(buf, sizeof(uint32_t), 2, fp);
1527				if (items != 2)
1528					return POLICYDB_ERROR;
1529				items = put_entry(c->u.ibendport.dev_name, 1, len, fp);
1530				if (items != len)
1531					return POLICYDB_ERROR;
1532
1533				if (context_write(p, &c->context[0], fp))
1534					return POLICYDB_ERROR;
1535				break;
1536			case OCON_PORT:
1537				buf[0] = c->u.port.protocol;
1538				buf[1] = c->u.port.low_port;
1539				buf[2] = c->u.port.high_port;
1540				for (j = 0; j < 3; j++) {
1541					buf[j] = cpu_to_le32(buf[j]);
1542				}
1543				items = put_entry(buf, sizeof(uint32_t), 3, fp);
1544				if (items != 3)
1545					return POLICYDB_ERROR;
1546				if (context_write(p, &c->context[0], fp))
1547					return POLICYDB_ERROR;
1548				break;
1549			case OCON_NODE:
1550				buf[0] = c->u.node.addr; /* network order */
1551				buf[1] = c->u.node.mask; /* network order */
1552				items = put_entry(buf, sizeof(uint32_t), 2, fp);
1553				if (items != 2)
1554					return POLICYDB_ERROR;
1555				if (context_write(p, &c->context[0], fp))
1556					return POLICYDB_ERROR;
1557				break;
1558			case OCON_FSUSE:
1559				buf[0] = cpu_to_le32(c->v.behavior);
1560				len = strlen(c->u.name);
1561				buf[1] = cpu_to_le32(len);
1562				items = put_entry(buf, sizeof(uint32_t), 2, fp);
1563				if (items != 2)
1564					return POLICYDB_ERROR;
1565				items = put_entry(c->u.name, 1, len, fp);
1566				if (items != len)
1567					return POLICYDB_ERROR;
1568				if (context_write(p, &c->context[0], fp))
1569					return POLICYDB_ERROR;
1570				break;
1571			case OCON_NODE6:
1572				for (j = 0; j < 4; j++)
1573					buf[j] = c->u.node6.addr[j]; /* network order */
1574				for (j = 0; j < 4; j++)
1575					buf[j + 4] = c->u.node6.mask[j]; /* network order */
1576				items = put_entry(buf, sizeof(uint32_t), 8, fp);
1577				if (items != 8)
1578					return POLICYDB_ERROR;
1579				if (context_write(p, &c->context[0], fp))
1580					return POLICYDB_ERROR;
1581				break;
1582			}
1583		}
1584	}
1585	return POLICYDB_SUCCESS;
1586}
1587
1588static int ocontext_write(const struct policydb_compat_info *info, policydb_t * p,
1589	struct policy_file *fp)
1590{
1591	int rc = POLICYDB_ERROR;
1592	switch (p->target_platform) {
1593	case SEPOL_TARGET_SELINUX:
1594		rc = ocontext_write_selinux(info, p, fp);
1595		break;
1596	case SEPOL_TARGET_XEN:
1597		rc = ocontext_write_xen(info, p, fp);
1598		break;
1599	}
1600	return rc;
1601}
1602
1603static int genfs_write(policydb_t * p, struct policy_file *fp)
1604{
1605	genfs_t *genfs;
1606	ocontext_t *c;
1607	size_t nel = 0, items, len;
1608	uint32_t buf[32];
1609
1610	for (genfs = p->genfs; genfs; genfs = genfs->next)
1611		nel++;
1612	buf[0] = cpu_to_le32(nel);
1613	items = put_entry(buf, sizeof(uint32_t), 1, fp);
1614	if (items != 1)
1615		return POLICYDB_ERROR;
1616	for (genfs = p->genfs; genfs; genfs = genfs->next) {
1617		len = strlen(genfs->fstype);
1618		buf[0] = cpu_to_le32(len);
1619		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1620		if (items != 1)
1621			return POLICYDB_ERROR;
1622		items = put_entry(genfs->fstype, 1, len, fp);
1623		if (items != len)
1624			return POLICYDB_ERROR;
1625		nel = 0;
1626		for (c = genfs->head; c; c = c->next)
1627			nel++;
1628		buf[0] = cpu_to_le32(nel);
1629		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1630		if (items != 1)
1631			return POLICYDB_ERROR;
1632		for (c = genfs->head; c; c = c->next) {
1633			len = strlen(c->u.name);
1634			buf[0] = cpu_to_le32(len);
1635			items = put_entry(buf, sizeof(uint32_t), 1, fp);
1636			if (items != 1)
1637				return POLICYDB_ERROR;
1638			items = put_entry(c->u.name, 1, len, fp);
1639			if (items != len)
1640				return POLICYDB_ERROR;
1641			buf[0] = cpu_to_le32(c->v.sclass);
1642			items = put_entry(buf, sizeof(uint32_t), 1, fp);
1643			if (items != 1)
1644				return POLICYDB_ERROR;
1645			if (context_write(p, &c->context[0], fp))
1646				return POLICYDB_ERROR;
1647		}
1648	}
1649	return POLICYDB_SUCCESS;
1650}
1651
1652
1653struct rangetrans_write_args {
1654	size_t nel;
1655	int new_rangetr;
1656	struct policy_file *fp;
1657	struct policydb *p;
1658};
1659
1660static int rangetrans_count(hashtab_key_t key,
1661			    void *data __attribute__ ((unused)),
1662			    void *ptr)
1663{
1664	struct range_trans *rt = (struct range_trans *)key;
1665	struct rangetrans_write_args *args = ptr;
1666	struct policydb *p = args->p;
1667
1668	/* all range_transitions are written for the new format, only
1669	   process related range_transitions are written for the old
1670	   format, so count accordingly */
1671	if (args->new_rangetr || rt->target_class == p->process_class)
1672		args->nel++;
1673	return 0;
1674}
1675
1676static int range_write_helper(hashtab_key_t key, void *data, void *ptr)
1677{
1678	uint32_t buf[2];
1679	struct range_trans *rt = (struct range_trans *)key;
1680	struct mls_range *r = data;
1681	struct rangetrans_write_args *args = ptr;
1682	struct policy_file *fp = args->fp;
1683	struct policydb *p = args->p;
1684	int new_rangetr = args->new_rangetr;
1685	size_t items;
1686	static int warning_issued = 0;
1687	int rc;
1688
1689	if (!new_rangetr && rt->target_class != p->process_class) {
1690		if (!warning_issued)
1691			WARN(fp->handle, "Discarding range_transition "
1692			     "rules for security classes other than "
1693			     "\"process\"");
1694		warning_issued = 1;
1695		return 0;
1696	}
1697
1698	buf[0] = cpu_to_le32(rt->source_type);
1699	buf[1] = cpu_to_le32(rt->target_type);
1700	items = put_entry(buf, sizeof(uint32_t), 2, fp);
1701	if (items != 2)
1702		return POLICYDB_ERROR;
1703	if (new_rangetr) {
1704		buf[0] = cpu_to_le32(rt->target_class);
1705		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1706		if (items != 1)
1707			return POLICYDB_ERROR;
1708	}
1709	rc = mls_write_range_helper(r, fp);
1710	if (rc)
1711		return rc;
1712
1713	return 0;
1714}
1715
1716static int range_write(policydb_t * p, struct policy_file *fp)
1717{
1718	size_t items;
1719	uint32_t buf[2];
1720	int new_rangetr = (p->policy_type == POLICY_KERN &&
1721			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
1722	struct rangetrans_write_args args;
1723	int rc;
1724
1725	args.nel = 0;
1726	args.new_rangetr = new_rangetr;
1727	args.fp = fp;
1728	args.p = p;
1729	rc = hashtab_map(p->range_tr, rangetrans_count, &args);
1730	if (rc)
1731		return rc;
1732
1733	buf[0] = cpu_to_le32(args.nel);
1734	items = put_entry(buf, sizeof(uint32_t), 1, fp);
1735	if (items != 1)
1736		return POLICYDB_ERROR;
1737
1738	return hashtab_map(p->range_tr, range_write_helper, &args);
1739}
1740
1741/************** module writing functions below **************/
1742
1743static int avrule_write(policydb_t *p, avrule_t * avrule,
1744			struct policy_file *fp)
1745{
1746	size_t items, items2;
1747	uint32_t buf[32], len;
1748	class_perm_node_t *cur;
1749
1750	if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS &&
1751	    (avrule->specified & AVRULE_TYPE) &&
1752	    (avrule->flags & RULE_SELF)) {
1753		ERR(fp->handle,
1754		    "Module contains a self rule not supported by the target module policy version");
1755		return POLICYDB_ERROR;
1756	}
1757
1758	items = 0;
1759	buf[items++] = cpu_to_le32(avrule->specified);
1760	buf[items++] = cpu_to_le32(avrule->flags);
1761	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1762	if (items2 != items)
1763		return POLICYDB_ERROR;
1764
1765	if (type_set_write(&avrule->stypes, fp))
1766		return POLICYDB_ERROR;
1767
1768	if (type_set_write(&avrule->ttypes, fp))
1769		return POLICYDB_ERROR;
1770
1771	cur = avrule->perms;
1772	len = 0;
1773	while (cur) {
1774		len++;
1775		cur = cur->next;
1776	}
1777	items = 0;
1778	buf[items++] = cpu_to_le32(len);
1779	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1780	if (items2 != items)
1781		return POLICYDB_ERROR;
1782	cur = avrule->perms;
1783	while (cur) {
1784		items = 0;
1785		buf[items++] = cpu_to_le32(cur->tclass);
1786		buf[items++] = cpu_to_le32(cur->data);
1787		items2 = put_entry(buf, sizeof(uint32_t), items, fp);
1788		if (items2 != items)
1789			return POLICYDB_ERROR;
1790
1791		cur = cur->next;
1792	}
1793
1794	if (avrule->specified & AVRULE_XPERMS) {
1795		size_t nel = ARRAY_SIZE(avrule->xperms->perms);
1796		uint32_t buf32[nel];
1797		uint8_t buf8;
1798		unsigned int i;
1799
1800		if (p->policyvers < MOD_POLICYDB_VERSION_XPERMS_IOCTL) {
1801			ERR(fp->handle,
1802			    "module policy version %u does not support ioctl"
1803			    " extended permissions rules and one was specified",
1804			    p->policyvers);
1805			return POLICYDB_ERROR;
1806		}
1807
1808		if (p->target_platform != SEPOL_TARGET_SELINUX) {
1809			ERR(fp->handle,
1810			    "Target platform %s does not support ioctl"
1811			    " extended permissions rules and one was specified",
1812			    policydb_target_strings[p->target_platform]);
1813			return POLICYDB_ERROR;
1814		}
1815
1816		buf8 = avrule->xperms->specified;
1817		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
1818		if (items != 1)
1819			return POLICYDB_ERROR;
1820		buf8 = avrule->xperms->driver;
1821		items = put_entry(&buf8, sizeof(uint8_t),1,fp);
1822		if (items != 1)
1823			return POLICYDB_ERROR;
1824		for (i = 0; i < nel; i++)
1825			buf32[i] = cpu_to_le32(avrule->xperms->perms[i]);
1826		items = put_entry(buf32, sizeof(uint32_t), nel, fp);
1827		if (items != nel)
1828			return POLICYDB_ERROR;
1829	}
1830
1831	return POLICYDB_SUCCESS;
1832}
1833
1834static int avrule_write_list(policydb_t *p, avrule_t * avrules,
1835			     struct policy_file *fp)
1836{
1837	uint32_t buf[32], len;
1838	avrule_t *avrule;
1839
1840	avrule = avrules;
1841	len = 0;
1842	while (avrule) {
1843		len++;
1844		avrule = avrule->next;
1845	}
1846
1847	buf[0] = cpu_to_le32(len);
1848	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1)
1849		return POLICYDB_ERROR;
1850
1851	avrule = avrules;
1852	while (avrule) {
1853		if (avrule_write(p, avrule, fp))
1854			return POLICYDB_ERROR;
1855		avrule = avrule->next;
1856	}
1857
1858	return POLICYDB_SUCCESS;
1859}
1860
1861static int only_process(ebitmap_t *in, struct policydb *p)
1862{
1863	unsigned int i, value;
1864	ebitmap_node_t *node;
1865
1866	if (!p->process_class)
1867		return 0;
1868
1869	value = p->process_class - 1;
1870
1871	ebitmap_for_each_positive_bit(in, node, i) {
1872		if (i != value)
1873			return 0;
1874	}
1875	return 1;
1876}
1877
1878static int role_trans_rule_write(policydb_t *p, role_trans_rule_t * t,
1879				 struct policy_file *fp)
1880{
1881	int nel = 0;
1882	size_t items;
1883	uint32_t buf[1];
1884	role_trans_rule_t *tr;
1885	int warned = 0;
1886	int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS;
1887
1888	for (tr = t; tr; tr = tr->next)
1889		if (new_role || only_process(&tr->classes, p))
1890			nel++;
1891
1892	buf[0] = cpu_to_le32(nel);
1893	items = put_entry(buf, sizeof(uint32_t), 1, fp);
1894	if (items != 1)
1895		return POLICYDB_ERROR;
1896	for (tr = t; tr; tr = tr->next) {
1897		if (!new_role && !only_process(&tr->classes, p)) {
1898			if (!warned)
1899				WARN(fp->handle, "Discarding role_transition "
1900					"rules for security classes other than "
1901					"\"process\"");
1902			warned = 1;
1903			continue;
1904		}
1905		if (role_set_write(&tr->roles, fp))
1906			return POLICYDB_ERROR;
1907		if (type_set_write(&tr->types, fp))
1908			return POLICYDB_ERROR;
1909		if (new_role)
1910			if (ebitmap_write(&tr->classes, fp))
1911				return POLICYDB_ERROR;
1912		buf[0] = cpu_to_le32(tr->new_role);
1913		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1914		if (items != 1)
1915			return POLICYDB_ERROR;
1916	}
1917	return POLICYDB_SUCCESS;
1918}
1919
1920static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp)
1921{
1922	int nel = 0;
1923	size_t items;
1924	uint32_t buf[1];
1925	role_allow_rule_t *ra;
1926
1927	for (ra = r; ra; ra = ra->next)
1928		nel++;
1929	buf[0] = cpu_to_le32(nel);
1930	items = put_entry(buf, sizeof(uint32_t), 1, fp);
1931	if (items != 1)
1932		return POLICYDB_ERROR;
1933	for (ra = r; ra; ra = ra->next) {
1934		if (role_set_write(&ra->roles, fp))
1935			return POLICYDB_ERROR;
1936		if (role_set_write(&ra->new_roles, fp))
1937			return POLICYDB_ERROR;
1938	}
1939	return POLICYDB_SUCCESS;
1940}
1941
1942static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t,
1943				     struct policy_file *fp)
1944{
1945	int nel = 0;
1946	size_t items, entries;
1947	uint32_t buf[3], len;
1948	filename_trans_rule_t *ftr;
1949
1950	for (ftr = t; ftr; ftr = ftr->next)
1951		nel++;
1952
1953	buf[0] = cpu_to_le32(nel);
1954	items = put_entry(buf, sizeof(uint32_t), 1, fp);
1955	if (items != 1)
1956		return POLICYDB_ERROR;
1957
1958	for (ftr = t; ftr; ftr = ftr->next) {
1959		len = strlen(ftr->name);
1960		buf[0] = cpu_to_le32(len);
1961		items = put_entry(buf, sizeof(uint32_t), 1, fp);
1962		if (items != 1)
1963			return POLICYDB_ERROR;
1964
1965		items = put_entry(ftr->name, sizeof(char), len, fp);
1966		if (items != len)
1967			return POLICYDB_ERROR;
1968
1969		if (type_set_write(&ftr->stypes, fp))
1970			return POLICYDB_ERROR;
1971		if (type_set_write(&ftr->ttypes, fp))
1972			return POLICYDB_ERROR;
1973
1974		buf[0] = cpu_to_le32(ftr->tclass);
1975		buf[1] = cpu_to_le32(ftr->otype);
1976		buf[2] = cpu_to_le32(ftr->flags);
1977
1978		if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) {
1979			entries = 3;
1980		} else if (!(ftr->flags & RULE_SELF)) {
1981			entries = 2;
1982		} else {
1983			ERR(fp->handle,
1984			    "Module contains a self rule not supported by the target module policy version");
1985			return POLICYDB_ERROR;
1986		}
1987
1988		items = put_entry(buf, sizeof(uint32_t), entries, fp);
1989		if (items != entries)
1990			return POLICYDB_ERROR;
1991	}
1992	return POLICYDB_SUCCESS;
1993}
1994
1995static int range_trans_rule_write(range_trans_rule_t * t,
1996				  struct policy_file *fp)
1997{
1998	int nel = 0;
1999	size_t items;
2000	uint32_t buf[1];
2001	range_trans_rule_t *rt;
2002
2003	for (rt = t; rt; rt = rt->next)
2004		nel++;
2005	buf[0] = cpu_to_le32(nel);
2006	items = put_entry(buf, sizeof(uint32_t), 1, fp);
2007	if (items != 1)
2008		return POLICYDB_ERROR;
2009	for (rt = t; rt; rt = rt->next) {
2010		if (type_set_write(&rt->stypes, fp))
2011			return POLICYDB_ERROR;
2012		if (type_set_write(&rt->ttypes, fp))
2013			return POLICYDB_ERROR;
2014		if (ebitmap_write(&rt->tclasses, fp))
2015			return POLICYDB_ERROR;
2016		if (mls_write_semantic_range_helper(&rt->trange, fp))
2017			return POLICYDB_ERROR;
2018	}
2019	return POLICYDB_SUCCESS;
2020}
2021
2022static int scope_index_write(scope_index_t * scope_index,
2023			     unsigned int num_scope_syms,
2024			     struct policy_file *fp)
2025{
2026	unsigned int i;
2027	uint32_t buf[1];
2028	for (i = 0; i < num_scope_syms; i++) {
2029		if (ebitmap_write(scope_index->scope + i, fp) == -1) {
2030			return POLICYDB_ERROR;
2031		}
2032	}
2033	buf[0] = cpu_to_le32(scope_index->class_perms_len);
2034	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
2035		return POLICYDB_ERROR;
2036	}
2037	for (i = 0; i < scope_index->class_perms_len; i++) {
2038		if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) {
2039			return POLICYDB_ERROR;
2040		}
2041	}
2042	return POLICYDB_SUCCESS;
2043}
2044
2045static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms,
2046			     policydb_t * p, struct policy_file *fp)
2047{
2048	struct policy_data pd;
2049	uint32_t buf[2];
2050	int i;
2051	buf[0] = cpu_to_le32(decl->decl_id);
2052	buf[1] = cpu_to_le32(decl->enabled);
2053	if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
2054		return POLICYDB_ERROR;
2055	}
2056	if (cond_write_list(p, decl->cond_list, fp) == -1 ||
2057	    avrule_write_list(p, decl->avrules, fp) == -1 ||
2058	    role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 ||
2059	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
2060		return POLICYDB_ERROR;
2061	}
2062
2063	if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS &&
2064	    filename_trans_rule_write(p, decl->filename_trans_rules, fp))
2065		return POLICYDB_ERROR;
2066
2067	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
2068	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
2069		return POLICYDB_ERROR;
2070	}
2071	if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 ||
2072	    scope_index_write(&decl->declared, num_scope_syms, fp) == -1) {
2073		return POLICYDB_ERROR;
2074	}
2075	pd.fp = fp;
2076	pd.p = p;
2077	for (i = 0; i < num_scope_syms; i++) {
2078		buf[0] = cpu_to_le32(decl->symtab[i].nprim);
2079		buf[1] = cpu_to_le32(decl->symtab[i].table->nel);
2080		if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) {
2081			return POLICYDB_ERROR;
2082		}
2083		if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) {
2084			return POLICYDB_ERROR;
2085		}
2086	}
2087	return POLICYDB_SUCCESS;
2088}
2089
2090static int avrule_block_write(avrule_block_t * block, int num_scope_syms,
2091			      policydb_t * p, struct policy_file *fp)
2092{
2093	/* first write a count of the total number of blocks */
2094	uint32_t buf[1], num_blocks = 0;
2095	avrule_block_t *cur;
2096	for (cur = block; cur != NULL; cur = cur->next) {
2097		num_blocks++;
2098	}
2099	buf[0] = cpu_to_le32(num_blocks);
2100	if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
2101		return POLICYDB_ERROR;
2102	}
2103
2104	/* now write each block */
2105	for (cur = block; cur != NULL; cur = cur->next) {
2106		uint32_t num_decls = 0;
2107		avrule_decl_t *decl;
2108		/* write a count of number of branches */
2109		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
2110			num_decls++;
2111		}
2112		buf[0] = cpu_to_le32(num_decls);
2113		if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
2114			return POLICYDB_ERROR;
2115		}
2116		for (decl = cur->branch_list; decl != NULL; decl = decl->next) {
2117			if (avrule_decl_write(decl, num_scope_syms, p, fp) ==
2118			    -1) {
2119				return POLICYDB_ERROR;
2120			}
2121		}
2122	}
2123	return POLICYDB_SUCCESS;
2124}
2125
2126static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
2127{
2128	scope_datum_t *scope = (scope_datum_t *) datum;
2129	struct policy_data *pd = ptr;
2130	struct policy_file *fp = pd->fp;
2131	uint32_t static_buf[32], *dyn_buf = NULL, *buf;
2132	size_t key_len = strlen(key);
2133	unsigned int items = 2 + scope->decl_ids_len, i;
2134	int rc;
2135
2136	buf = static_buf;
2137	if (items >= (sizeof(static_buf) / 4)) {
2138		/* too many things required, so dynamically create a
2139		 * buffer.  this would have been easier with C99's
2140		 * dynamic arrays... */
2141		rc = POLICYDB_ERROR;
2142		dyn_buf = calloc(items, sizeof(*dyn_buf));
2143		if (!dyn_buf)
2144			goto err;
2145		buf = dyn_buf;
2146	}
2147	buf[0] = cpu_to_le32(key_len);
2148
2149	rc = POLICYDB_ERROR;
2150	if (put_entry(buf, sizeof(*buf), 1, fp) != 1 ||
2151	    put_entry(key, 1, key_len, fp) != key_len)
2152		goto err;
2153	buf[0] = cpu_to_le32(scope->scope);
2154	buf[1] = cpu_to_le32(scope->decl_ids_len);
2155
2156	for (i = 0; i < scope->decl_ids_len; i++)
2157		buf[2 + i] = cpu_to_le32(scope->decl_ids[i]);
2158
2159	rc = POLICYDB_ERROR;
2160	if (put_entry(buf, sizeof(*buf), items, fp) != items)
2161		goto err;
2162	rc = POLICYDB_SUCCESS;
2163err:
2164	free(dyn_buf);
2165	return rc;
2166}
2167
2168static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
2169			     hashtab_datum_t datum, void *args)
2170{
2171	type_datum_t *typdatum = datum;
2172	uint32_t *p_nel = args;
2173
2174	if (typdatum->flavor == TYPE_ATTRIB) {
2175		/* uncount attribute from total number of types */
2176		(*p_nel)--;
2177	}
2178	return 0;
2179}
2180
2181static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
2182			     hashtab_datum_t datum, void *args)
2183{
2184	role_datum_t *role = datum;
2185	uint32_t *p_nel = args;
2186
2187	if (role->flavor == ROLE_ATTRIB) {
2188		/* uncount attribute from total number of roles */
2189		(*p_nel)--;
2190	}
2191	return 0;
2192}
2193
2194/*
2195 * Write the configuration data in a policy database
2196 * structure to a policy database binary representation
2197 * file.
2198 */
2199int policydb_write(policydb_t * p, struct policy_file *fp)
2200{
2201	unsigned int i, num_syms;
2202	uint32_t buf[32], config;
2203	size_t items, items2, len;
2204	const struct policydb_compat_info *info;
2205	struct policy_data pd;
2206	const char *policydb_str;
2207
2208	if (p->unsupported_format)
2209		return POLICYDB_UNSUPPORTED;
2210
2211	pd.fp = fp;
2212	pd.p = p;
2213
2214	config = 0;
2215	if (p->mls) {
2216		if ((p->policyvers < POLICYDB_VERSION_MLS &&
2217		    p->policy_type == POLICY_KERN) ||
2218		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
2219		    p->policy_type == POLICY_BASE) ||
2220		    (p->policyvers < MOD_POLICYDB_VERSION_MLS &&
2221		    p->policy_type == POLICY_MOD)) {
2222			ERR(fp->handle, "policy version %d cannot support MLS",
2223			    p->policyvers);
2224			return POLICYDB_ERROR;
2225		}
2226		config |= POLICYDB_CONFIG_MLS;
2227	}
2228
2229	config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown);
2230
2231	/* Write the magic number and string identifiers. */
2232	items = 0;
2233	if (p->policy_type == POLICY_KERN) {
2234		buf[items++] = cpu_to_le32(POLICYDB_MAGIC);
2235		len = strlen(policydb_target_strings[p->target_platform]);
2236		policydb_str = policydb_target_strings[p->target_platform];
2237	} else {
2238		buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC);
2239		len = strlen(POLICYDB_MOD_STRING);
2240		policydb_str = POLICYDB_MOD_STRING;
2241	}
2242	buf[items++] = cpu_to_le32(len);
2243	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
2244	if (items != items2)
2245		return POLICYDB_ERROR;
2246	items = put_entry(policydb_str, 1, len, fp);
2247	if (items != len)
2248		return POLICYDB_ERROR;
2249
2250	/* Write the version, config, and table sizes. */
2251	items = 0;
2252	info = policydb_lookup_compat(p->policyvers, p->policy_type,
2253					p->target_platform);
2254	if (!info) {
2255		ERR(fp->handle, "compatibility lookup failed for policy "
2256		    "version %d", p->policyvers);
2257		return POLICYDB_ERROR;
2258	}
2259
2260	if (p->policy_type != POLICY_KERN) {
2261		buf[items++] = cpu_to_le32(p->policy_type);
2262	}
2263	buf[items++] = cpu_to_le32(p->policyvers);
2264	buf[items++] = cpu_to_le32(config);
2265	buf[items++] = cpu_to_le32(info->sym_num);
2266	buf[items++] = cpu_to_le32(info->ocon_num);
2267
2268	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
2269	if (items != items2)
2270		return POLICYDB_ERROR;
2271
2272	if (p->policy_type == POLICY_MOD) {
2273		/* Write module name and version */
2274		len = strlen(p->name);
2275		buf[0] = cpu_to_le32(len);
2276		items = put_entry(buf, sizeof(uint32_t), 1, fp);
2277		if (items != 1)
2278			return POLICYDB_ERROR;
2279		items = put_entry(p->name, 1, len, fp);
2280		if (items != len)
2281			return POLICYDB_ERROR;
2282		len = strlen(p->version);
2283		buf[0] = cpu_to_le32(len);
2284		items = put_entry(buf, sizeof(uint32_t), 1, fp);
2285		if (items != 1)
2286			return POLICYDB_ERROR;
2287		items = put_entry(p->version, 1, len, fp);
2288		if (items != len)
2289			return POLICYDB_ERROR;
2290	}
2291
2292	if ((p->policyvers >= POLICYDB_VERSION_POLCAP &&
2293	     p->policy_type == POLICY_KERN) ||
2294	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
2295	     p->policy_type == POLICY_BASE) ||
2296	    (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP &&
2297	     p->policy_type == POLICY_MOD)) {
2298		if (ebitmap_write(&p->policycaps, fp) == -1)
2299			return POLICYDB_ERROR;
2300	}
2301
2302	if (p->policyvers < POLICYDB_VERSION_PERMISSIVE &&
2303	    p->policy_type == POLICY_KERN) {
2304		ebitmap_node_t *tnode;
2305
2306		ebitmap_for_each_positive_bit(&p->permissive_map, tnode, i) {
2307			WARN(fp->handle, "Warning! Policy version %d cannot "
2308			     "support permissive types, but some were defined",
2309			     p->policyvers);
2310			break;
2311		}
2312	}
2313
2314	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
2315	    p->policy_type == POLICY_KERN) {
2316		if (ebitmap_write(&p->permissive_map, fp) == -1)
2317			return POLICYDB_ERROR;
2318	}
2319
2320	num_syms = info->sym_num;
2321	for (i = 0; i < num_syms; i++) {
2322		buf[0] = cpu_to_le32(p->symtab[i].nprim);
2323		buf[1] = p->symtab[i].table->nel;
2324
2325		/*
2326		 * A special case when writing type/attribute symbol table.
2327		 * The kernel policy version less than 24 does not support
2328		 * to load entries of attribute, so we have to re-calculate
2329		 * the actual number of types except for attributes.
2330		 */
2331		if (i == SYM_TYPES &&
2332		    p->policyvers < POLICYDB_VERSION_BOUNDARY &&
2333		    p->policy_type == POLICY_KERN) {
2334			hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]);
2335		}
2336
2337		/*
2338		 * Another special case when writing role/attribute symbol
2339		 * table, role attributes are redundant for policy.X, or
2340		 * when the pp's version is not big enough. So deduct
2341		 * their numbers from p_roles.table->nel.
2342		 */
2343		if ((i == SYM_ROLES) &&
2344		    ((p->policy_type == POLICY_KERN) ||
2345		     (p->policy_type != POLICY_KERN &&
2346		      p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB)))
2347			(void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]);
2348
2349		buf[1] = cpu_to_le32(buf[1]);
2350		items = put_entry(buf, sizeof(uint32_t), 2, fp);
2351		if (items != 2)
2352			return POLICYDB_ERROR;
2353		if (hashtab_map(p->symtab[i].table, write_f[i], &pd))
2354			return POLICYDB_ERROR;
2355	}
2356
2357	if (p->policy_type == POLICY_KERN) {
2358		if (avtab_write(p, &p->te_avtab, fp))
2359			return POLICYDB_ERROR;
2360		if (p->policyvers < POLICYDB_VERSION_BOOL) {
2361			if (p->p_bools.nprim)
2362				WARN(fp->handle, "Discarding "
2363				     "booleans and conditional rules");
2364		} else {
2365			if (cond_write_list(p, p->cond_list, fp))
2366				return POLICYDB_ERROR;
2367		}
2368		if (role_trans_write(p, fp))
2369			return POLICYDB_ERROR;
2370		if (role_allow_write(p->role_allow, fp))
2371			return POLICYDB_ERROR;
2372		if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
2373			if (filename_trans_write(p, fp))
2374				return POLICYDB_ERROR;
2375		} else {
2376			if (p->filename_trans)
2377				WARN(fp->handle, "Discarding filename type transition rules");
2378		}
2379	} else {
2380		if (avrule_block_write(p->global, num_syms, p, fp) == -1) {
2381			return POLICYDB_ERROR;
2382		}
2383
2384		for (i = 0; i < num_syms; i++) {
2385			buf[0] = cpu_to_le32(p->scope[i].table->nel);
2386			if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) {
2387				return POLICYDB_ERROR;
2388			}
2389			if (hashtab_map(p->scope[i].table, scope_write, &pd))
2390				return POLICYDB_ERROR;
2391		}
2392	}
2393
2394	if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) {
2395		return POLICYDB_ERROR;
2396	}
2397
2398	if ((p->policyvers >= POLICYDB_VERSION_MLS
2399	     && p->policy_type == POLICY_KERN)
2400	    || (p->policyvers >= MOD_POLICYDB_VERSION_MLS
2401		&& p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS
2402		&& p->policy_type == POLICY_BASE)) {
2403		if (range_write(p, fp)) {
2404			return POLICYDB_ERROR;
2405		}
2406	}
2407
2408	if (p->policy_type == POLICY_KERN
2409	    && p->policyvers >= POLICYDB_VERSION_AVTAB) {
2410		for (i = 0; i < p->p_types.nprim; i++) {
2411			if (ebitmap_write(&p->type_attr_map[i], fp) == -1)
2412				return POLICYDB_ERROR;
2413		}
2414	}
2415
2416	return POLICYDB_SUCCESS;
2417}
2418