cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

conditional.c (16991B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Authors: Karl MacMillan <kmacmillan@tresys.com>
      3 *	    Frank Mayer <mayerf@tresys.com>
      4 *
      5 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/errno.h>
     10#include <linux/string.h>
     11#include <linux/spinlock.h>
     12#include <linux/slab.h>
     13
     14#include "security.h"
     15#include "conditional.h"
     16#include "services.h"
     17
     18/*
     19 * cond_evaluate_expr evaluates a conditional expr
     20 * in reverse polish notation. It returns true (1), false (0),
     21 * or undefined (-1). Undefined occurs when the expression
     22 * exceeds the stack depth of COND_EXPR_MAXDEPTH.
     23 */
     24static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
     25{
     26	u32 i;
     27	int s[COND_EXPR_MAXDEPTH];
     28	int sp = -1;
     29
     30	if (expr->len == 0)
     31		return -1;
     32
     33	for (i = 0; i < expr->len; i++) {
     34		struct cond_expr_node *node = &expr->nodes[i];
     35
     36		switch (node->expr_type) {
     37		case COND_BOOL:
     38			if (sp == (COND_EXPR_MAXDEPTH - 1))
     39				return -1;
     40			sp++;
     41			s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
     42			break;
     43		case COND_NOT:
     44			if (sp < 0)
     45				return -1;
     46			s[sp] = !s[sp];
     47			break;
     48		case COND_OR:
     49			if (sp < 1)
     50				return -1;
     51			sp--;
     52			s[sp] |= s[sp + 1];
     53			break;
     54		case COND_AND:
     55			if (sp < 1)
     56				return -1;
     57			sp--;
     58			s[sp] &= s[sp + 1];
     59			break;
     60		case COND_XOR:
     61			if (sp < 1)
     62				return -1;
     63			sp--;
     64			s[sp] ^= s[sp + 1];
     65			break;
     66		case COND_EQ:
     67			if (sp < 1)
     68				return -1;
     69			sp--;
     70			s[sp] = (s[sp] == s[sp + 1]);
     71			break;
     72		case COND_NEQ:
     73			if (sp < 1)
     74				return -1;
     75			sp--;
     76			s[sp] = (s[sp] != s[sp + 1]);
     77			break;
     78		default:
     79			return -1;
     80		}
     81	}
     82	return s[0];
     83}
     84
     85/*
     86 * evaluate_cond_node evaluates the conditional stored in
     87 * a struct cond_node and if the result is different than the
     88 * current state of the node it sets the rules in the true/false
     89 * list appropriately. If the result of the expression is undefined
     90 * all of the rules are disabled for safety.
     91 */
     92static void evaluate_cond_node(struct policydb *p, struct cond_node *node)
     93{
     94	struct avtab_node *avnode;
     95	int new_state;
     96	u32 i;
     97
     98	new_state = cond_evaluate_expr(p, &node->expr);
     99	if (new_state != node->cur_state) {
    100		node->cur_state = new_state;
    101		if (new_state == -1)
    102			pr_err("SELinux: expression result was undefined - disabling all rules.\n");
    103		/* turn the rules on or off */
    104		for (i = 0; i < node->true_list.len; i++) {
    105			avnode = node->true_list.nodes[i];
    106			if (new_state <= 0)
    107				avnode->key.specified &= ~AVTAB_ENABLED;
    108			else
    109				avnode->key.specified |= AVTAB_ENABLED;
    110		}
    111
    112		for (i = 0; i < node->false_list.len; i++) {
    113			avnode = node->false_list.nodes[i];
    114			/* -1 or 1 */
    115			if (new_state)
    116				avnode->key.specified &= ~AVTAB_ENABLED;
    117			else
    118				avnode->key.specified |= AVTAB_ENABLED;
    119		}
    120	}
    121}
    122
    123void evaluate_cond_nodes(struct policydb *p)
    124{
    125	u32 i;
    126
    127	for (i = 0; i < p->cond_list_len; i++)
    128		evaluate_cond_node(p, &p->cond_list[i]);
    129}
    130
    131void cond_policydb_init(struct policydb *p)
    132{
    133	p->bool_val_to_struct = NULL;
    134	p->cond_list = NULL;
    135	p->cond_list_len = 0;
    136
    137	avtab_init(&p->te_cond_avtab);
    138}
    139
    140static void cond_node_destroy(struct cond_node *node)
    141{
    142	kfree(node->expr.nodes);
    143	/* the avtab_ptr_t nodes are destroyed by the avtab */
    144	kfree(node->true_list.nodes);
    145	kfree(node->false_list.nodes);
    146}
    147
    148static void cond_list_destroy(struct policydb *p)
    149{
    150	u32 i;
    151
    152	for (i = 0; i < p->cond_list_len; i++)
    153		cond_node_destroy(&p->cond_list[i]);
    154	kfree(p->cond_list);
    155	p->cond_list = NULL;
    156	p->cond_list_len = 0;
    157}
    158
    159void cond_policydb_destroy(struct policydb *p)
    160{
    161	kfree(p->bool_val_to_struct);
    162	avtab_destroy(&p->te_cond_avtab);
    163	cond_list_destroy(p);
    164}
    165
    166int cond_init_bool_indexes(struct policydb *p)
    167{
    168	kfree(p->bool_val_to_struct);
    169	p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
    170					      sizeof(*p->bool_val_to_struct),
    171					      GFP_KERNEL);
    172	if (!p->bool_val_to_struct)
    173		return -ENOMEM;
    174	return 0;
    175}
    176
    177int cond_destroy_bool(void *key, void *datum, void *p)
    178{
    179	kfree(key);
    180	kfree(datum);
    181	return 0;
    182}
    183
    184int cond_index_bool(void *key, void *datum, void *datap)
    185{
    186	struct policydb *p;
    187	struct cond_bool_datum *booldatum;
    188
    189	booldatum = datum;
    190	p = datap;
    191
    192	if (!booldatum->value || booldatum->value > p->p_bools.nprim)
    193		return -EINVAL;
    194
    195	p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
    196	p->bool_val_to_struct[booldatum->value - 1] = booldatum;
    197
    198	return 0;
    199}
    200
    201static int bool_isvalid(struct cond_bool_datum *b)
    202{
    203	if (!(b->state == 0 || b->state == 1))
    204		return 0;
    205	return 1;
    206}
    207
    208int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
    209{
    210	char *key = NULL;
    211	struct cond_bool_datum *booldatum;
    212	__le32 buf[3];
    213	u32 len;
    214	int rc;
    215
    216	booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
    217	if (!booldatum)
    218		return -ENOMEM;
    219
    220	rc = next_entry(buf, fp, sizeof(buf));
    221	if (rc)
    222		goto err;
    223
    224	booldatum->value = le32_to_cpu(buf[0]);
    225	booldatum->state = le32_to_cpu(buf[1]);
    226
    227	rc = -EINVAL;
    228	if (!bool_isvalid(booldatum))
    229		goto err;
    230
    231	len = le32_to_cpu(buf[2]);
    232	if (((len == 0) || (len == (u32)-1)))
    233		goto err;
    234
    235	rc = -ENOMEM;
    236	key = kmalloc(len + 1, GFP_KERNEL);
    237	if (!key)
    238		goto err;
    239	rc = next_entry(key, fp, len);
    240	if (rc)
    241		goto err;
    242	key[len] = '\0';
    243	rc = symtab_insert(s, key, booldatum);
    244	if (rc)
    245		goto err;
    246
    247	return 0;
    248err:
    249	cond_destroy_bool(key, booldatum, NULL);
    250	return rc;
    251}
    252
    253struct cond_insertf_data {
    254	struct policydb *p;
    255	struct avtab_node **dst;
    256	struct cond_av_list *other;
    257};
    258
    259static int cond_insertf(struct avtab *a, const struct avtab_key *k,
    260			const struct avtab_datum *d, void *ptr)
    261{
    262	struct cond_insertf_data *data = ptr;
    263	struct policydb *p = data->p;
    264	struct cond_av_list *other = data->other;
    265	struct avtab_node *node_ptr;
    266	u32 i;
    267	bool found;
    268
    269	/*
    270	 * For type rules we have to make certain there aren't any
    271	 * conflicting rules by searching the te_avtab and the
    272	 * cond_te_avtab.
    273	 */
    274	if (k->specified & AVTAB_TYPE) {
    275		if (avtab_search(&p->te_avtab, k)) {
    276			pr_err("SELinux: type rule already exists outside of a conditional.\n");
    277			return -EINVAL;
    278		}
    279		/*
    280		 * If we are reading the false list other will be a pointer to
    281		 * the true list. We can have duplicate entries if there is only
    282		 * 1 other entry and it is in our true list.
    283		 *
    284		 * If we are reading the true list (other == NULL) there shouldn't
    285		 * be any other entries.
    286		 */
    287		if (other) {
    288			node_ptr = avtab_search_node(&p->te_cond_avtab, k);
    289			if (node_ptr) {
    290				if (avtab_search_node_next(node_ptr, k->specified)) {
    291					pr_err("SELinux: too many conflicting type rules.\n");
    292					return -EINVAL;
    293				}
    294				found = false;
    295				for (i = 0; i < other->len; i++) {
    296					if (other->nodes[i] == node_ptr) {
    297						found = true;
    298						break;
    299					}
    300				}
    301				if (!found) {
    302					pr_err("SELinux: conflicting type rules.\n");
    303					return -EINVAL;
    304				}
    305			}
    306		} else {
    307			if (avtab_search(&p->te_cond_avtab, k)) {
    308				pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
    309				return -EINVAL;
    310			}
    311		}
    312	}
    313
    314	node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
    315	if (!node_ptr) {
    316		pr_err("SELinux: could not insert rule.\n");
    317		return -ENOMEM;
    318	}
    319
    320	*data->dst = node_ptr;
    321	return 0;
    322}
    323
    324static int cond_read_av_list(struct policydb *p, void *fp,
    325			     struct cond_av_list *list,
    326			     struct cond_av_list *other)
    327{
    328	int rc;
    329	__le32 buf[1];
    330	u32 i, len;
    331	struct cond_insertf_data data;
    332
    333	rc = next_entry(buf, fp, sizeof(u32));
    334	if (rc)
    335		return rc;
    336
    337	len = le32_to_cpu(buf[0]);
    338	if (len == 0)
    339		return 0;
    340
    341	list->nodes = kcalloc(len, sizeof(*list->nodes), GFP_KERNEL);
    342	if (!list->nodes)
    343		return -ENOMEM;
    344
    345	data.p = p;
    346	data.other = other;
    347	for (i = 0; i < len; i++) {
    348		data.dst = &list->nodes[i];
    349		rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
    350				     &data);
    351		if (rc) {
    352			kfree(list->nodes);
    353			list->nodes = NULL;
    354			return rc;
    355		}
    356	}
    357
    358	list->len = len;
    359	return 0;
    360}
    361
    362static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
    363{
    364	if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
    365		pr_err("SELinux: conditional expressions uses unknown operator.\n");
    366		return 0;
    367	}
    368
    369	if (expr->bool > p->p_bools.nprim) {
    370		pr_err("SELinux: conditional expressions uses unknown bool.\n");
    371		return 0;
    372	}
    373	return 1;
    374}
    375
    376static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
    377{
    378	__le32 buf[2];
    379	u32 i, len;
    380	int rc;
    381
    382	rc = next_entry(buf, fp, sizeof(u32) * 2);
    383	if (rc)
    384		return rc;
    385
    386	node->cur_state = le32_to_cpu(buf[0]);
    387
    388	/* expr */
    389	len = le32_to_cpu(buf[1]);
    390	node->expr.nodes = kcalloc(len, sizeof(*node->expr.nodes), GFP_KERNEL);
    391	if (!node->expr.nodes)
    392		return -ENOMEM;
    393
    394	node->expr.len = len;
    395
    396	for (i = 0; i < len; i++) {
    397		struct cond_expr_node *expr = &node->expr.nodes[i];
    398
    399		rc = next_entry(buf, fp, sizeof(u32) * 2);
    400		if (rc)
    401			return rc;
    402
    403		expr->expr_type = le32_to_cpu(buf[0]);
    404		expr->bool = le32_to_cpu(buf[1]);
    405
    406		if (!expr_node_isvalid(p, expr))
    407			return -EINVAL;
    408	}
    409
    410	rc = cond_read_av_list(p, fp, &node->true_list, NULL);
    411	if (rc)
    412		return rc;
    413	return cond_read_av_list(p, fp, &node->false_list, &node->true_list);
    414}
    415
    416int cond_read_list(struct policydb *p, void *fp)
    417{
    418	__le32 buf[1];
    419	u32 i, len;
    420	int rc;
    421
    422	rc = next_entry(buf, fp, sizeof(buf));
    423	if (rc)
    424		return rc;
    425
    426	len = le32_to_cpu(buf[0]);
    427
    428	p->cond_list = kcalloc(len, sizeof(*p->cond_list), GFP_KERNEL);
    429	if (!p->cond_list)
    430		return -ENOMEM;
    431
    432	rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
    433	if (rc)
    434		goto err;
    435
    436	p->cond_list_len = len;
    437
    438	for (i = 0; i < len; i++) {
    439		rc = cond_read_node(p, &p->cond_list[i], fp);
    440		if (rc)
    441			goto err;
    442	}
    443	return 0;
    444err:
    445	cond_list_destroy(p);
    446	return rc;
    447}
    448
    449int cond_write_bool(void *vkey, void *datum, void *ptr)
    450{
    451	char *key = vkey;
    452	struct cond_bool_datum *booldatum = datum;
    453	struct policy_data *pd = ptr;
    454	void *fp = pd->fp;
    455	__le32 buf[3];
    456	u32 len;
    457	int rc;
    458
    459	len = strlen(key);
    460	buf[0] = cpu_to_le32(booldatum->value);
    461	buf[1] = cpu_to_le32(booldatum->state);
    462	buf[2] = cpu_to_le32(len);
    463	rc = put_entry(buf, sizeof(u32), 3, fp);
    464	if (rc)
    465		return rc;
    466	rc = put_entry(key, 1, len, fp);
    467	if (rc)
    468		return rc;
    469	return 0;
    470}
    471
    472/*
    473 * cond_write_cond_av_list doesn't write out the av_list nodes.
    474 * Instead it writes out the key/value pairs from the avtab. This
    475 * is necessary because there is no way to uniquely identifying rules
    476 * in the avtab so it is not possible to associate individual rules
    477 * in the avtab with a conditional without saving them as part of
    478 * the conditional. This means that the avtab with the conditional
    479 * rules will not be saved but will be rebuilt on policy load.
    480 */
    481static int cond_write_av_list(struct policydb *p,
    482			      struct cond_av_list *list, struct policy_file *fp)
    483{
    484	__le32 buf[1];
    485	u32 i;
    486	int rc;
    487
    488	buf[0] = cpu_to_le32(list->len);
    489	rc = put_entry(buf, sizeof(u32), 1, fp);
    490	if (rc)
    491		return rc;
    492
    493	for (i = 0; i < list->len; i++) {
    494		rc = avtab_write_item(p, list->nodes[i], fp);
    495		if (rc)
    496			return rc;
    497	}
    498
    499	return 0;
    500}
    501
    502static int cond_write_node(struct policydb *p, struct cond_node *node,
    503		    struct policy_file *fp)
    504{
    505	__le32 buf[2];
    506	int rc;
    507	u32 i;
    508
    509	buf[0] = cpu_to_le32(node->cur_state);
    510	rc = put_entry(buf, sizeof(u32), 1, fp);
    511	if (rc)
    512		return rc;
    513
    514	buf[0] = cpu_to_le32(node->expr.len);
    515	rc = put_entry(buf, sizeof(u32), 1, fp);
    516	if (rc)
    517		return rc;
    518
    519	for (i = 0; i < node->expr.len; i++) {
    520		buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
    521		buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
    522		rc = put_entry(buf, sizeof(u32), 2, fp);
    523		if (rc)
    524			return rc;
    525	}
    526
    527	rc = cond_write_av_list(p, &node->true_list, fp);
    528	if (rc)
    529		return rc;
    530	rc = cond_write_av_list(p, &node->false_list, fp);
    531	if (rc)
    532		return rc;
    533
    534	return 0;
    535}
    536
    537int cond_write_list(struct policydb *p, void *fp)
    538{
    539	u32 i;
    540	__le32 buf[1];
    541	int rc;
    542
    543	buf[0] = cpu_to_le32(p->cond_list_len);
    544	rc = put_entry(buf, sizeof(u32), 1, fp);
    545	if (rc)
    546		return rc;
    547
    548	for (i = 0; i < p->cond_list_len; i++) {
    549		rc = cond_write_node(p, &p->cond_list[i], fp);
    550		if (rc)
    551			return rc;
    552	}
    553
    554	return 0;
    555}
    556
    557void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
    558		struct extended_perms_decision *xpermd)
    559{
    560	struct avtab_node *node;
    561
    562	if (!ctab || !key || !xpermd)
    563		return;
    564
    565	for (node = avtab_search_node(ctab, key); node;
    566			node = avtab_search_node_next(node, key->specified)) {
    567		if (node->key.specified & AVTAB_ENABLED)
    568			services_compute_xperms_decision(xpermd, node);
    569	}
    570}
    571/* Determine whether additional permissions are granted by the conditional
    572 * av table, and if so, add them to the result
    573 */
    574void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
    575		struct av_decision *avd, struct extended_perms *xperms)
    576{
    577	struct avtab_node *node;
    578
    579	if (!ctab || !key || !avd)
    580		return;
    581
    582	for (node = avtab_search_node(ctab, key); node;
    583				node = avtab_search_node_next(node, key->specified)) {
    584		if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
    585		    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
    586			avd->allowed |= node->datum.u.data;
    587		if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
    588		    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
    589			/* Since a '0' in an auditdeny mask represents a
    590			 * permission we do NOT want to audit (dontaudit), we use
    591			 * the '&' operand to ensure that all '0's in the mask
    592			 * are retained (much unlike the allow and auditallow cases).
    593			 */
    594			avd->auditdeny &= node->datum.u.data;
    595		if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
    596		    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
    597			avd->auditallow |= node->datum.u.data;
    598		if (xperms && (node->key.specified & AVTAB_ENABLED) &&
    599				(node->key.specified & AVTAB_XPERMS))
    600			services_compute_xperms_drivers(xperms, node);
    601	}
    602}
    603
    604static int cond_dup_av_list(struct cond_av_list *new,
    605			struct cond_av_list *orig,
    606			struct avtab *avtab)
    607{
    608	u32 i;
    609
    610	memset(new, 0, sizeof(*new));
    611
    612	new->nodes = kcalloc(orig->len, sizeof(*new->nodes), GFP_KERNEL);
    613	if (!new->nodes)
    614		return -ENOMEM;
    615
    616	for (i = 0; i < orig->len; i++) {
    617		new->nodes[i] = avtab_insert_nonunique(avtab,
    618						       &orig->nodes[i]->key,
    619						       &orig->nodes[i]->datum);
    620		if (!new->nodes[i])
    621			return -ENOMEM;
    622		new->len++;
    623	}
    624
    625	return 0;
    626}
    627
    628static int duplicate_policydb_cond_list(struct policydb *newp,
    629					struct policydb *origp)
    630{
    631	int rc;
    632	u32 i;
    633
    634	rc = avtab_alloc_dup(&newp->te_cond_avtab, &origp->te_cond_avtab);
    635	if (rc)
    636		return rc;
    637
    638	newp->cond_list_len = 0;
    639	newp->cond_list = kcalloc(origp->cond_list_len,
    640				sizeof(*newp->cond_list),
    641				GFP_KERNEL);
    642	if (!newp->cond_list)
    643		goto error;
    644
    645	for (i = 0; i < origp->cond_list_len; i++) {
    646		struct cond_node *newn = &newp->cond_list[i];
    647		struct cond_node *orign = &origp->cond_list[i];
    648
    649		newp->cond_list_len++;
    650
    651		newn->cur_state = orign->cur_state;
    652		newn->expr.nodes = kmemdup(orign->expr.nodes,
    653				orign->expr.len * sizeof(*orign->expr.nodes),
    654				GFP_KERNEL);
    655		if (!newn->expr.nodes)
    656			goto error;
    657
    658		newn->expr.len = orign->expr.len;
    659
    660		rc = cond_dup_av_list(&newn->true_list, &orign->true_list,
    661				&newp->te_cond_avtab);
    662		if (rc)
    663			goto error;
    664
    665		rc = cond_dup_av_list(&newn->false_list, &orign->false_list,
    666				&newp->te_cond_avtab);
    667		if (rc)
    668			goto error;
    669	}
    670
    671	return 0;
    672
    673error:
    674	avtab_destroy(&newp->te_cond_avtab);
    675	cond_list_destroy(newp);
    676	return -ENOMEM;
    677}
    678
    679static int cond_bools_destroy(void *key, void *datum, void *args)
    680{
    681	/* key was not copied so no need to free here */
    682	kfree(datum);
    683	return 0;
    684}
    685
    686static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, void *args)
    687{
    688	struct cond_bool_datum *datum;
    689
    690	datum = kmemdup(orig->datum, sizeof(struct cond_bool_datum),
    691			GFP_KERNEL);
    692	if (!datum)
    693		return -ENOMEM;
    694
    695	new->key = orig->key; /* No need to copy, never modified */
    696	new->datum = datum;
    697	return 0;
    698}
    699
    700static int cond_bools_index(void *key, void *datum, void *args)
    701{
    702	struct cond_bool_datum *booldatum, **cond_bool_array;
    703
    704	booldatum = datum;
    705	cond_bool_array = args;
    706	cond_bool_array[booldatum->value - 1] = booldatum;
    707
    708	return 0;
    709}
    710
    711static int duplicate_policydb_bools(struct policydb *newdb,
    712				struct policydb *orig)
    713{
    714	struct cond_bool_datum **cond_bool_array;
    715	int rc;
    716
    717	cond_bool_array = kmalloc_array(orig->p_bools.nprim,
    718					sizeof(*orig->bool_val_to_struct),
    719					GFP_KERNEL);
    720	if (!cond_bool_array)
    721		return -ENOMEM;
    722
    723	rc = hashtab_duplicate(&newdb->p_bools.table, &orig->p_bools.table,
    724			cond_bools_copy, cond_bools_destroy, NULL);
    725	if (rc) {
    726		kfree(cond_bool_array);
    727		return -ENOMEM;
    728	}
    729
    730	hashtab_map(&newdb->p_bools.table, cond_bools_index, cond_bool_array);
    731	newdb->bool_val_to_struct = cond_bool_array;
    732
    733	newdb->p_bools.nprim = orig->p_bools.nprim;
    734
    735	return 0;
    736}
    737
    738void cond_policydb_destroy_dup(struct policydb *p)
    739{
    740	hashtab_map(&p->p_bools.table, cond_bools_destroy, NULL);
    741	hashtab_destroy(&p->p_bools.table);
    742	cond_policydb_destroy(p);
    743}
    744
    745int cond_policydb_dup(struct policydb *new, struct policydb *orig)
    746{
    747	cond_policydb_init(new);
    748
    749	if (duplicate_policydb_bools(new, orig))
    750		return -ENOMEM;
    751
    752	if (duplicate_policydb_cond_list(new, orig)) {
    753		cond_policydb_destroy_dup(new);
    754		return -ENOMEM;
    755	}
    756
    757	return 0;
    758}