162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Implementation of the policy database.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *	Support for enhanced MLS infrastructure.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *	Added conditional policy language extensions
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com>
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      Added support for the policy capability bitmap
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Update: Mellanox Techonologies
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *	Added Infiniband support
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Copyright (C) 2016 Mellanox Techonologies
2662306a36Sopenharmony_ci * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
2762306a36Sopenharmony_ci * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
2862306a36Sopenharmony_ci * Copyright (C) 2003 - 2004 Tresys Technology, LLC
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <linux/kernel.h>
3262306a36Sopenharmony_ci#include <linux/sched.h>
3362306a36Sopenharmony_ci#include <linux/slab.h>
3462306a36Sopenharmony_ci#include <linux/string.h>
3562306a36Sopenharmony_ci#include <linux/errno.h>
3662306a36Sopenharmony_ci#include <linux/audit.h>
3762306a36Sopenharmony_ci#include "security.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include "policydb.h"
4062306a36Sopenharmony_ci#include "conditional.h"
4162306a36Sopenharmony_ci#include "mls.h"
4262306a36Sopenharmony_ci#include "services.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DEBUG
4562306a36Sopenharmony_cistatic const char *const symtab_name[SYM_NUM] = {
4662306a36Sopenharmony_ci	"common prefixes",
4762306a36Sopenharmony_ci	"classes",
4862306a36Sopenharmony_ci	"roles",
4962306a36Sopenharmony_ci	"types",
5062306a36Sopenharmony_ci	"users",
5162306a36Sopenharmony_ci	"bools",
5262306a36Sopenharmony_ci	"levels",
5362306a36Sopenharmony_ci	"categories",
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct policydb_compat_info {
5862306a36Sopenharmony_ci	unsigned int version;
5962306a36Sopenharmony_ci	unsigned int sym_num;
6062306a36Sopenharmony_ci	unsigned int ocon_num;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* These need to be updated if SYM_NUM or OCON_NUM changes */
6462306a36Sopenharmony_cistatic const struct policydb_compat_info policydb_compat[] = {
6562306a36Sopenharmony_ci	{
6662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_BASE,
6762306a36Sopenharmony_ci		.sym_num	= SYM_NUM - 3,
6862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 3,
6962306a36Sopenharmony_ci	},
7062306a36Sopenharmony_ci	{
7162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_BOOL,
7262306a36Sopenharmony_ci		.sym_num	= SYM_NUM - 2,
7362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 3,
7462306a36Sopenharmony_ci	},
7562306a36Sopenharmony_ci	{
7662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_IPV6,
7762306a36Sopenharmony_ci		.sym_num	= SYM_NUM - 2,
7862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
7962306a36Sopenharmony_ci	},
8062306a36Sopenharmony_ci	{
8162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_NLCLASS,
8262306a36Sopenharmony_ci		.sym_num	= SYM_NUM - 2,
8362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
8462306a36Sopenharmony_ci	},
8562306a36Sopenharmony_ci	{
8662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_MLS,
8762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
8862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
8962306a36Sopenharmony_ci	},
9062306a36Sopenharmony_ci	{
9162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_AVTAB,
9262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
9362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
9462306a36Sopenharmony_ci	},
9562306a36Sopenharmony_ci	{
9662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_RANGETRANS,
9762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
9862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
9962306a36Sopenharmony_ci	},
10062306a36Sopenharmony_ci	{
10162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_POLCAP,
10262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
10362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci	{
10662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_PERMISSIVE,
10762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
10862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
10962306a36Sopenharmony_ci	},
11062306a36Sopenharmony_ci	{
11162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_BOUNDARY,
11262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
11362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
11462306a36Sopenharmony_ci	},
11562306a36Sopenharmony_ci	{
11662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_FILENAME_TRANS,
11762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
11862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
11962306a36Sopenharmony_ci	},
12062306a36Sopenharmony_ci	{
12162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_ROLETRANS,
12262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
12362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
12462306a36Sopenharmony_ci	},
12562306a36Sopenharmony_ci	{
12662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
12762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
12862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
12962306a36Sopenharmony_ci	},
13062306a36Sopenharmony_ci	{
13162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_DEFAULT_TYPE,
13262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
13362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
13462306a36Sopenharmony_ci	},
13562306a36Sopenharmony_ci	{
13662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_CONSTRAINT_NAMES,
13762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
13862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
13962306a36Sopenharmony_ci	},
14062306a36Sopenharmony_ci	{
14162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_XPERMS_IOCTL,
14262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
14362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM - 2,
14462306a36Sopenharmony_ci	},
14562306a36Sopenharmony_ci	{
14662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_INFINIBAND,
14762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
14862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM,
14962306a36Sopenharmony_ci	},
15062306a36Sopenharmony_ci	{
15162306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_GLBLUB,
15262306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
15362306a36Sopenharmony_ci		.ocon_num	= OCON_NUM,
15462306a36Sopenharmony_ci	},
15562306a36Sopenharmony_ci	{
15662306a36Sopenharmony_ci		.version	= POLICYDB_VERSION_COMP_FTRANS,
15762306a36Sopenharmony_ci		.sym_num	= SYM_NUM,
15862306a36Sopenharmony_ci		.ocon_num	= OCON_NUM,
15962306a36Sopenharmony_ci	},
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic const struct policydb_compat_info *policydb_lookup_compat(unsigned int version)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	unsigned int i;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) {
16762306a36Sopenharmony_ci		if (policydb_compat[i].version == version)
16862306a36Sopenharmony_ci			return &policydb_compat[i];
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return NULL;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * The following *_destroy functions are used to
17662306a36Sopenharmony_ci * free any memory allocated for each kind of
17762306a36Sopenharmony_ci * symbol data in the policy database.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int perm_destroy(void *key, void *datum, void *p)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	kfree(key);
18362306a36Sopenharmony_ci	kfree(datum);
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int common_destroy(void *key, void *datum, void *p)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct common_datum *comdatum;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	kfree(key);
19262306a36Sopenharmony_ci	if (datum) {
19362306a36Sopenharmony_ci		comdatum = datum;
19462306a36Sopenharmony_ci		hashtab_map(&comdatum->permissions.table, perm_destroy, NULL);
19562306a36Sopenharmony_ci		hashtab_destroy(&comdatum->permissions.table);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci	kfree(datum);
19862306a36Sopenharmony_ci	return 0;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void constraint_expr_destroy(struct constraint_expr *expr)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	if (expr) {
20462306a36Sopenharmony_ci		ebitmap_destroy(&expr->names);
20562306a36Sopenharmony_ci		if (expr->type_names) {
20662306a36Sopenharmony_ci			ebitmap_destroy(&expr->type_names->types);
20762306a36Sopenharmony_ci			ebitmap_destroy(&expr->type_names->negset);
20862306a36Sopenharmony_ci			kfree(expr->type_names);
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		kfree(expr);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic int cls_destroy(void *key, void *datum, void *p)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct class_datum *cladatum;
21762306a36Sopenharmony_ci	struct constraint_node *constraint, *ctemp;
21862306a36Sopenharmony_ci	struct constraint_expr *e, *etmp;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	kfree(key);
22162306a36Sopenharmony_ci	if (datum) {
22262306a36Sopenharmony_ci		cladatum = datum;
22362306a36Sopenharmony_ci		hashtab_map(&cladatum->permissions.table, perm_destroy, NULL);
22462306a36Sopenharmony_ci		hashtab_destroy(&cladatum->permissions.table);
22562306a36Sopenharmony_ci		constraint = cladatum->constraints;
22662306a36Sopenharmony_ci		while (constraint) {
22762306a36Sopenharmony_ci			e = constraint->expr;
22862306a36Sopenharmony_ci			while (e) {
22962306a36Sopenharmony_ci				etmp = e;
23062306a36Sopenharmony_ci				e = e->next;
23162306a36Sopenharmony_ci				constraint_expr_destroy(etmp);
23262306a36Sopenharmony_ci			}
23362306a36Sopenharmony_ci			ctemp = constraint;
23462306a36Sopenharmony_ci			constraint = constraint->next;
23562306a36Sopenharmony_ci			kfree(ctemp);
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		constraint = cladatum->validatetrans;
23962306a36Sopenharmony_ci		while (constraint) {
24062306a36Sopenharmony_ci			e = constraint->expr;
24162306a36Sopenharmony_ci			while (e) {
24262306a36Sopenharmony_ci				etmp = e;
24362306a36Sopenharmony_ci				e = e->next;
24462306a36Sopenharmony_ci				constraint_expr_destroy(etmp);
24562306a36Sopenharmony_ci			}
24662306a36Sopenharmony_ci			ctemp = constraint;
24762306a36Sopenharmony_ci			constraint = constraint->next;
24862306a36Sopenharmony_ci			kfree(ctemp);
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci		kfree(cladatum->comkey);
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	kfree(datum);
25362306a36Sopenharmony_ci	return 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int role_destroy(void *key, void *datum, void *p)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct role_datum *role;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	kfree(key);
26162306a36Sopenharmony_ci	if (datum) {
26262306a36Sopenharmony_ci		role = datum;
26362306a36Sopenharmony_ci		ebitmap_destroy(&role->dominates);
26462306a36Sopenharmony_ci		ebitmap_destroy(&role->types);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci	kfree(datum);
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int type_destroy(void *key, void *datum, void *p)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	kfree(key);
27362306a36Sopenharmony_ci	kfree(datum);
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int user_destroy(void *key, void *datum, void *p)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct user_datum *usrdatum;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	kfree(key);
28262306a36Sopenharmony_ci	if (datum) {
28362306a36Sopenharmony_ci		usrdatum = datum;
28462306a36Sopenharmony_ci		ebitmap_destroy(&usrdatum->roles);
28562306a36Sopenharmony_ci		ebitmap_destroy(&usrdatum->range.level[0].cat);
28662306a36Sopenharmony_ci		ebitmap_destroy(&usrdatum->range.level[1].cat);
28762306a36Sopenharmony_ci		ebitmap_destroy(&usrdatum->dfltlevel.cat);
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	kfree(datum);
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int sens_destroy(void *key, void *datum, void *p)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct level_datum *levdatum;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	kfree(key);
29862306a36Sopenharmony_ci	if (datum) {
29962306a36Sopenharmony_ci		levdatum = datum;
30062306a36Sopenharmony_ci		if (levdatum->level)
30162306a36Sopenharmony_ci			ebitmap_destroy(&levdatum->level->cat);
30262306a36Sopenharmony_ci		kfree(levdatum->level);
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	kfree(datum);
30562306a36Sopenharmony_ci	return 0;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int cat_destroy(void *key, void *datum, void *p)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	kfree(key);
31162306a36Sopenharmony_ci	kfree(datum);
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
31662306a36Sopenharmony_ci	common_destroy,
31762306a36Sopenharmony_ci	cls_destroy,
31862306a36Sopenharmony_ci	role_destroy,
31962306a36Sopenharmony_ci	type_destroy,
32062306a36Sopenharmony_ci	user_destroy,
32162306a36Sopenharmony_ci	cond_destroy_bool,
32262306a36Sopenharmony_ci	sens_destroy,
32362306a36Sopenharmony_ci	cat_destroy,
32462306a36Sopenharmony_ci};
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int filenametr_destroy(void *key, void *datum, void *p)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct filename_trans_key *ft = key;
32962306a36Sopenharmony_ci	struct filename_trans_datum *next, *d = datum;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	kfree(ft->name);
33262306a36Sopenharmony_ci	kfree(key);
33362306a36Sopenharmony_ci	do {
33462306a36Sopenharmony_ci		ebitmap_destroy(&d->stypes);
33562306a36Sopenharmony_ci		next = d->next;
33662306a36Sopenharmony_ci		kfree(d);
33762306a36Sopenharmony_ci		d = next;
33862306a36Sopenharmony_ci	} while (unlikely(d));
33962306a36Sopenharmony_ci	cond_resched();
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int range_tr_destroy(void *key, void *datum, void *p)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct mls_range *rt = datum;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	kfree(key);
34862306a36Sopenharmony_ci	ebitmap_destroy(&rt->level[0].cat);
34962306a36Sopenharmony_ci	ebitmap_destroy(&rt->level[1].cat);
35062306a36Sopenharmony_ci	kfree(datum);
35162306a36Sopenharmony_ci	cond_resched();
35262306a36Sopenharmony_ci	return 0;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int role_tr_destroy(void *key, void *datum, void *p)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	kfree(key);
35862306a36Sopenharmony_ci	kfree(datum);
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void ocontext_destroy(struct ocontext *c, unsigned int i)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	if (!c)
36562306a36Sopenharmony_ci		return;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	context_destroy(&c->context[0]);
36862306a36Sopenharmony_ci	context_destroy(&c->context[1]);
36962306a36Sopenharmony_ci	if (i == OCON_ISID || i == OCON_FS ||
37062306a36Sopenharmony_ci	    i == OCON_NETIF || i == OCON_FSUSE)
37162306a36Sopenharmony_ci		kfree(c->u.name);
37262306a36Sopenharmony_ci	kfree(c);
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/*
37662306a36Sopenharmony_ci * Initialize the role table.
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_cistatic int roles_init(struct policydb *p)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	char *key = NULL;
38162306a36Sopenharmony_ci	int rc;
38262306a36Sopenharmony_ci	struct role_datum *role;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	role = kzalloc(sizeof(*role), GFP_KERNEL);
38562306a36Sopenharmony_ci	if (!role)
38662306a36Sopenharmony_ci		return -ENOMEM;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	rc = -EINVAL;
38962306a36Sopenharmony_ci	role->value = ++p->p_roles.nprim;
39062306a36Sopenharmony_ci	if (role->value != OBJECT_R_VAL)
39162306a36Sopenharmony_ci		goto out;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	rc = -ENOMEM;
39462306a36Sopenharmony_ci	key = kstrdup(OBJECT_R, GFP_KERNEL);
39562306a36Sopenharmony_ci	if (!key)
39662306a36Sopenharmony_ci		goto out;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	rc = symtab_insert(&p->p_roles, key, role);
39962306a36Sopenharmony_ci	if (rc)
40062306a36Sopenharmony_ci		goto out;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ciout:
40462306a36Sopenharmony_ci	kfree(key);
40562306a36Sopenharmony_ci	kfree(role);
40662306a36Sopenharmony_ci	return rc;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic u32 filenametr_hash(const void *k)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	const struct filename_trans_key *ft = k;
41262306a36Sopenharmony_ci	unsigned long hash;
41362306a36Sopenharmony_ci	unsigned int byte_num;
41462306a36Sopenharmony_ci	unsigned char focus;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	hash = ft->ttype ^ ft->tclass;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	byte_num = 0;
41962306a36Sopenharmony_ci	while ((focus = ft->name[byte_num++]))
42062306a36Sopenharmony_ci		hash = partial_name_hash(focus, hash);
42162306a36Sopenharmony_ci	return hash;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int filenametr_cmp(const void *k1, const void *k2)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	const struct filename_trans_key *ft1 = k1;
42762306a36Sopenharmony_ci	const struct filename_trans_key *ft2 = k2;
42862306a36Sopenharmony_ci	int v;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	v = ft1->ttype - ft2->ttype;
43162306a36Sopenharmony_ci	if (v)
43262306a36Sopenharmony_ci		return v;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	v = ft1->tclass - ft2->tclass;
43562306a36Sopenharmony_ci	if (v)
43662306a36Sopenharmony_ci		return v;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return strcmp(ft1->name, ft2->name);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic const struct hashtab_key_params filenametr_key_params = {
44362306a36Sopenharmony_ci	.hash = filenametr_hash,
44462306a36Sopenharmony_ci	.cmp = filenametr_cmp,
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistruct filename_trans_datum *policydb_filenametr_search(
44862306a36Sopenharmony_ci	struct policydb *p, struct filename_trans_key *key)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	return hashtab_search(&p->filename_trans, key, filenametr_key_params);
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic u32 rangetr_hash(const void *k)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	const struct range_trans *key = k;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	return key->source_type + (key->target_type << 3) +
45862306a36Sopenharmony_ci		(key->target_class << 5);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int rangetr_cmp(const void *k1, const void *k2)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	const struct range_trans *key1 = k1, *key2 = k2;
46462306a36Sopenharmony_ci	int v;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	v = key1->source_type - key2->source_type;
46762306a36Sopenharmony_ci	if (v)
46862306a36Sopenharmony_ci		return v;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	v = key1->target_type - key2->target_type;
47162306a36Sopenharmony_ci	if (v)
47262306a36Sopenharmony_ci		return v;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	v = key1->target_class - key2->target_class;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return v;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic const struct hashtab_key_params rangetr_key_params = {
48062306a36Sopenharmony_ci	.hash = rangetr_hash,
48162306a36Sopenharmony_ci	.cmp = rangetr_cmp,
48262306a36Sopenharmony_ci};
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistruct mls_range *policydb_rangetr_search(struct policydb *p,
48562306a36Sopenharmony_ci					  struct range_trans *key)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	return hashtab_search(&p->range_tr, key, rangetr_key_params);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic u32 role_trans_hash(const void *k)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	const struct role_trans_key *key = k;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return key->role + (key->type << 3) + (key->tclass << 5);
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic int role_trans_cmp(const void *k1, const void *k2)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	const struct role_trans_key *key1 = k1, *key2 = k2;
50062306a36Sopenharmony_ci	int v;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	v = key1->role - key2->role;
50362306a36Sopenharmony_ci	if (v)
50462306a36Sopenharmony_ci		return v;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	v = key1->type - key2->type;
50762306a36Sopenharmony_ci	if (v)
50862306a36Sopenharmony_ci		return v;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	return key1->tclass - key2->tclass;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic const struct hashtab_key_params roletr_key_params = {
51462306a36Sopenharmony_ci	.hash = role_trans_hash,
51562306a36Sopenharmony_ci	.cmp = role_trans_cmp,
51662306a36Sopenharmony_ci};
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistruct role_trans_datum *policydb_roletr_search(struct policydb *p,
51962306a36Sopenharmony_ci						struct role_trans_key *key)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	return hashtab_search(&p->role_tr, key, roletr_key_params);
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci/*
52562306a36Sopenharmony_ci * Initialize a policy database structure.
52662306a36Sopenharmony_ci */
52762306a36Sopenharmony_cistatic void policydb_init(struct policydb *p)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	memset(p, 0, sizeof(*p));
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	avtab_init(&p->te_avtab);
53262306a36Sopenharmony_ci	cond_policydb_init(p);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ebitmap_init(&p->filename_trans_ttypes);
53562306a36Sopenharmony_ci	ebitmap_init(&p->policycaps);
53662306a36Sopenharmony_ci	ebitmap_init(&p->permissive_map);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/*
54062306a36Sopenharmony_ci * The following *_index functions are used to
54162306a36Sopenharmony_ci * define the val_to_name and val_to_struct arrays
54262306a36Sopenharmony_ci * in a policy database structure.  The val_to_name
54362306a36Sopenharmony_ci * arrays are used when converting security context
54462306a36Sopenharmony_ci * structures into string representations.  The
54562306a36Sopenharmony_ci * val_to_struct arrays are used when the attributes
54662306a36Sopenharmony_ci * of a class, role, or user are needed.
54762306a36Sopenharmony_ci */
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int common_index(void *key, void *datum, void *datap)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct policydb *p;
55262306a36Sopenharmony_ci	struct common_datum *comdatum;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	comdatum = datum;
55562306a36Sopenharmony_ci	p = datap;
55662306a36Sopenharmony_ci	if (!comdatum->value || comdatum->value > p->p_commons.nprim)
55762306a36Sopenharmony_ci		return -EINVAL;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int class_index(void *key, void *datum, void *datap)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct policydb *p;
56762306a36Sopenharmony_ci	struct class_datum *cladatum;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	cladatum = datum;
57062306a36Sopenharmony_ci	p = datap;
57162306a36Sopenharmony_ci	if (!cladatum->value || cladatum->value > p->p_classes.nprim)
57262306a36Sopenharmony_ci		return -EINVAL;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
57562306a36Sopenharmony_ci	p->class_val_to_struct[cladatum->value - 1] = cladatum;
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic int role_index(void *key, void *datum, void *datap)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct policydb *p;
58262306a36Sopenharmony_ci	struct role_datum *role;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	role = datum;
58562306a36Sopenharmony_ci	p = datap;
58662306a36Sopenharmony_ci	if (!role->value
58762306a36Sopenharmony_ci	    || role->value > p->p_roles.nprim
58862306a36Sopenharmony_ci	    || role->bounds > p->p_roles.nprim)
58962306a36Sopenharmony_ci		return -EINVAL;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
59262306a36Sopenharmony_ci	p->role_val_to_struct[role->value - 1] = role;
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int type_index(void *key, void *datum, void *datap)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct policydb *p;
59962306a36Sopenharmony_ci	struct type_datum *typdatum;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	typdatum = datum;
60262306a36Sopenharmony_ci	p = datap;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (typdatum->primary) {
60562306a36Sopenharmony_ci		if (!typdatum->value
60662306a36Sopenharmony_ci		    || typdatum->value > p->p_types.nprim
60762306a36Sopenharmony_ci		    || typdatum->bounds > p->p_types.nprim)
60862306a36Sopenharmony_ci			return -EINVAL;
60962306a36Sopenharmony_ci		p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
61062306a36Sopenharmony_ci		p->type_val_to_struct[typdatum->value - 1] = typdatum;
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	return 0;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int user_index(void *key, void *datum, void *datap)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct policydb *p;
61962306a36Sopenharmony_ci	struct user_datum *usrdatum;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	usrdatum = datum;
62262306a36Sopenharmony_ci	p = datap;
62362306a36Sopenharmony_ci	if (!usrdatum->value
62462306a36Sopenharmony_ci	    || usrdatum->value > p->p_users.nprim
62562306a36Sopenharmony_ci	    || usrdatum->bounds > p->p_users.nprim)
62662306a36Sopenharmony_ci		return -EINVAL;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
62962306a36Sopenharmony_ci	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int sens_index(void *key, void *datum, void *datap)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct policydb *p;
63662306a36Sopenharmony_ci	struct level_datum *levdatum;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	levdatum = datum;
63962306a36Sopenharmony_ci	p = datap;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (!levdatum->isalias) {
64262306a36Sopenharmony_ci		if (!levdatum->level->sens ||
64362306a36Sopenharmony_ci		    levdatum->level->sens > p->p_levels.nprim)
64462306a36Sopenharmony_ci			return -EINVAL;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return 0;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic int cat_index(void *key, void *datum, void *datap)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct policydb *p;
65562306a36Sopenharmony_ci	struct cat_datum *catdatum;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	catdatum = datum;
65862306a36Sopenharmony_ci	p = datap;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (!catdatum->isalias) {
66162306a36Sopenharmony_ci		if (!catdatum->value || catdatum->value > p->p_cats.nprim)
66262306a36Sopenharmony_ci			return -EINVAL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return 0;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
67162306a36Sopenharmony_ci	common_index,
67262306a36Sopenharmony_ci	class_index,
67362306a36Sopenharmony_ci	role_index,
67462306a36Sopenharmony_ci	type_index,
67562306a36Sopenharmony_ci	user_index,
67662306a36Sopenharmony_ci	cond_index_bool,
67762306a36Sopenharmony_ci	sens_index,
67862306a36Sopenharmony_ci	cat_index,
67962306a36Sopenharmony_ci};
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DEBUG
68262306a36Sopenharmony_cistatic void hash_eval(struct hashtab *h, const char *hash_name)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct hashtab_info info;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	hashtab_stat(h, &info);
68762306a36Sopenharmony_ci	pr_debug("SELinux: %s:  %d entries and %d/%d buckets used, longest chain length %d\n",
68862306a36Sopenharmony_ci		 hash_name, h->nel, info.slots_used, h->size,
68962306a36Sopenharmony_ci		 info.max_chain_len);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic void symtab_hash_eval(struct symtab *s)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int i;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	for (i = 0; i < SYM_NUM; i++)
69762306a36Sopenharmony_ci		hash_eval(&s[i].table, symtab_name[i]);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci#else
70162306a36Sopenharmony_cistatic inline void hash_eval(struct hashtab *h, const char *hash_name)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_cistatic inline void symtab_hash_eval(struct symtab *s)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci#endif /* CONFIG_SECURITY_SELINUX_DEBUG */
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci/*
71062306a36Sopenharmony_ci * Define the other val_to_name and val_to_struct arrays
71162306a36Sopenharmony_ci * in a policy database structure.
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * Caller must clean up on failure.
71462306a36Sopenharmony_ci */
71562306a36Sopenharmony_cistatic int policydb_index(struct policydb *p)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	int i, rc;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (p->mls_enabled)
72062306a36Sopenharmony_ci		pr_debug("SELinux:  %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
72162306a36Sopenharmony_ci			 p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
72262306a36Sopenharmony_ci			 p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
72362306a36Sopenharmony_ci	else
72462306a36Sopenharmony_ci		pr_debug("SELinux:  %d users, %d roles, %d types, %d bools\n",
72562306a36Sopenharmony_ci			 p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
72662306a36Sopenharmony_ci			 p->p_bools.nprim);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	pr_debug("SELinux:  %d classes, %d rules\n",
72962306a36Sopenharmony_ci		 p->p_classes.nprim, p->te_avtab.nel);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	avtab_hash_eval(&p->te_avtab, "rules");
73262306a36Sopenharmony_ci	symtab_hash_eval(p->symtab);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	p->class_val_to_struct = kcalloc(p->p_classes.nprim,
73562306a36Sopenharmony_ci					 sizeof(*p->class_val_to_struct),
73662306a36Sopenharmony_ci					 GFP_KERNEL);
73762306a36Sopenharmony_ci	if (!p->class_val_to_struct)
73862306a36Sopenharmony_ci		return -ENOMEM;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	p->role_val_to_struct = kcalloc(p->p_roles.nprim,
74162306a36Sopenharmony_ci					sizeof(*p->role_val_to_struct),
74262306a36Sopenharmony_ci					GFP_KERNEL);
74362306a36Sopenharmony_ci	if (!p->role_val_to_struct)
74462306a36Sopenharmony_ci		return -ENOMEM;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	p->user_val_to_struct = kcalloc(p->p_users.nprim,
74762306a36Sopenharmony_ci					sizeof(*p->user_val_to_struct),
74862306a36Sopenharmony_ci					GFP_KERNEL);
74962306a36Sopenharmony_ci	if (!p->user_val_to_struct)
75062306a36Sopenharmony_ci		return -ENOMEM;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	p->type_val_to_struct = kvcalloc(p->p_types.nprim,
75362306a36Sopenharmony_ci					 sizeof(*p->type_val_to_struct),
75462306a36Sopenharmony_ci					 GFP_KERNEL);
75562306a36Sopenharmony_ci	if (!p->type_val_to_struct)
75662306a36Sopenharmony_ci		return -ENOMEM;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	rc = cond_init_bool_indexes(p);
75962306a36Sopenharmony_ci	if (rc)
76062306a36Sopenharmony_ci		goto out;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	for (i = 0; i < SYM_NUM; i++) {
76362306a36Sopenharmony_ci		p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
76462306a36Sopenharmony_ci						 sizeof(char *),
76562306a36Sopenharmony_ci						 GFP_KERNEL);
76662306a36Sopenharmony_ci		if (!p->sym_val_to_name[i])
76762306a36Sopenharmony_ci			return -ENOMEM;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		rc = hashtab_map(&p->symtab[i].table, index_f[i], p);
77062306a36Sopenharmony_ci		if (rc)
77162306a36Sopenharmony_ci			goto out;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci	rc = 0;
77462306a36Sopenharmony_ciout:
77562306a36Sopenharmony_ci	return rc;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/*
77962306a36Sopenharmony_ci * Free any memory allocated by a policy database structure.
78062306a36Sopenharmony_ci */
78162306a36Sopenharmony_civoid policydb_destroy(struct policydb *p)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct ocontext *c, *ctmp;
78462306a36Sopenharmony_ci	struct genfs *g, *gtmp;
78562306a36Sopenharmony_ci	u32 i;
78662306a36Sopenharmony_ci	struct role_allow *ra, *lra = NULL;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	for (i = 0; i < SYM_NUM; i++) {
78962306a36Sopenharmony_ci		cond_resched();
79062306a36Sopenharmony_ci		hashtab_map(&p->symtab[i].table, destroy_f[i], NULL);
79162306a36Sopenharmony_ci		hashtab_destroy(&p->symtab[i].table);
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	for (i = 0; i < SYM_NUM; i++)
79562306a36Sopenharmony_ci		kvfree(p->sym_val_to_name[i]);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	kfree(p->class_val_to_struct);
79862306a36Sopenharmony_ci	kfree(p->role_val_to_struct);
79962306a36Sopenharmony_ci	kfree(p->user_val_to_struct);
80062306a36Sopenharmony_ci	kvfree(p->type_val_to_struct);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	avtab_destroy(&p->te_avtab);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	for (i = 0; i < OCON_NUM; i++) {
80562306a36Sopenharmony_ci		cond_resched();
80662306a36Sopenharmony_ci		c = p->ocontexts[i];
80762306a36Sopenharmony_ci		while (c) {
80862306a36Sopenharmony_ci			ctmp = c;
80962306a36Sopenharmony_ci			c = c->next;
81062306a36Sopenharmony_ci			ocontext_destroy(ctmp, i);
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci		p->ocontexts[i] = NULL;
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	g = p->genfs;
81662306a36Sopenharmony_ci	while (g) {
81762306a36Sopenharmony_ci		cond_resched();
81862306a36Sopenharmony_ci		kfree(g->fstype);
81962306a36Sopenharmony_ci		c = g->head;
82062306a36Sopenharmony_ci		while (c) {
82162306a36Sopenharmony_ci			ctmp = c;
82262306a36Sopenharmony_ci			c = c->next;
82362306a36Sopenharmony_ci			ocontext_destroy(ctmp, OCON_FSUSE);
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci		gtmp = g;
82662306a36Sopenharmony_ci		g = g->next;
82762306a36Sopenharmony_ci		kfree(gtmp);
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci	p->genfs = NULL;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	cond_policydb_destroy(p);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	hashtab_map(&p->role_tr, role_tr_destroy, NULL);
83462306a36Sopenharmony_ci	hashtab_destroy(&p->role_tr);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	for (ra = p->role_allow; ra; ra = ra->next) {
83762306a36Sopenharmony_ci		cond_resched();
83862306a36Sopenharmony_ci		kfree(lra);
83962306a36Sopenharmony_ci		lra = ra;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	kfree(lra);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	hashtab_map(&p->filename_trans, filenametr_destroy, NULL);
84462306a36Sopenharmony_ci	hashtab_destroy(&p->filename_trans);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	hashtab_map(&p->range_tr, range_tr_destroy, NULL);
84762306a36Sopenharmony_ci	hashtab_destroy(&p->range_tr);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (p->type_attr_map_array) {
85062306a36Sopenharmony_ci		for (i = 0; i < p->p_types.nprim; i++)
85162306a36Sopenharmony_ci			ebitmap_destroy(&p->type_attr_map_array[i]);
85262306a36Sopenharmony_ci		kvfree(p->type_attr_map_array);
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	ebitmap_destroy(&p->filename_trans_ttypes);
85662306a36Sopenharmony_ci	ebitmap_destroy(&p->policycaps);
85762306a36Sopenharmony_ci	ebitmap_destroy(&p->permissive_map);
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/*
86162306a36Sopenharmony_ci * Load the initial SIDs specified in a policy database
86262306a36Sopenharmony_ci * structure into a SID table.
86362306a36Sopenharmony_ci */
86462306a36Sopenharmony_ciint policydb_load_isids(struct policydb *p, struct sidtab *s)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct ocontext *head, *c;
86762306a36Sopenharmony_ci	int rc;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	rc = sidtab_init(s);
87062306a36Sopenharmony_ci	if (rc) {
87162306a36Sopenharmony_ci		pr_err("SELinux:  out of memory on SID table init\n");
87262306a36Sopenharmony_ci		return rc;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	head = p->ocontexts[OCON_ISID];
87662306a36Sopenharmony_ci	for (c = head; c; c = c->next) {
87762306a36Sopenharmony_ci		u32 sid = c->sid[0];
87862306a36Sopenharmony_ci		const char *name = security_get_initial_sid_context(sid);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		if (sid == SECSID_NULL) {
88162306a36Sopenharmony_ci			pr_err("SELinux:  SID 0 was assigned a context.\n");
88262306a36Sopenharmony_ci			sidtab_destroy(s);
88362306a36Sopenharmony_ci			return -EINVAL;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		/* Ignore initial SIDs unused by this kernel. */
88762306a36Sopenharmony_ci		if (!name)
88862306a36Sopenharmony_ci			continue;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		rc = sidtab_set_initial(s, sid, &c->context[0]);
89162306a36Sopenharmony_ci		if (rc) {
89262306a36Sopenharmony_ci			pr_err("SELinux:  unable to load initial SID %s.\n",
89362306a36Sopenharmony_ci			       name);
89462306a36Sopenharmony_ci			sidtab_destroy(s);
89562306a36Sopenharmony_ci			return rc;
89662306a36Sopenharmony_ci		}
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci	return 0;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ciint policydb_class_isvalid(struct policydb *p, unsigned int class)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	if (!class || class > p->p_classes.nprim)
90462306a36Sopenharmony_ci		return 0;
90562306a36Sopenharmony_ci	return 1;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ciint policydb_role_isvalid(struct policydb *p, unsigned int role)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	if (!role || role > p->p_roles.nprim)
91162306a36Sopenharmony_ci		return 0;
91262306a36Sopenharmony_ci	return 1;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ciint policydb_type_isvalid(struct policydb *p, unsigned int type)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	if (!type || type > p->p_types.nprim)
91862306a36Sopenharmony_ci		return 0;
91962306a36Sopenharmony_ci	return 1;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci/*
92362306a36Sopenharmony_ci * Return 1 if the fields in the security context
92462306a36Sopenharmony_ci * structure `c' are valid.  Return 0 otherwise.
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_ciint policydb_context_isvalid(struct policydb *p, struct context *c)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct role_datum *role;
92962306a36Sopenharmony_ci	struct user_datum *usrdatum;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (!c->role || c->role > p->p_roles.nprim)
93262306a36Sopenharmony_ci		return 0;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (!c->user || c->user > p->p_users.nprim)
93562306a36Sopenharmony_ci		return 0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (!c->type || c->type > p->p_types.nprim)
93862306a36Sopenharmony_ci		return 0;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	if (c->role != OBJECT_R_VAL) {
94162306a36Sopenharmony_ci		/*
94262306a36Sopenharmony_ci		 * Role must be authorized for the type.
94362306a36Sopenharmony_ci		 */
94462306a36Sopenharmony_ci		role = p->role_val_to_struct[c->role - 1];
94562306a36Sopenharmony_ci		if (!role || !ebitmap_get_bit(&role->types, c->type - 1))
94662306a36Sopenharmony_ci			/* role may not be associated with type */
94762306a36Sopenharmony_ci			return 0;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		/*
95062306a36Sopenharmony_ci		 * User must be authorized for the role.
95162306a36Sopenharmony_ci		 */
95262306a36Sopenharmony_ci		usrdatum = p->user_val_to_struct[c->user - 1];
95362306a36Sopenharmony_ci		if (!usrdatum)
95462306a36Sopenharmony_ci			return 0;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))
95762306a36Sopenharmony_ci			/* user may not be associated with role */
95862306a36Sopenharmony_ci			return 0;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (!mls_context_isvalid(p, c))
96262306a36Sopenharmony_ci		return 0;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return 1;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci/*
96862306a36Sopenharmony_ci * Read a MLS range structure from a policydb binary
96962306a36Sopenharmony_ci * representation file.
97062306a36Sopenharmony_ci */
97162306a36Sopenharmony_cistatic int mls_read_range_helper(struct mls_range *r, void *fp)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	__le32 buf[2];
97462306a36Sopenharmony_ci	u32 items;
97562306a36Sopenharmony_ci	int rc;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
97862306a36Sopenharmony_ci	if (rc)
97962306a36Sopenharmony_ci		goto out;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	rc = -EINVAL;
98262306a36Sopenharmony_ci	items = le32_to_cpu(buf[0]);
98362306a36Sopenharmony_ci	if (items > ARRAY_SIZE(buf)) {
98462306a36Sopenharmony_ci		pr_err("SELinux: mls:  range overflow\n");
98562306a36Sopenharmony_ci		goto out;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32) * items);
98962306a36Sopenharmony_ci	if (rc) {
99062306a36Sopenharmony_ci		pr_err("SELinux: mls:  truncated range\n");
99162306a36Sopenharmony_ci		goto out;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	r->level[0].sens = le32_to_cpu(buf[0]);
99562306a36Sopenharmony_ci	if (items > 1)
99662306a36Sopenharmony_ci		r->level[1].sens = le32_to_cpu(buf[1]);
99762306a36Sopenharmony_ci	else
99862306a36Sopenharmony_ci		r->level[1].sens = r->level[0].sens;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	rc = ebitmap_read(&r->level[0].cat, fp);
100162306a36Sopenharmony_ci	if (rc) {
100262306a36Sopenharmony_ci		pr_err("SELinux: mls:  error reading low categories\n");
100362306a36Sopenharmony_ci		goto out;
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci	if (items > 1) {
100662306a36Sopenharmony_ci		rc = ebitmap_read(&r->level[1].cat, fp);
100762306a36Sopenharmony_ci		if (rc) {
100862306a36Sopenharmony_ci			pr_err("SELinux: mls:  error reading high categories\n");
100962306a36Sopenharmony_ci			goto bad_high;
101062306a36Sopenharmony_ci		}
101162306a36Sopenharmony_ci	} else {
101262306a36Sopenharmony_ci		rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
101362306a36Sopenharmony_ci		if (rc) {
101462306a36Sopenharmony_ci			pr_err("SELinux: mls:  out of memory\n");
101562306a36Sopenharmony_ci			goto bad_high;
101662306a36Sopenharmony_ci		}
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return 0;
102062306a36Sopenharmony_cibad_high:
102162306a36Sopenharmony_ci	ebitmap_destroy(&r->level[0].cat);
102262306a36Sopenharmony_ciout:
102362306a36Sopenharmony_ci	return rc;
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci/*
102762306a36Sopenharmony_ci * Read and validate a security context structure
102862306a36Sopenharmony_ci * from a policydb binary representation file.
102962306a36Sopenharmony_ci */
103062306a36Sopenharmony_cistatic int context_read_and_validate(struct context *c,
103162306a36Sopenharmony_ci				     struct policydb *p,
103262306a36Sopenharmony_ci				     void *fp)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	__le32 buf[3];
103562306a36Sopenharmony_ci	int rc;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
103862306a36Sopenharmony_ci	if (rc) {
103962306a36Sopenharmony_ci		pr_err("SELinux: context truncated\n");
104062306a36Sopenharmony_ci		goto out;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci	c->user = le32_to_cpu(buf[0]);
104362306a36Sopenharmony_ci	c->role = le32_to_cpu(buf[1]);
104462306a36Sopenharmony_ci	c->type = le32_to_cpu(buf[2]);
104562306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_MLS) {
104662306a36Sopenharmony_ci		rc = mls_read_range_helper(&c->range, fp);
104762306a36Sopenharmony_ci		if (rc) {
104862306a36Sopenharmony_ci			pr_err("SELinux: error reading MLS range of context\n");
104962306a36Sopenharmony_ci			goto out;
105062306a36Sopenharmony_ci		}
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	rc = -EINVAL;
105462306a36Sopenharmony_ci	if (!policydb_context_isvalid(p, c)) {
105562306a36Sopenharmony_ci		pr_err("SELinux:  invalid security context\n");
105662306a36Sopenharmony_ci		context_destroy(c);
105762306a36Sopenharmony_ci		goto out;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci	rc = 0;
106062306a36Sopenharmony_ciout:
106162306a36Sopenharmony_ci	return rc;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci/*
106562306a36Sopenharmony_ci * The following *_read functions are used to
106662306a36Sopenharmony_ci * read the symbol data from a policy database
106762306a36Sopenharmony_ci * binary representation file.
106862306a36Sopenharmony_ci */
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic int str_read(char **strp, gfp_t flags, void *fp, u32 len)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	int rc;
107362306a36Sopenharmony_ci	char *str;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	if ((len == 0) || (len == (u32)-1))
107662306a36Sopenharmony_ci		return -EINVAL;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	str = kmalloc(len + 1, flags | __GFP_NOWARN);
107962306a36Sopenharmony_ci	if (!str)
108062306a36Sopenharmony_ci		return -ENOMEM;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	rc = next_entry(str, fp, len);
108362306a36Sopenharmony_ci	if (rc) {
108462306a36Sopenharmony_ci		kfree(str);
108562306a36Sopenharmony_ci		return rc;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	str[len] = '\0';
108962306a36Sopenharmony_ci	*strp = str;
109062306a36Sopenharmony_ci	return 0;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int perm_read(struct policydb *p, struct symtab *s, void *fp)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	char *key = NULL;
109662306a36Sopenharmony_ci	struct perm_datum *perdatum;
109762306a36Sopenharmony_ci	int rc;
109862306a36Sopenharmony_ci	__le32 buf[2];
109962306a36Sopenharmony_ci	u32 len;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
110262306a36Sopenharmony_ci	if (!perdatum)
110362306a36Sopenharmony_ci		return -ENOMEM;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
110662306a36Sopenharmony_ci	if (rc)
110762306a36Sopenharmony_ci		goto bad;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
111062306a36Sopenharmony_ci	perdatum->value = le32_to_cpu(buf[1]);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
111362306a36Sopenharmony_ci	if (rc)
111462306a36Sopenharmony_ci		goto bad;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	rc = symtab_insert(s, key, perdatum);
111762306a36Sopenharmony_ci	if (rc)
111862306a36Sopenharmony_ci		goto bad;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	return 0;
112162306a36Sopenharmony_cibad:
112262306a36Sopenharmony_ci	perm_destroy(key, perdatum, NULL);
112362306a36Sopenharmony_ci	return rc;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic int common_read(struct policydb *p, struct symtab *s, void *fp)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	char *key = NULL;
112962306a36Sopenharmony_ci	struct common_datum *comdatum;
113062306a36Sopenharmony_ci	__le32 buf[4];
113162306a36Sopenharmony_ci	u32 i, len, nel;
113262306a36Sopenharmony_ci	int rc;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
113562306a36Sopenharmony_ci	if (!comdatum)
113662306a36Sopenharmony_ci		return -ENOMEM;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
113962306a36Sopenharmony_ci	if (rc)
114062306a36Sopenharmony_ci		goto bad;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
114362306a36Sopenharmony_ci	comdatum->value = le32_to_cpu(buf[1]);
114462306a36Sopenharmony_ci	nel = le32_to_cpu(buf[3]);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	rc = symtab_init(&comdatum->permissions, nel);
114762306a36Sopenharmony_ci	if (rc)
114862306a36Sopenharmony_ci		goto bad;
114962306a36Sopenharmony_ci	comdatum->permissions.nprim = le32_to_cpu(buf[2]);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
115262306a36Sopenharmony_ci	if (rc)
115362306a36Sopenharmony_ci		goto bad;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
115662306a36Sopenharmony_ci		rc = perm_read(p, &comdatum->permissions, fp);
115762306a36Sopenharmony_ci		if (rc)
115862306a36Sopenharmony_ci			goto bad;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	rc = symtab_insert(s, key, comdatum);
116262306a36Sopenharmony_ci	if (rc)
116362306a36Sopenharmony_ci		goto bad;
116462306a36Sopenharmony_ci	return 0;
116562306a36Sopenharmony_cibad:
116662306a36Sopenharmony_ci	common_destroy(key, comdatum, NULL);
116762306a36Sopenharmony_ci	return rc;
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistatic void type_set_init(struct type_set *t)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	ebitmap_init(&t->types);
117362306a36Sopenharmony_ci	ebitmap_init(&t->negset);
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic int type_set_read(struct type_set *t, void *fp)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	__le32 buf[1];
117962306a36Sopenharmony_ci	int rc;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (ebitmap_read(&t->types, fp))
118262306a36Sopenharmony_ci		return -EINVAL;
118362306a36Sopenharmony_ci	if (ebitmap_read(&t->negset, fp))
118462306a36Sopenharmony_ci		return -EINVAL;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
118762306a36Sopenharmony_ci	if (rc < 0)
118862306a36Sopenharmony_ci		return -EINVAL;
118962306a36Sopenharmony_ci	t->flags = le32_to_cpu(buf[0]);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return 0;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic int read_cons_helper(struct policydb *p,
119662306a36Sopenharmony_ci				struct constraint_node **nodep,
119762306a36Sopenharmony_ci				u32 ncons, int allowxtarget, void *fp)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct constraint_node *c, *lc;
120062306a36Sopenharmony_ci	struct constraint_expr *e, *le;
120162306a36Sopenharmony_ci	__le32 buf[3];
120262306a36Sopenharmony_ci	u32 i, j, nexpr;
120362306a36Sopenharmony_ci	int rc, depth;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	lc = NULL;
120662306a36Sopenharmony_ci	for (i = 0; i < ncons; i++) {
120762306a36Sopenharmony_ci		c = kzalloc(sizeof(*c), GFP_KERNEL);
120862306a36Sopenharmony_ci		if (!c)
120962306a36Sopenharmony_ci			return -ENOMEM;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci		if (lc)
121262306a36Sopenharmony_ci			lc->next = c;
121362306a36Sopenharmony_ci		else
121462306a36Sopenharmony_ci			*nodep = c;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci		rc = next_entry(buf, fp, (sizeof(u32) * 2));
121762306a36Sopenharmony_ci		if (rc)
121862306a36Sopenharmony_ci			return rc;
121962306a36Sopenharmony_ci		c->permissions = le32_to_cpu(buf[0]);
122062306a36Sopenharmony_ci		nexpr = le32_to_cpu(buf[1]);
122162306a36Sopenharmony_ci		le = NULL;
122262306a36Sopenharmony_ci		depth = -1;
122362306a36Sopenharmony_ci		for (j = 0; j < nexpr; j++) {
122462306a36Sopenharmony_ci			e = kzalloc(sizeof(*e), GFP_KERNEL);
122562306a36Sopenharmony_ci			if (!e)
122662306a36Sopenharmony_ci				return -ENOMEM;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci			if (le)
122962306a36Sopenharmony_ci				le->next = e;
123062306a36Sopenharmony_ci			else
123162306a36Sopenharmony_ci				c->expr = e;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci			rc = next_entry(buf, fp, (sizeof(u32) * 3));
123462306a36Sopenharmony_ci			if (rc)
123562306a36Sopenharmony_ci				return rc;
123662306a36Sopenharmony_ci			e->expr_type = le32_to_cpu(buf[0]);
123762306a36Sopenharmony_ci			e->attr = le32_to_cpu(buf[1]);
123862306a36Sopenharmony_ci			e->op = le32_to_cpu(buf[2]);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci			switch (e->expr_type) {
124162306a36Sopenharmony_ci			case CEXPR_NOT:
124262306a36Sopenharmony_ci				if (depth < 0)
124362306a36Sopenharmony_ci					return -EINVAL;
124462306a36Sopenharmony_ci				break;
124562306a36Sopenharmony_ci			case CEXPR_AND:
124662306a36Sopenharmony_ci			case CEXPR_OR:
124762306a36Sopenharmony_ci				if (depth < 1)
124862306a36Sopenharmony_ci					return -EINVAL;
124962306a36Sopenharmony_ci				depth--;
125062306a36Sopenharmony_ci				break;
125162306a36Sopenharmony_ci			case CEXPR_ATTR:
125262306a36Sopenharmony_ci				if (depth == (CEXPR_MAXDEPTH - 1))
125362306a36Sopenharmony_ci					return -EINVAL;
125462306a36Sopenharmony_ci				depth++;
125562306a36Sopenharmony_ci				break;
125662306a36Sopenharmony_ci			case CEXPR_NAMES:
125762306a36Sopenharmony_ci				if (!allowxtarget && (e->attr & CEXPR_XTARGET))
125862306a36Sopenharmony_ci					return -EINVAL;
125962306a36Sopenharmony_ci				if (depth == (CEXPR_MAXDEPTH - 1))
126062306a36Sopenharmony_ci					return -EINVAL;
126162306a36Sopenharmony_ci				depth++;
126262306a36Sopenharmony_ci				rc = ebitmap_read(&e->names, fp);
126362306a36Sopenharmony_ci				if (rc)
126462306a36Sopenharmony_ci					return rc;
126562306a36Sopenharmony_ci				if (p->policyvers >=
126662306a36Sopenharmony_ci				    POLICYDB_VERSION_CONSTRAINT_NAMES) {
126762306a36Sopenharmony_ci					e->type_names = kzalloc(sizeof
126862306a36Sopenharmony_ci						(*e->type_names), GFP_KERNEL);
126962306a36Sopenharmony_ci					if (!e->type_names)
127062306a36Sopenharmony_ci						return -ENOMEM;
127162306a36Sopenharmony_ci					type_set_init(e->type_names);
127262306a36Sopenharmony_ci					rc = type_set_read(e->type_names, fp);
127362306a36Sopenharmony_ci					if (rc)
127462306a36Sopenharmony_ci						return rc;
127562306a36Sopenharmony_ci				}
127662306a36Sopenharmony_ci				break;
127762306a36Sopenharmony_ci			default:
127862306a36Sopenharmony_ci				return -EINVAL;
127962306a36Sopenharmony_ci			}
128062306a36Sopenharmony_ci			le = e;
128162306a36Sopenharmony_ci		}
128262306a36Sopenharmony_ci		if (depth != 0)
128362306a36Sopenharmony_ci			return -EINVAL;
128462306a36Sopenharmony_ci		lc = c;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	return 0;
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic int class_read(struct policydb *p, struct symtab *s, void *fp)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	char *key = NULL;
129362306a36Sopenharmony_ci	struct class_datum *cladatum;
129462306a36Sopenharmony_ci	__le32 buf[6];
129562306a36Sopenharmony_ci	u32 i, len, len2, ncons, nel;
129662306a36Sopenharmony_ci	int rc;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
129962306a36Sopenharmony_ci	if (!cladatum)
130062306a36Sopenharmony_ci		return -ENOMEM;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32)*6);
130362306a36Sopenharmony_ci	if (rc)
130462306a36Sopenharmony_ci		goto bad;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
130762306a36Sopenharmony_ci	len2 = le32_to_cpu(buf[1]);
130862306a36Sopenharmony_ci	cladatum->value = le32_to_cpu(buf[2]);
130962306a36Sopenharmony_ci	nel = le32_to_cpu(buf[4]);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	rc = symtab_init(&cladatum->permissions, nel);
131262306a36Sopenharmony_ci	if (rc)
131362306a36Sopenharmony_ci		goto bad;
131462306a36Sopenharmony_ci	cladatum->permissions.nprim = le32_to_cpu(buf[3]);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	ncons = le32_to_cpu(buf[5]);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
131962306a36Sopenharmony_ci	if (rc)
132062306a36Sopenharmony_ci		goto bad;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (len2) {
132362306a36Sopenharmony_ci		rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2);
132462306a36Sopenharmony_ci		if (rc)
132562306a36Sopenharmony_ci			goto bad;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci		rc = -EINVAL;
132862306a36Sopenharmony_ci		cladatum->comdatum = symtab_search(&p->p_commons,
132962306a36Sopenharmony_ci						   cladatum->comkey);
133062306a36Sopenharmony_ci		if (!cladatum->comdatum) {
133162306a36Sopenharmony_ci			pr_err("SELinux:  unknown common %s\n",
133262306a36Sopenharmony_ci			       cladatum->comkey);
133362306a36Sopenharmony_ci			goto bad;
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
133762306a36Sopenharmony_ci		rc = perm_read(p, &cladatum->permissions, fp);
133862306a36Sopenharmony_ci		if (rc)
133962306a36Sopenharmony_ci			goto bad;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
134362306a36Sopenharmony_ci	if (rc)
134462306a36Sopenharmony_ci		goto bad;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
134762306a36Sopenharmony_ci		/* grab the validatetrans rules */
134862306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32));
134962306a36Sopenharmony_ci		if (rc)
135062306a36Sopenharmony_ci			goto bad;
135162306a36Sopenharmony_ci		ncons = le32_to_cpu(buf[0]);
135262306a36Sopenharmony_ci		rc = read_cons_helper(p, &cladatum->validatetrans,
135362306a36Sopenharmony_ci				ncons, 1, fp);
135462306a36Sopenharmony_ci		if (rc)
135562306a36Sopenharmony_ci			goto bad;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
135962306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32) * 3);
136062306a36Sopenharmony_ci		if (rc)
136162306a36Sopenharmony_ci			goto bad;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		cladatum->default_user = le32_to_cpu(buf[0]);
136462306a36Sopenharmony_ci		cladatum->default_role = le32_to_cpu(buf[1]);
136562306a36Sopenharmony_ci		cladatum->default_range = le32_to_cpu(buf[2]);
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
136962306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32) * 1);
137062306a36Sopenharmony_ci		if (rc)
137162306a36Sopenharmony_ci			goto bad;
137262306a36Sopenharmony_ci		cladatum->default_type = le32_to_cpu(buf[0]);
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	rc = symtab_insert(s, key, cladatum);
137662306a36Sopenharmony_ci	if (rc)
137762306a36Sopenharmony_ci		goto bad;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	return 0;
138062306a36Sopenharmony_cibad:
138162306a36Sopenharmony_ci	cls_destroy(key, cladatum, NULL);
138262306a36Sopenharmony_ci	return rc;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic int role_read(struct policydb *p, struct symtab *s, void *fp)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	char *key = NULL;
138862306a36Sopenharmony_ci	struct role_datum *role;
138962306a36Sopenharmony_ci	int rc;
139062306a36Sopenharmony_ci	unsigned int to_read = 2;
139162306a36Sopenharmony_ci	__le32 buf[3];
139262306a36Sopenharmony_ci	u32 len;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	role = kzalloc(sizeof(*role), GFP_KERNEL);
139562306a36Sopenharmony_ci	if (!role)
139662306a36Sopenharmony_ci		return -ENOMEM;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
139962306a36Sopenharmony_ci		to_read = 3;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
140262306a36Sopenharmony_ci	if (rc)
140362306a36Sopenharmony_ci		goto bad;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
140662306a36Sopenharmony_ci	role->value = le32_to_cpu(buf[1]);
140762306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
140862306a36Sopenharmony_ci		role->bounds = le32_to_cpu(buf[2]);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
141162306a36Sopenharmony_ci	if (rc)
141262306a36Sopenharmony_ci		goto bad;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	rc = ebitmap_read(&role->dominates, fp);
141562306a36Sopenharmony_ci	if (rc)
141662306a36Sopenharmony_ci		goto bad;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	rc = ebitmap_read(&role->types, fp);
141962306a36Sopenharmony_ci	if (rc)
142062306a36Sopenharmony_ci		goto bad;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (strcmp(key, OBJECT_R) == 0) {
142362306a36Sopenharmony_ci		rc = -EINVAL;
142462306a36Sopenharmony_ci		if (role->value != OBJECT_R_VAL) {
142562306a36Sopenharmony_ci			pr_err("SELinux: Role %s has wrong value %d\n",
142662306a36Sopenharmony_ci			       OBJECT_R, role->value);
142762306a36Sopenharmony_ci			goto bad;
142862306a36Sopenharmony_ci		}
142962306a36Sopenharmony_ci		rc = 0;
143062306a36Sopenharmony_ci		goto bad;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	rc = symtab_insert(s, key, role);
143462306a36Sopenharmony_ci	if (rc)
143562306a36Sopenharmony_ci		goto bad;
143662306a36Sopenharmony_ci	return 0;
143762306a36Sopenharmony_cibad:
143862306a36Sopenharmony_ci	role_destroy(key, role, NULL);
143962306a36Sopenharmony_ci	return rc;
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cistatic int type_read(struct policydb *p, struct symtab *s, void *fp)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	char *key = NULL;
144562306a36Sopenharmony_ci	struct type_datum *typdatum;
144662306a36Sopenharmony_ci	int rc;
144762306a36Sopenharmony_ci	unsigned int to_read = 3;
144862306a36Sopenharmony_ci	__le32 buf[4];
144962306a36Sopenharmony_ci	u32 len;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
145262306a36Sopenharmony_ci	if (!typdatum)
145362306a36Sopenharmony_ci		return -ENOMEM;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
145662306a36Sopenharmony_ci		to_read = 4;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
145962306a36Sopenharmony_ci	if (rc)
146062306a36Sopenharmony_ci		goto bad;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
146362306a36Sopenharmony_ci	typdatum->value = le32_to_cpu(buf[1]);
146462306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
146562306a36Sopenharmony_ci		u32 prop = le32_to_cpu(buf[2]);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		if (prop & TYPEDATUM_PROPERTY_PRIMARY)
146862306a36Sopenharmony_ci			typdatum->primary = 1;
146962306a36Sopenharmony_ci		if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
147062306a36Sopenharmony_ci			typdatum->attribute = 1;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		typdatum->bounds = le32_to_cpu(buf[3]);
147362306a36Sopenharmony_ci	} else {
147462306a36Sopenharmony_ci		typdatum->primary = le32_to_cpu(buf[2]);
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
147862306a36Sopenharmony_ci	if (rc)
147962306a36Sopenharmony_ci		goto bad;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	rc = symtab_insert(s, key, typdatum);
148262306a36Sopenharmony_ci	if (rc)
148362306a36Sopenharmony_ci		goto bad;
148462306a36Sopenharmony_ci	return 0;
148562306a36Sopenharmony_cibad:
148662306a36Sopenharmony_ci	type_destroy(key, typdatum, NULL);
148762306a36Sopenharmony_ci	return rc;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci/*
149262306a36Sopenharmony_ci * Read a MLS level structure from a policydb binary
149362306a36Sopenharmony_ci * representation file.
149462306a36Sopenharmony_ci */
149562306a36Sopenharmony_cistatic int mls_read_level(struct mls_level *lp, void *fp)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	__le32 buf[1];
149862306a36Sopenharmony_ci	int rc;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	memset(lp, 0, sizeof(*lp));
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
150362306a36Sopenharmony_ci	if (rc) {
150462306a36Sopenharmony_ci		pr_err("SELinux: mls: truncated level\n");
150562306a36Sopenharmony_ci		return rc;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci	lp->sens = le32_to_cpu(buf[0]);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	rc = ebitmap_read(&lp->cat, fp);
151062306a36Sopenharmony_ci	if (rc) {
151162306a36Sopenharmony_ci		pr_err("SELinux: mls:  error reading level categories\n");
151262306a36Sopenharmony_ci		return rc;
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci	return 0;
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_cistatic int user_read(struct policydb *p, struct symtab *s, void *fp)
151862306a36Sopenharmony_ci{
151962306a36Sopenharmony_ci	char *key = NULL;
152062306a36Sopenharmony_ci	struct user_datum *usrdatum;
152162306a36Sopenharmony_ci	int rc;
152262306a36Sopenharmony_ci	unsigned int to_read = 2;
152362306a36Sopenharmony_ci	__le32 buf[3];
152462306a36Sopenharmony_ci	u32 len;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
152762306a36Sopenharmony_ci	if (!usrdatum)
152862306a36Sopenharmony_ci		return -ENOMEM;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
153162306a36Sopenharmony_ci		to_read = 3;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
153462306a36Sopenharmony_ci	if (rc)
153562306a36Sopenharmony_ci		goto bad;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
153862306a36Sopenharmony_ci	usrdatum->value = le32_to_cpu(buf[1]);
153962306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
154062306a36Sopenharmony_ci		usrdatum->bounds = le32_to_cpu(buf[2]);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
154362306a36Sopenharmony_ci	if (rc)
154462306a36Sopenharmony_ci		goto bad;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	rc = ebitmap_read(&usrdatum->roles, fp);
154762306a36Sopenharmony_ci	if (rc)
154862306a36Sopenharmony_ci		goto bad;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_MLS) {
155162306a36Sopenharmony_ci		rc = mls_read_range_helper(&usrdatum->range, fp);
155262306a36Sopenharmony_ci		if (rc)
155362306a36Sopenharmony_ci			goto bad;
155462306a36Sopenharmony_ci		rc = mls_read_level(&usrdatum->dfltlevel, fp);
155562306a36Sopenharmony_ci		if (rc)
155662306a36Sopenharmony_ci			goto bad;
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	rc = symtab_insert(s, key, usrdatum);
156062306a36Sopenharmony_ci	if (rc)
156162306a36Sopenharmony_ci		goto bad;
156262306a36Sopenharmony_ci	return 0;
156362306a36Sopenharmony_cibad:
156462306a36Sopenharmony_ci	user_destroy(key, usrdatum, NULL);
156562306a36Sopenharmony_ci	return rc;
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic int sens_read(struct policydb *p, struct symtab *s, void *fp)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	char *key = NULL;
157162306a36Sopenharmony_ci	struct level_datum *levdatum;
157262306a36Sopenharmony_ci	int rc;
157362306a36Sopenharmony_ci	__le32 buf[2];
157462306a36Sopenharmony_ci	u32 len;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	levdatum = kzalloc(sizeof(*levdatum), GFP_KERNEL);
157762306a36Sopenharmony_ci	if (!levdatum)
157862306a36Sopenharmony_ci		return -ENOMEM;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
158162306a36Sopenharmony_ci	if (rc)
158262306a36Sopenharmony_ci		goto bad;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
158562306a36Sopenharmony_ci	levdatum->isalias = le32_to_cpu(buf[1]);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
158862306a36Sopenharmony_ci	if (rc)
158962306a36Sopenharmony_ci		goto bad;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	rc = -ENOMEM;
159262306a36Sopenharmony_ci	levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_KERNEL);
159362306a36Sopenharmony_ci	if (!levdatum->level)
159462306a36Sopenharmony_ci		goto bad;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	rc = mls_read_level(levdatum->level, fp);
159762306a36Sopenharmony_ci	if (rc)
159862306a36Sopenharmony_ci		goto bad;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	rc = symtab_insert(s, key, levdatum);
160162306a36Sopenharmony_ci	if (rc)
160262306a36Sopenharmony_ci		goto bad;
160362306a36Sopenharmony_ci	return 0;
160462306a36Sopenharmony_cibad:
160562306a36Sopenharmony_ci	sens_destroy(key, levdatum, NULL);
160662306a36Sopenharmony_ci	return rc;
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_cistatic int cat_read(struct policydb *p, struct symtab *s, void *fp)
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	char *key = NULL;
161262306a36Sopenharmony_ci	struct cat_datum *catdatum;
161362306a36Sopenharmony_ci	int rc;
161462306a36Sopenharmony_ci	__le32 buf[3];
161562306a36Sopenharmony_ci	u32 len;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	catdatum = kzalloc(sizeof(*catdatum), GFP_KERNEL);
161862306a36Sopenharmony_ci	if (!catdatum)
161962306a36Sopenharmony_ci		return -ENOMEM;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof buf);
162262306a36Sopenharmony_ci	if (rc)
162362306a36Sopenharmony_ci		goto bad;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
162662306a36Sopenharmony_ci	catdatum->value = le32_to_cpu(buf[1]);
162762306a36Sopenharmony_ci	catdatum->isalias = le32_to_cpu(buf[2]);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	rc = str_read(&key, GFP_KERNEL, fp, len);
163062306a36Sopenharmony_ci	if (rc)
163162306a36Sopenharmony_ci		goto bad;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	rc = symtab_insert(s, key, catdatum);
163462306a36Sopenharmony_ci	if (rc)
163562306a36Sopenharmony_ci		goto bad;
163662306a36Sopenharmony_ci	return 0;
163762306a36Sopenharmony_cibad:
163862306a36Sopenharmony_ci	cat_destroy(key, catdatum, NULL);
163962306a36Sopenharmony_ci	return rc;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic int (*const read_f[SYM_NUM]) (struct policydb *p,
164362306a36Sopenharmony_ci				     struct symtab *s, void *fp) = {
164462306a36Sopenharmony_ci	common_read,
164562306a36Sopenharmony_ci	class_read,
164662306a36Sopenharmony_ci	role_read,
164762306a36Sopenharmony_ci	type_read,
164862306a36Sopenharmony_ci	user_read,
164962306a36Sopenharmony_ci	cond_read_bool,
165062306a36Sopenharmony_ci	sens_read,
165162306a36Sopenharmony_ci	cat_read,
165262306a36Sopenharmony_ci};
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic int user_bounds_sanity_check(void *key, void *datum, void *datap)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	struct user_datum *upper, *user;
165762306a36Sopenharmony_ci	struct policydb *p = datap;
165862306a36Sopenharmony_ci	int depth = 0;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	upper = user = datum;
166162306a36Sopenharmony_ci	while (upper->bounds) {
166262306a36Sopenharmony_ci		struct ebitmap_node *node;
166362306a36Sopenharmony_ci		u32 bit;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
166662306a36Sopenharmony_ci			pr_err("SELinux: user %s: "
166762306a36Sopenharmony_ci			       "too deep or looped boundary\n",
166862306a36Sopenharmony_ci			       (char *) key);
166962306a36Sopenharmony_ci			return -EINVAL;
167062306a36Sopenharmony_ci		}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		upper = p->user_val_to_struct[upper->bounds - 1];
167362306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
167462306a36Sopenharmony_ci			if (ebitmap_get_bit(&upper->roles, bit))
167562306a36Sopenharmony_ci				continue;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci			pr_err("SELinux: boundary violated policy: "
167862306a36Sopenharmony_ci			       "user=%s role=%s bounds=%s\n",
167962306a36Sopenharmony_ci			       sym_name(p, SYM_USERS, user->value - 1),
168062306a36Sopenharmony_ci			       sym_name(p, SYM_ROLES, bit),
168162306a36Sopenharmony_ci			       sym_name(p, SYM_USERS, upper->value - 1));
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci			return -EINVAL;
168462306a36Sopenharmony_ci		}
168562306a36Sopenharmony_ci	}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	return 0;
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistatic int role_bounds_sanity_check(void *key, void *datum, void *datap)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct role_datum *upper, *role;
169362306a36Sopenharmony_ci	struct policydb *p = datap;
169462306a36Sopenharmony_ci	int depth = 0;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	upper = role = datum;
169762306a36Sopenharmony_ci	while (upper->bounds) {
169862306a36Sopenharmony_ci		struct ebitmap_node *node;
169962306a36Sopenharmony_ci		u32 bit;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
170262306a36Sopenharmony_ci			pr_err("SELinux: role %s: "
170362306a36Sopenharmony_ci			       "too deep or looped bounds\n",
170462306a36Sopenharmony_ci			       (char *) key);
170562306a36Sopenharmony_ci			return -EINVAL;
170662306a36Sopenharmony_ci		}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		upper = p->role_val_to_struct[upper->bounds - 1];
170962306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(&role->types, node, bit) {
171062306a36Sopenharmony_ci			if (ebitmap_get_bit(&upper->types, bit))
171162306a36Sopenharmony_ci				continue;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci			pr_err("SELinux: boundary violated policy: "
171462306a36Sopenharmony_ci			       "role=%s type=%s bounds=%s\n",
171562306a36Sopenharmony_ci			       sym_name(p, SYM_ROLES, role->value - 1),
171662306a36Sopenharmony_ci			       sym_name(p, SYM_TYPES, bit),
171762306a36Sopenharmony_ci			       sym_name(p, SYM_ROLES, upper->value - 1));
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci			return -EINVAL;
172062306a36Sopenharmony_ci		}
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	return 0;
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic int type_bounds_sanity_check(void *key, void *datum, void *datap)
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	struct type_datum *upper;
172962306a36Sopenharmony_ci	struct policydb *p = datap;
173062306a36Sopenharmony_ci	int depth = 0;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	upper = datum;
173362306a36Sopenharmony_ci	while (upper->bounds) {
173462306a36Sopenharmony_ci		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
173562306a36Sopenharmony_ci			pr_err("SELinux: type %s: "
173662306a36Sopenharmony_ci			       "too deep or looped boundary\n",
173762306a36Sopenharmony_ci			       (char *) key);
173862306a36Sopenharmony_ci			return -EINVAL;
173962306a36Sopenharmony_ci		}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci		upper = p->type_val_to_struct[upper->bounds - 1];
174262306a36Sopenharmony_ci		BUG_ON(!upper);
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci		if (upper->attribute) {
174562306a36Sopenharmony_ci			pr_err("SELinux: type %s: "
174662306a36Sopenharmony_ci			       "bounded by attribute %s\n",
174762306a36Sopenharmony_ci			       (char *) key,
174862306a36Sopenharmony_ci			       sym_name(p, SYM_TYPES, upper->value - 1));
174962306a36Sopenharmony_ci			return -EINVAL;
175062306a36Sopenharmony_ci		}
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	return 0;
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic int policydb_bounds_sanity_check(struct policydb *p)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	int rc;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
176162306a36Sopenharmony_ci		return 0;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	rc = hashtab_map(&p->p_users.table, user_bounds_sanity_check, p);
176462306a36Sopenharmony_ci	if (rc)
176562306a36Sopenharmony_ci		return rc;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	rc = hashtab_map(&p->p_roles.table, role_bounds_sanity_check, p);
176862306a36Sopenharmony_ci	if (rc)
176962306a36Sopenharmony_ci		return rc;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	rc = hashtab_map(&p->p_types.table, type_bounds_sanity_check, p);
177262306a36Sopenharmony_ci	if (rc)
177362306a36Sopenharmony_ci		return rc;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	return 0;
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ciu16 string_to_security_class(struct policydb *p, const char *name)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	struct class_datum *cladatum;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	cladatum = symtab_search(&p->p_classes, name);
178362306a36Sopenharmony_ci	if (!cladatum)
178462306a36Sopenharmony_ci		return 0;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	return cladatum->value;
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ciu32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct class_datum *cladatum;
179262306a36Sopenharmony_ci	struct perm_datum *perdatum = NULL;
179362306a36Sopenharmony_ci	struct common_datum *comdatum;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	if (!tclass || tclass > p->p_classes.nprim)
179662306a36Sopenharmony_ci		return 0;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	cladatum = p->class_val_to_struct[tclass-1];
179962306a36Sopenharmony_ci	comdatum = cladatum->comdatum;
180062306a36Sopenharmony_ci	if (comdatum)
180162306a36Sopenharmony_ci		perdatum = symtab_search(&comdatum->permissions, name);
180262306a36Sopenharmony_ci	if (!perdatum)
180362306a36Sopenharmony_ci		perdatum = symtab_search(&cladatum->permissions, name);
180462306a36Sopenharmony_ci	if (!perdatum)
180562306a36Sopenharmony_ci		return 0;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	return 1U << (perdatum->value-1);
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic int range_read(struct policydb *p, void *fp)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	struct range_trans *rt = NULL;
181362306a36Sopenharmony_ci	struct mls_range *r = NULL;
181462306a36Sopenharmony_ci	int rc;
181562306a36Sopenharmony_ci	__le32 buf[2];
181662306a36Sopenharmony_ci	u32 i, nel;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_MLS)
181962306a36Sopenharmony_ci		return 0;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
182262306a36Sopenharmony_ci	if (rc)
182362306a36Sopenharmony_ci		return rc;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	nel = le32_to_cpu(buf[0]);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	rc = hashtab_init(&p->range_tr, nel);
182862306a36Sopenharmony_ci	if (rc)
182962306a36Sopenharmony_ci		return rc;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
183262306a36Sopenharmony_ci		rc = -ENOMEM;
183362306a36Sopenharmony_ci		rt = kzalloc(sizeof(*rt), GFP_KERNEL);
183462306a36Sopenharmony_ci		if (!rt)
183562306a36Sopenharmony_ci			goto out;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci		rc = next_entry(buf, fp, (sizeof(u32) * 2));
183862306a36Sopenharmony_ci		if (rc)
183962306a36Sopenharmony_ci			goto out;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci		rt->source_type = le32_to_cpu(buf[0]);
184262306a36Sopenharmony_ci		rt->target_type = le32_to_cpu(buf[1]);
184362306a36Sopenharmony_ci		if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
184462306a36Sopenharmony_ci			rc = next_entry(buf, fp, sizeof(u32));
184562306a36Sopenharmony_ci			if (rc)
184662306a36Sopenharmony_ci				goto out;
184762306a36Sopenharmony_ci			rt->target_class = le32_to_cpu(buf[0]);
184862306a36Sopenharmony_ci		} else
184962306a36Sopenharmony_ci			rt->target_class = p->process_class;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci		rc = -EINVAL;
185262306a36Sopenharmony_ci		if (!policydb_type_isvalid(p, rt->source_type) ||
185362306a36Sopenharmony_ci		    !policydb_type_isvalid(p, rt->target_type) ||
185462306a36Sopenharmony_ci		    !policydb_class_isvalid(p, rt->target_class))
185562306a36Sopenharmony_ci			goto out;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci		rc = -ENOMEM;
185862306a36Sopenharmony_ci		r = kzalloc(sizeof(*r), GFP_KERNEL);
185962306a36Sopenharmony_ci		if (!r)
186062306a36Sopenharmony_ci			goto out;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci		rc = mls_read_range_helper(r, fp);
186362306a36Sopenharmony_ci		if (rc)
186462306a36Sopenharmony_ci			goto out;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci		rc = -EINVAL;
186762306a36Sopenharmony_ci		if (!mls_range_isvalid(p, r)) {
186862306a36Sopenharmony_ci			pr_warn("SELinux:  rangetrans:  invalid range\n");
186962306a36Sopenharmony_ci			goto out;
187062306a36Sopenharmony_ci		}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci		rc = hashtab_insert(&p->range_tr, rt, r, rangetr_key_params);
187362306a36Sopenharmony_ci		if (rc)
187462306a36Sopenharmony_ci			goto out;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci		rt = NULL;
187762306a36Sopenharmony_ci		r = NULL;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci	hash_eval(&p->range_tr, "rangetr");
188062306a36Sopenharmony_ci	rc = 0;
188162306a36Sopenharmony_ciout:
188262306a36Sopenharmony_ci	kfree(rt);
188362306a36Sopenharmony_ci	kfree(r);
188462306a36Sopenharmony_ci	return rc;
188562306a36Sopenharmony_ci}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_cistatic int filename_trans_read_helper_compat(struct policydb *p, void *fp)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	struct filename_trans_key key, *ft = NULL;
189062306a36Sopenharmony_ci	struct filename_trans_datum *last, *datum = NULL;
189162306a36Sopenharmony_ci	char *name = NULL;
189262306a36Sopenharmony_ci	u32 len, stype, otype;
189362306a36Sopenharmony_ci	__le32 buf[4];
189462306a36Sopenharmony_ci	int rc;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	/* length of the path component string */
189762306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
189862306a36Sopenharmony_ci	if (rc)
189962306a36Sopenharmony_ci		return rc;
190062306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	/* path component string */
190362306a36Sopenharmony_ci	rc = str_read(&name, GFP_KERNEL, fp, len);
190462306a36Sopenharmony_ci	if (rc)
190562306a36Sopenharmony_ci		return rc;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32) * 4);
190862306a36Sopenharmony_ci	if (rc)
190962306a36Sopenharmony_ci		goto out;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	stype = le32_to_cpu(buf[0]);
191262306a36Sopenharmony_ci	key.ttype = le32_to_cpu(buf[1]);
191362306a36Sopenharmony_ci	key.tclass = le32_to_cpu(buf[2]);
191462306a36Sopenharmony_ci	key.name = name;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	otype = le32_to_cpu(buf[3]);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	last = NULL;
191962306a36Sopenharmony_ci	datum = policydb_filenametr_search(p, &key);
192062306a36Sopenharmony_ci	while (datum) {
192162306a36Sopenharmony_ci		if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
192262306a36Sopenharmony_ci			/* conflicting/duplicate rules are ignored */
192362306a36Sopenharmony_ci			datum = NULL;
192462306a36Sopenharmony_ci			goto out;
192562306a36Sopenharmony_ci		}
192662306a36Sopenharmony_ci		if (likely(datum->otype == otype))
192762306a36Sopenharmony_ci			break;
192862306a36Sopenharmony_ci		last = datum;
192962306a36Sopenharmony_ci		datum = datum->next;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci	if (!datum) {
193262306a36Sopenharmony_ci		rc = -ENOMEM;
193362306a36Sopenharmony_ci		datum = kmalloc(sizeof(*datum), GFP_KERNEL);
193462306a36Sopenharmony_ci		if (!datum)
193562306a36Sopenharmony_ci			goto out;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci		ebitmap_init(&datum->stypes);
193862306a36Sopenharmony_ci		datum->otype = otype;
193962306a36Sopenharmony_ci		datum->next = NULL;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci		if (unlikely(last)) {
194262306a36Sopenharmony_ci			last->next = datum;
194362306a36Sopenharmony_ci		} else {
194462306a36Sopenharmony_ci			rc = -ENOMEM;
194562306a36Sopenharmony_ci			ft = kmemdup(&key, sizeof(key), GFP_KERNEL);
194662306a36Sopenharmony_ci			if (!ft)
194762306a36Sopenharmony_ci				goto out;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci			rc = hashtab_insert(&p->filename_trans, ft, datum,
195062306a36Sopenharmony_ci					    filenametr_key_params);
195162306a36Sopenharmony_ci			if (rc)
195262306a36Sopenharmony_ci				goto out;
195362306a36Sopenharmony_ci			name = NULL;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci			rc = ebitmap_set_bit(&p->filename_trans_ttypes,
195662306a36Sopenharmony_ci					     key.ttype, 1);
195762306a36Sopenharmony_ci			if (rc)
195862306a36Sopenharmony_ci				return rc;
195962306a36Sopenharmony_ci		}
196062306a36Sopenharmony_ci	}
196162306a36Sopenharmony_ci	kfree(name);
196262306a36Sopenharmony_ci	return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ciout:
196562306a36Sopenharmony_ci	kfree(ft);
196662306a36Sopenharmony_ci	kfree(name);
196762306a36Sopenharmony_ci	kfree(datum);
196862306a36Sopenharmony_ci	return rc;
196962306a36Sopenharmony_ci}
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_cistatic int filename_trans_read_helper(struct policydb *p, void *fp)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct filename_trans_key *ft = NULL;
197462306a36Sopenharmony_ci	struct filename_trans_datum **dst, *datum, *first = NULL;
197562306a36Sopenharmony_ci	char *name = NULL;
197662306a36Sopenharmony_ci	u32 len, ttype, tclass, ndatum, i;
197762306a36Sopenharmony_ci	__le32 buf[3];
197862306a36Sopenharmony_ci	int rc;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	/* length of the path component string */
198162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
198262306a36Sopenharmony_ci	if (rc)
198362306a36Sopenharmony_ci		return rc;
198462306a36Sopenharmony_ci	len = le32_to_cpu(buf[0]);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	/* path component string */
198762306a36Sopenharmony_ci	rc = str_read(&name, GFP_KERNEL, fp, len);
198862306a36Sopenharmony_ci	if (rc)
198962306a36Sopenharmony_ci		return rc;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32) * 3);
199262306a36Sopenharmony_ci	if (rc)
199362306a36Sopenharmony_ci		goto out;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	ttype = le32_to_cpu(buf[0]);
199662306a36Sopenharmony_ci	tclass = le32_to_cpu(buf[1]);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	ndatum = le32_to_cpu(buf[2]);
199962306a36Sopenharmony_ci	if (ndatum == 0) {
200062306a36Sopenharmony_ci		pr_err("SELinux:  Filename transition key with no datum\n");
200162306a36Sopenharmony_ci		rc = -ENOENT;
200262306a36Sopenharmony_ci		goto out;
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	dst = &first;
200662306a36Sopenharmony_ci	for (i = 0; i < ndatum; i++) {
200762306a36Sopenharmony_ci		rc = -ENOMEM;
200862306a36Sopenharmony_ci		datum = kmalloc(sizeof(*datum), GFP_KERNEL);
200962306a36Sopenharmony_ci		if (!datum)
201062306a36Sopenharmony_ci			goto out;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci		datum->next = NULL;
201362306a36Sopenharmony_ci		*dst = datum;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		/* ebitmap_read() will at least init the bitmap */
201662306a36Sopenharmony_ci		rc = ebitmap_read(&datum->stypes, fp);
201762306a36Sopenharmony_ci		if (rc)
201862306a36Sopenharmony_ci			goto out;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32));
202162306a36Sopenharmony_ci		if (rc)
202262306a36Sopenharmony_ci			goto out;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci		datum->otype = le32_to_cpu(buf[0]);
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci		dst = &datum->next;
202762306a36Sopenharmony_ci	}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	rc = -ENOMEM;
203062306a36Sopenharmony_ci	ft = kmalloc(sizeof(*ft), GFP_KERNEL);
203162306a36Sopenharmony_ci	if (!ft)
203262306a36Sopenharmony_ci		goto out;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	ft->ttype = ttype;
203562306a36Sopenharmony_ci	ft->tclass = tclass;
203662306a36Sopenharmony_ci	ft->name = name;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	rc = hashtab_insert(&p->filename_trans, ft, first,
203962306a36Sopenharmony_ci			    filenametr_key_params);
204062306a36Sopenharmony_ci	if (rc == -EEXIST)
204162306a36Sopenharmony_ci		pr_err("SELinux:  Duplicate filename transition key\n");
204262306a36Sopenharmony_ci	if (rc)
204362306a36Sopenharmony_ci		goto out;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	return ebitmap_set_bit(&p->filename_trans_ttypes, ttype, 1);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ciout:
204862306a36Sopenharmony_ci	kfree(ft);
204962306a36Sopenharmony_ci	kfree(name);
205062306a36Sopenharmony_ci	while (first) {
205162306a36Sopenharmony_ci		datum = first;
205262306a36Sopenharmony_ci		first = first->next;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci		ebitmap_destroy(&datum->stypes);
205562306a36Sopenharmony_ci		kfree(datum);
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci	return rc;
205862306a36Sopenharmony_ci}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_cistatic int filename_trans_read(struct policydb *p, void *fp)
206162306a36Sopenharmony_ci{
206262306a36Sopenharmony_ci	u32 nel, i;
206362306a36Sopenharmony_ci	__le32 buf[1];
206462306a36Sopenharmony_ci	int rc;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
206762306a36Sopenharmony_ci		return 0;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
207062306a36Sopenharmony_ci	if (rc)
207162306a36Sopenharmony_ci		return rc;
207262306a36Sopenharmony_ci	nel = le32_to_cpu(buf[0]);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
207562306a36Sopenharmony_ci		p->compat_filename_trans_count = nel;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci		rc = hashtab_init(&p->filename_trans, (1 << 11));
207862306a36Sopenharmony_ci		if (rc)
207962306a36Sopenharmony_ci			return rc;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		for (i = 0; i < nel; i++) {
208262306a36Sopenharmony_ci			rc = filename_trans_read_helper_compat(p, fp);
208362306a36Sopenharmony_ci			if (rc)
208462306a36Sopenharmony_ci				return rc;
208562306a36Sopenharmony_ci		}
208662306a36Sopenharmony_ci	} else {
208762306a36Sopenharmony_ci		rc = hashtab_init(&p->filename_trans, nel);
208862306a36Sopenharmony_ci		if (rc)
208962306a36Sopenharmony_ci			return rc;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		for (i = 0; i < nel; i++) {
209262306a36Sopenharmony_ci			rc = filename_trans_read_helper(p, fp);
209362306a36Sopenharmony_ci			if (rc)
209462306a36Sopenharmony_ci				return rc;
209562306a36Sopenharmony_ci		}
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci	hash_eval(&p->filename_trans, "filenametr");
209862306a36Sopenharmony_ci	return 0;
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic int genfs_read(struct policydb *p, void *fp)
210262306a36Sopenharmony_ci{
210362306a36Sopenharmony_ci	int rc;
210462306a36Sopenharmony_ci	u32 i, j, nel, nel2, len, len2;
210562306a36Sopenharmony_ci	__le32 buf[1];
210662306a36Sopenharmony_ci	struct ocontext *l, *c;
210762306a36Sopenharmony_ci	struct ocontext *newc = NULL;
210862306a36Sopenharmony_ci	struct genfs *genfs_p, *genfs;
210962306a36Sopenharmony_ci	struct genfs *newgenfs = NULL;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
211262306a36Sopenharmony_ci	if (rc)
211362306a36Sopenharmony_ci		return rc;
211462306a36Sopenharmony_ci	nel = le32_to_cpu(buf[0]);
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
211762306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32));
211862306a36Sopenharmony_ci		if (rc)
211962306a36Sopenharmony_ci			goto out;
212062306a36Sopenharmony_ci		len = le32_to_cpu(buf[0]);
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		rc = -ENOMEM;
212362306a36Sopenharmony_ci		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
212462306a36Sopenharmony_ci		if (!newgenfs)
212562306a36Sopenharmony_ci			goto out;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci		rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len);
212862306a36Sopenharmony_ci		if (rc)
212962306a36Sopenharmony_ci			goto out;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		for (genfs_p = NULL, genfs = p->genfs; genfs;
213262306a36Sopenharmony_ci		     genfs_p = genfs, genfs = genfs->next) {
213362306a36Sopenharmony_ci			rc = -EINVAL;
213462306a36Sopenharmony_ci			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
213562306a36Sopenharmony_ci				pr_err("SELinux:  dup genfs fstype %s\n",
213662306a36Sopenharmony_ci				       newgenfs->fstype);
213762306a36Sopenharmony_ci				goto out;
213862306a36Sopenharmony_ci			}
213962306a36Sopenharmony_ci			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
214062306a36Sopenharmony_ci				break;
214162306a36Sopenharmony_ci		}
214262306a36Sopenharmony_ci		newgenfs->next = genfs;
214362306a36Sopenharmony_ci		if (genfs_p)
214462306a36Sopenharmony_ci			genfs_p->next = newgenfs;
214562306a36Sopenharmony_ci		else
214662306a36Sopenharmony_ci			p->genfs = newgenfs;
214762306a36Sopenharmony_ci		genfs = newgenfs;
214862306a36Sopenharmony_ci		newgenfs = NULL;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32));
215162306a36Sopenharmony_ci		if (rc)
215262306a36Sopenharmony_ci			goto out;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci		nel2 = le32_to_cpu(buf[0]);
215562306a36Sopenharmony_ci		for (j = 0; j < nel2; j++) {
215662306a36Sopenharmony_ci			rc = next_entry(buf, fp, sizeof(u32));
215762306a36Sopenharmony_ci			if (rc)
215862306a36Sopenharmony_ci				goto out;
215962306a36Sopenharmony_ci			len = le32_to_cpu(buf[0]);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci			rc = -ENOMEM;
216262306a36Sopenharmony_ci			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
216362306a36Sopenharmony_ci			if (!newc)
216462306a36Sopenharmony_ci				goto out;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci			rc = str_read(&newc->u.name, GFP_KERNEL, fp, len);
216762306a36Sopenharmony_ci			if (rc)
216862306a36Sopenharmony_ci				goto out;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci			rc = next_entry(buf, fp, sizeof(u32));
217162306a36Sopenharmony_ci			if (rc)
217262306a36Sopenharmony_ci				goto out;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci			newc->v.sclass = le32_to_cpu(buf[0]);
217562306a36Sopenharmony_ci			rc = context_read_and_validate(&newc->context[0], p, fp);
217662306a36Sopenharmony_ci			if (rc)
217762306a36Sopenharmony_ci				goto out;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci			for (l = NULL, c = genfs->head; c;
218062306a36Sopenharmony_ci			     l = c, c = c->next) {
218162306a36Sopenharmony_ci				rc = -EINVAL;
218262306a36Sopenharmony_ci				if (!strcmp(newc->u.name, c->u.name) &&
218362306a36Sopenharmony_ci				    (!c->v.sclass || !newc->v.sclass ||
218462306a36Sopenharmony_ci				     newc->v.sclass == c->v.sclass)) {
218562306a36Sopenharmony_ci					pr_err("SELinux:  dup genfs entry (%s,%s)\n",
218662306a36Sopenharmony_ci					       genfs->fstype, c->u.name);
218762306a36Sopenharmony_ci					goto out;
218862306a36Sopenharmony_ci				}
218962306a36Sopenharmony_ci				len = strlen(newc->u.name);
219062306a36Sopenharmony_ci				len2 = strlen(c->u.name);
219162306a36Sopenharmony_ci				if (len > len2)
219262306a36Sopenharmony_ci					break;
219362306a36Sopenharmony_ci			}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci			newc->next = c;
219662306a36Sopenharmony_ci			if (l)
219762306a36Sopenharmony_ci				l->next = newc;
219862306a36Sopenharmony_ci			else
219962306a36Sopenharmony_ci				genfs->head = newc;
220062306a36Sopenharmony_ci			newc = NULL;
220162306a36Sopenharmony_ci		}
220262306a36Sopenharmony_ci	}
220362306a36Sopenharmony_ci	rc = 0;
220462306a36Sopenharmony_ciout:
220562306a36Sopenharmony_ci	if (newgenfs) {
220662306a36Sopenharmony_ci		kfree(newgenfs->fstype);
220762306a36Sopenharmony_ci		kfree(newgenfs);
220862306a36Sopenharmony_ci	}
220962306a36Sopenharmony_ci	ocontext_destroy(newc, OCON_FSUSE);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	return rc;
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic int ocontext_read(struct policydb *p, const struct policydb_compat_info *info,
221562306a36Sopenharmony_ci			 void *fp)
221662306a36Sopenharmony_ci{
221762306a36Sopenharmony_ci	int rc;
221862306a36Sopenharmony_ci	unsigned int i;
221962306a36Sopenharmony_ci	u32 j, nel, len;
222062306a36Sopenharmony_ci	__be64 prefixbuf[1];
222162306a36Sopenharmony_ci	__le32 buf[3];
222262306a36Sopenharmony_ci	struct ocontext *l, *c;
222362306a36Sopenharmony_ci	u32 nodebuf[8];
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	for (i = 0; i < info->ocon_num; i++) {
222662306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32));
222762306a36Sopenharmony_ci		if (rc)
222862306a36Sopenharmony_ci			goto out;
222962306a36Sopenharmony_ci		nel = le32_to_cpu(buf[0]);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci		l = NULL;
223262306a36Sopenharmony_ci		for (j = 0; j < nel; j++) {
223362306a36Sopenharmony_ci			rc = -ENOMEM;
223462306a36Sopenharmony_ci			c = kzalloc(sizeof(*c), GFP_KERNEL);
223562306a36Sopenharmony_ci			if (!c)
223662306a36Sopenharmony_ci				goto out;
223762306a36Sopenharmony_ci			if (l)
223862306a36Sopenharmony_ci				l->next = c;
223962306a36Sopenharmony_ci			else
224062306a36Sopenharmony_ci				p->ocontexts[i] = c;
224162306a36Sopenharmony_ci			l = c;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci			switch (i) {
224462306a36Sopenharmony_ci			case OCON_ISID:
224562306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32));
224662306a36Sopenharmony_ci				if (rc)
224762306a36Sopenharmony_ci					goto out;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci				c->sid[0] = le32_to_cpu(buf[0]);
225062306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
225162306a36Sopenharmony_ci				if (rc)
225262306a36Sopenharmony_ci					goto out;
225362306a36Sopenharmony_ci				break;
225462306a36Sopenharmony_ci			case OCON_FS:
225562306a36Sopenharmony_ci			case OCON_NETIF:
225662306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32));
225762306a36Sopenharmony_ci				if (rc)
225862306a36Sopenharmony_ci					goto out;
225962306a36Sopenharmony_ci				len = le32_to_cpu(buf[0]);
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci				rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
226262306a36Sopenharmony_ci				if (rc)
226362306a36Sopenharmony_ci					goto out;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci				if (i == OCON_FS)
226662306a36Sopenharmony_ci					pr_warn("SELinux:  void and deprecated fs ocon %s\n",
226762306a36Sopenharmony_ci						c->u.name);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
227062306a36Sopenharmony_ci				if (rc)
227162306a36Sopenharmony_ci					goto out;
227262306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[1], p, fp);
227362306a36Sopenharmony_ci				if (rc)
227462306a36Sopenharmony_ci					goto out;
227562306a36Sopenharmony_ci				break;
227662306a36Sopenharmony_ci			case OCON_PORT:
227762306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32)*3);
227862306a36Sopenharmony_ci				if (rc)
227962306a36Sopenharmony_ci					goto out;
228062306a36Sopenharmony_ci				c->u.port.protocol = le32_to_cpu(buf[0]);
228162306a36Sopenharmony_ci				c->u.port.low_port = le32_to_cpu(buf[1]);
228262306a36Sopenharmony_ci				c->u.port.high_port = le32_to_cpu(buf[2]);
228362306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
228462306a36Sopenharmony_ci				if (rc)
228562306a36Sopenharmony_ci					goto out;
228662306a36Sopenharmony_ci				break;
228762306a36Sopenharmony_ci			case OCON_NODE:
228862306a36Sopenharmony_ci				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
228962306a36Sopenharmony_ci				if (rc)
229062306a36Sopenharmony_ci					goto out;
229162306a36Sopenharmony_ci				c->u.node.addr = nodebuf[0]; /* network order */
229262306a36Sopenharmony_ci				c->u.node.mask = nodebuf[1]; /* network order */
229362306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
229462306a36Sopenharmony_ci				if (rc)
229562306a36Sopenharmony_ci					goto out;
229662306a36Sopenharmony_ci				break;
229762306a36Sopenharmony_ci			case OCON_FSUSE:
229862306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32)*2);
229962306a36Sopenharmony_ci				if (rc)
230062306a36Sopenharmony_ci					goto out;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci				rc = -EINVAL;
230362306a36Sopenharmony_ci				c->v.behavior = le32_to_cpu(buf[0]);
230462306a36Sopenharmony_ci				/* Determined at runtime, not in policy DB. */
230562306a36Sopenharmony_ci				if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
230662306a36Sopenharmony_ci					goto out;
230762306a36Sopenharmony_ci				if (c->v.behavior > SECURITY_FS_USE_MAX)
230862306a36Sopenharmony_ci					goto out;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci				len = le32_to_cpu(buf[1]);
231162306a36Sopenharmony_ci				rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
231262306a36Sopenharmony_ci				if (rc)
231362306a36Sopenharmony_ci					goto out;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
231662306a36Sopenharmony_ci				if (rc)
231762306a36Sopenharmony_ci					goto out;
231862306a36Sopenharmony_ci				break;
231962306a36Sopenharmony_ci			case OCON_NODE6: {
232062306a36Sopenharmony_ci				int k;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
232362306a36Sopenharmony_ci				if (rc)
232462306a36Sopenharmony_ci					goto out;
232562306a36Sopenharmony_ci				for (k = 0; k < 4; k++)
232662306a36Sopenharmony_ci					c->u.node6.addr[k] = nodebuf[k];
232762306a36Sopenharmony_ci				for (k = 0; k < 4; k++)
232862306a36Sopenharmony_ci					c->u.node6.mask[k] = nodebuf[k+4];
232962306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0], p, fp);
233062306a36Sopenharmony_ci				if (rc)
233162306a36Sopenharmony_ci					goto out;
233262306a36Sopenharmony_ci				break;
233362306a36Sopenharmony_ci			}
233462306a36Sopenharmony_ci			case OCON_IBPKEY: {
233562306a36Sopenharmony_ci				u32 pkey_lo, pkey_hi;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci				rc = next_entry(prefixbuf, fp, sizeof(u64));
233862306a36Sopenharmony_ci				if (rc)
233962306a36Sopenharmony_ci					goto out;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci				/* we need to have subnet_prefix in CPU order */
234262306a36Sopenharmony_ci				c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32) * 2);
234562306a36Sopenharmony_ci				if (rc)
234662306a36Sopenharmony_ci					goto out;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci				pkey_lo = le32_to_cpu(buf[0]);
234962306a36Sopenharmony_ci				pkey_hi = le32_to_cpu(buf[1]);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci				if (pkey_lo > U16_MAX || pkey_hi > U16_MAX) {
235262306a36Sopenharmony_ci					rc = -EINVAL;
235362306a36Sopenharmony_ci					goto out;
235462306a36Sopenharmony_ci				}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci				c->u.ibpkey.low_pkey  = pkey_lo;
235762306a36Sopenharmony_ci				c->u.ibpkey.high_pkey = pkey_hi;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0],
236062306a36Sopenharmony_ci							       p,
236162306a36Sopenharmony_ci							       fp);
236262306a36Sopenharmony_ci				if (rc)
236362306a36Sopenharmony_ci					goto out;
236462306a36Sopenharmony_ci				break;
236562306a36Sopenharmony_ci			}
236662306a36Sopenharmony_ci			case OCON_IBENDPORT: {
236762306a36Sopenharmony_ci				u32 port;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci				rc = next_entry(buf, fp, sizeof(u32) * 2);
237062306a36Sopenharmony_ci				if (rc)
237162306a36Sopenharmony_ci					goto out;
237262306a36Sopenharmony_ci				len = le32_to_cpu(buf[0]);
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci				rc = str_read(&c->u.ibendport.dev_name, GFP_KERNEL, fp, len);
237562306a36Sopenharmony_ci				if (rc)
237662306a36Sopenharmony_ci					goto out;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci				port = le32_to_cpu(buf[1]);
237962306a36Sopenharmony_ci				if (port > U8_MAX || port == 0) {
238062306a36Sopenharmony_ci					rc = -EINVAL;
238162306a36Sopenharmony_ci					goto out;
238262306a36Sopenharmony_ci				}
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci				c->u.ibendport.port = port;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci				rc = context_read_and_validate(&c->context[0],
238762306a36Sopenharmony_ci							       p,
238862306a36Sopenharmony_ci							       fp);
238962306a36Sopenharmony_ci				if (rc)
239062306a36Sopenharmony_ci					goto out;
239162306a36Sopenharmony_ci				break;
239262306a36Sopenharmony_ci			} /* end case */
239362306a36Sopenharmony_ci			} /* end switch */
239462306a36Sopenharmony_ci		}
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci	rc = 0;
239762306a36Sopenharmony_ciout:
239862306a36Sopenharmony_ci	return rc;
239962306a36Sopenharmony_ci}
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci/*
240262306a36Sopenharmony_ci * Read the configuration data from a policy database binary
240362306a36Sopenharmony_ci * representation file into a policy database structure.
240462306a36Sopenharmony_ci */
240562306a36Sopenharmony_ciint policydb_read(struct policydb *p, void *fp)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	struct role_allow *ra, *lra;
240862306a36Sopenharmony_ci	struct role_trans_key *rtk = NULL;
240962306a36Sopenharmony_ci	struct role_trans_datum *rtd = NULL;
241062306a36Sopenharmony_ci	int rc;
241162306a36Sopenharmony_ci	__le32 buf[4];
241262306a36Sopenharmony_ci	u32 i, j, len, nprim, nel, perm;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	char *policydb_str;
241562306a36Sopenharmony_ci	const struct policydb_compat_info *info;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	policydb_init(p);
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci	/* Read the magic number and string length. */
242062306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32) * 2);
242162306a36Sopenharmony_ci	if (rc)
242262306a36Sopenharmony_ci		goto bad;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	rc = -EINVAL;
242562306a36Sopenharmony_ci	if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
242662306a36Sopenharmony_ci		pr_err("SELinux:  policydb magic number 0x%x does "
242762306a36Sopenharmony_ci		       "not match expected magic number 0x%x\n",
242862306a36Sopenharmony_ci		       le32_to_cpu(buf[0]), POLICYDB_MAGIC);
242962306a36Sopenharmony_ci		goto bad;
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	rc = -EINVAL;
243362306a36Sopenharmony_ci	len = le32_to_cpu(buf[1]);
243462306a36Sopenharmony_ci	if (len != strlen(POLICYDB_STRING)) {
243562306a36Sopenharmony_ci		pr_err("SELinux:  policydb string length %d does not "
243662306a36Sopenharmony_ci		       "match expected length %zu\n",
243762306a36Sopenharmony_ci		       len, strlen(POLICYDB_STRING));
243862306a36Sopenharmony_ci		goto bad;
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	rc = -ENOMEM;
244262306a36Sopenharmony_ci	policydb_str = kmalloc(len + 1, GFP_KERNEL);
244362306a36Sopenharmony_ci	if (!policydb_str) {
244462306a36Sopenharmony_ci		pr_err("SELinux:  unable to allocate memory for policydb "
244562306a36Sopenharmony_ci		       "string of length %d\n", len);
244662306a36Sopenharmony_ci		goto bad;
244762306a36Sopenharmony_ci	}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	rc = next_entry(policydb_str, fp, len);
245062306a36Sopenharmony_ci	if (rc) {
245162306a36Sopenharmony_ci		pr_err("SELinux:  truncated policydb string identifier\n");
245262306a36Sopenharmony_ci		kfree(policydb_str);
245362306a36Sopenharmony_ci		goto bad;
245462306a36Sopenharmony_ci	}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	rc = -EINVAL;
245762306a36Sopenharmony_ci	policydb_str[len] = '\0';
245862306a36Sopenharmony_ci	if (strcmp(policydb_str, POLICYDB_STRING)) {
245962306a36Sopenharmony_ci		pr_err("SELinux:  policydb string %s does not match "
246062306a36Sopenharmony_ci		       "my string %s\n", policydb_str, POLICYDB_STRING);
246162306a36Sopenharmony_ci		kfree(policydb_str);
246262306a36Sopenharmony_ci		goto bad;
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci	/* Done with policydb_str. */
246562306a36Sopenharmony_ci	kfree(policydb_str);
246662306a36Sopenharmony_ci	policydb_str = NULL;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	/* Read the version and table sizes. */
246962306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32)*4);
247062306a36Sopenharmony_ci	if (rc)
247162306a36Sopenharmony_ci		goto bad;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	rc = -EINVAL;
247462306a36Sopenharmony_ci	p->policyvers = le32_to_cpu(buf[0]);
247562306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_MIN ||
247662306a36Sopenharmony_ci	    p->policyvers > POLICYDB_VERSION_MAX) {
247762306a36Sopenharmony_ci		pr_err("SELinux:  policydb version %d does not match "
247862306a36Sopenharmony_ci		       "my version range %d-%d\n",
247962306a36Sopenharmony_ci		       le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
248062306a36Sopenharmony_ci		goto bad;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
248462306a36Sopenharmony_ci		p->mls_enabled = 1;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci		rc = -EINVAL;
248762306a36Sopenharmony_ci		if (p->policyvers < POLICYDB_VERSION_MLS) {
248862306a36Sopenharmony_ci			pr_err("SELinux: security policydb version %d "
248962306a36Sopenharmony_ci				"(MLS) not backwards compatible\n",
249062306a36Sopenharmony_ci				p->policyvers);
249162306a36Sopenharmony_ci			goto bad;
249262306a36Sopenharmony_ci		}
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci	p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
249562306a36Sopenharmony_ci	p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
249862306a36Sopenharmony_ci		rc = ebitmap_read(&p->policycaps, fp);
249962306a36Sopenharmony_ci		if (rc)
250062306a36Sopenharmony_ci			goto bad;
250162306a36Sopenharmony_ci	}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
250462306a36Sopenharmony_ci		rc = ebitmap_read(&p->permissive_map, fp);
250562306a36Sopenharmony_ci		if (rc)
250662306a36Sopenharmony_ci			goto bad;
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	rc = -EINVAL;
251062306a36Sopenharmony_ci	info = policydb_lookup_compat(p->policyvers);
251162306a36Sopenharmony_ci	if (!info) {
251262306a36Sopenharmony_ci		pr_err("SELinux:  unable to find policy compat info "
251362306a36Sopenharmony_ci		       "for version %d\n", p->policyvers);
251462306a36Sopenharmony_ci		goto bad;
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	rc = -EINVAL;
251862306a36Sopenharmony_ci	if (le32_to_cpu(buf[2]) != info->sym_num ||
251962306a36Sopenharmony_ci		le32_to_cpu(buf[3]) != info->ocon_num) {
252062306a36Sopenharmony_ci		pr_err("SELinux:  policydb table sizes (%d,%d) do "
252162306a36Sopenharmony_ci		       "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
252262306a36Sopenharmony_ci			le32_to_cpu(buf[3]),
252362306a36Sopenharmony_ci		       info->sym_num, info->ocon_num);
252462306a36Sopenharmony_ci		goto bad;
252562306a36Sopenharmony_ci	}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	for (i = 0; i < info->sym_num; i++) {
252862306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32)*2);
252962306a36Sopenharmony_ci		if (rc)
253062306a36Sopenharmony_ci			goto bad;
253162306a36Sopenharmony_ci		nprim = le32_to_cpu(buf[0]);
253262306a36Sopenharmony_ci		nel = le32_to_cpu(buf[1]);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		rc = symtab_init(&p->symtab[i], nel);
253562306a36Sopenharmony_ci		if (rc)
253662306a36Sopenharmony_ci			goto out;
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci		if (i == SYM_ROLES) {
253962306a36Sopenharmony_ci			rc = roles_init(p);
254062306a36Sopenharmony_ci			if (rc)
254162306a36Sopenharmony_ci				goto out;
254262306a36Sopenharmony_ci		}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci		for (j = 0; j < nel; j++) {
254562306a36Sopenharmony_ci			rc = read_f[i](p, &p->symtab[i], fp);
254662306a36Sopenharmony_ci			if (rc)
254762306a36Sopenharmony_ci				goto bad;
254862306a36Sopenharmony_ci		}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci		p->symtab[i].nprim = nprim;
255162306a36Sopenharmony_ci	}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	rc = -EINVAL;
255462306a36Sopenharmony_ci	p->process_class = string_to_security_class(p, "process");
255562306a36Sopenharmony_ci	if (!p->process_class) {
255662306a36Sopenharmony_ci		pr_err("SELinux: process class is required, not defined in policy\n");
255762306a36Sopenharmony_ci		goto bad;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	rc = avtab_read(&p->te_avtab, fp, p);
256162306a36Sopenharmony_ci	if (rc)
256262306a36Sopenharmony_ci		goto bad;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOOL) {
256562306a36Sopenharmony_ci		rc = cond_read_list(p, fp);
256662306a36Sopenharmony_ci		if (rc)
256762306a36Sopenharmony_ci			goto bad;
256862306a36Sopenharmony_ci	}
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
257162306a36Sopenharmony_ci	if (rc)
257262306a36Sopenharmony_ci		goto bad;
257362306a36Sopenharmony_ci	nel = le32_to_cpu(buf[0]);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	rc = hashtab_init(&p->role_tr, nel);
257662306a36Sopenharmony_ci	if (rc)
257762306a36Sopenharmony_ci		goto bad;
257862306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
257962306a36Sopenharmony_ci		rc = -ENOMEM;
258062306a36Sopenharmony_ci		rtk = kmalloc(sizeof(*rtk), GFP_KERNEL);
258162306a36Sopenharmony_ci		if (!rtk)
258262306a36Sopenharmony_ci			goto bad;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci		rc = -ENOMEM;
258562306a36Sopenharmony_ci		rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
258662306a36Sopenharmony_ci		if (!rtd)
258762306a36Sopenharmony_ci			goto bad;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32)*3);
259062306a36Sopenharmony_ci		if (rc)
259162306a36Sopenharmony_ci			goto bad;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci		rtk->role = le32_to_cpu(buf[0]);
259462306a36Sopenharmony_ci		rtk->type = le32_to_cpu(buf[1]);
259562306a36Sopenharmony_ci		rtd->new_role = le32_to_cpu(buf[2]);
259662306a36Sopenharmony_ci		if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
259762306a36Sopenharmony_ci			rc = next_entry(buf, fp, sizeof(u32));
259862306a36Sopenharmony_ci			if (rc)
259962306a36Sopenharmony_ci				goto bad;
260062306a36Sopenharmony_ci			rtk->tclass = le32_to_cpu(buf[0]);
260162306a36Sopenharmony_ci		} else
260262306a36Sopenharmony_ci			rtk->tclass = p->process_class;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci		rc = -EINVAL;
260562306a36Sopenharmony_ci		if (!policydb_role_isvalid(p, rtk->role) ||
260662306a36Sopenharmony_ci		    !policydb_type_isvalid(p, rtk->type) ||
260762306a36Sopenharmony_ci		    !policydb_class_isvalid(p, rtk->tclass) ||
260862306a36Sopenharmony_ci		    !policydb_role_isvalid(p, rtd->new_role))
260962306a36Sopenharmony_ci			goto bad;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci		rc = hashtab_insert(&p->role_tr, rtk, rtd, roletr_key_params);
261262306a36Sopenharmony_ci		if (rc)
261362306a36Sopenharmony_ci			goto bad;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci		rtk = NULL;
261662306a36Sopenharmony_ci		rtd = NULL;
261762306a36Sopenharmony_ci	}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	rc = next_entry(buf, fp, sizeof(u32));
262062306a36Sopenharmony_ci	if (rc)
262162306a36Sopenharmony_ci		goto bad;
262262306a36Sopenharmony_ci	nel = le32_to_cpu(buf[0]);
262362306a36Sopenharmony_ci	lra = NULL;
262462306a36Sopenharmony_ci	for (i = 0; i < nel; i++) {
262562306a36Sopenharmony_ci		rc = -ENOMEM;
262662306a36Sopenharmony_ci		ra = kzalloc(sizeof(*ra), GFP_KERNEL);
262762306a36Sopenharmony_ci		if (!ra)
262862306a36Sopenharmony_ci			goto bad;
262962306a36Sopenharmony_ci		if (lra)
263062306a36Sopenharmony_ci			lra->next = ra;
263162306a36Sopenharmony_ci		else
263262306a36Sopenharmony_ci			p->role_allow = ra;
263362306a36Sopenharmony_ci		rc = next_entry(buf, fp, sizeof(u32)*2);
263462306a36Sopenharmony_ci		if (rc)
263562306a36Sopenharmony_ci			goto bad;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci		rc = -EINVAL;
263862306a36Sopenharmony_ci		ra->role = le32_to_cpu(buf[0]);
263962306a36Sopenharmony_ci		ra->new_role = le32_to_cpu(buf[1]);
264062306a36Sopenharmony_ci		if (!policydb_role_isvalid(p, ra->role) ||
264162306a36Sopenharmony_ci		    !policydb_role_isvalid(p, ra->new_role))
264262306a36Sopenharmony_ci			goto bad;
264362306a36Sopenharmony_ci		lra = ra;
264462306a36Sopenharmony_ci	}
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	rc = filename_trans_read(p, fp);
264762306a36Sopenharmony_ci	if (rc)
264862306a36Sopenharmony_ci		goto bad;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci	rc = policydb_index(p);
265162306a36Sopenharmony_ci	if (rc)
265262306a36Sopenharmony_ci		goto bad;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	rc = -EINVAL;
265562306a36Sopenharmony_ci	perm = string_to_av_perm(p, p->process_class, "transition");
265662306a36Sopenharmony_ci	if (!perm) {
265762306a36Sopenharmony_ci		pr_err("SELinux: process transition permission is required, not defined in policy\n");
265862306a36Sopenharmony_ci		goto bad;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci	p->process_trans_perms = perm;
266162306a36Sopenharmony_ci	perm = string_to_av_perm(p, p->process_class, "dyntransition");
266262306a36Sopenharmony_ci	if (!perm) {
266362306a36Sopenharmony_ci		pr_err("SELinux: process dyntransition permission is required, not defined in policy\n");
266462306a36Sopenharmony_ci		goto bad;
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci	p->process_trans_perms |= perm;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	rc = ocontext_read(p, info, fp);
266962306a36Sopenharmony_ci	if (rc)
267062306a36Sopenharmony_ci		goto bad;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	rc = genfs_read(p, fp);
267362306a36Sopenharmony_ci	if (rc)
267462306a36Sopenharmony_ci		goto bad;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	rc = range_read(p, fp);
267762306a36Sopenharmony_ci	if (rc)
267862306a36Sopenharmony_ci		goto bad;
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	rc = -ENOMEM;
268162306a36Sopenharmony_ci	p->type_attr_map_array = kvcalloc(p->p_types.nprim,
268262306a36Sopenharmony_ci					  sizeof(*p->type_attr_map_array),
268362306a36Sopenharmony_ci					  GFP_KERNEL);
268462306a36Sopenharmony_ci	if (!p->type_attr_map_array)
268562306a36Sopenharmony_ci		goto bad;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	/* just in case ebitmap_init() becomes more than just a memset(0): */
268862306a36Sopenharmony_ci	for (i = 0; i < p->p_types.nprim; i++)
268962306a36Sopenharmony_ci		ebitmap_init(&p->type_attr_map_array[i]);
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	for (i = 0; i < p->p_types.nprim; i++) {
269262306a36Sopenharmony_ci		struct ebitmap *e = &p->type_attr_map_array[i];
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci		if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
269562306a36Sopenharmony_ci			rc = ebitmap_read(e, fp);
269662306a36Sopenharmony_ci			if (rc)
269762306a36Sopenharmony_ci				goto bad;
269862306a36Sopenharmony_ci		}
269962306a36Sopenharmony_ci		/* add the type itself as the degenerate case */
270062306a36Sopenharmony_ci		rc = ebitmap_set_bit(e, i, 1);
270162306a36Sopenharmony_ci		if (rc)
270262306a36Sopenharmony_ci			goto bad;
270362306a36Sopenharmony_ci	}
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	rc = policydb_bounds_sanity_check(p);
270662306a36Sopenharmony_ci	if (rc)
270762306a36Sopenharmony_ci		goto bad;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	rc = 0;
271062306a36Sopenharmony_ciout:
271162306a36Sopenharmony_ci	return rc;
271262306a36Sopenharmony_cibad:
271362306a36Sopenharmony_ci	kfree(rtk);
271462306a36Sopenharmony_ci	kfree(rtd);
271562306a36Sopenharmony_ci	policydb_destroy(p);
271662306a36Sopenharmony_ci	goto out;
271762306a36Sopenharmony_ci}
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci/*
272062306a36Sopenharmony_ci * Write a MLS level structure to a policydb binary
272162306a36Sopenharmony_ci * representation file.
272262306a36Sopenharmony_ci */
272362306a36Sopenharmony_cistatic int mls_write_level(struct mls_level *l, void *fp)
272462306a36Sopenharmony_ci{
272562306a36Sopenharmony_ci	__le32 buf[1];
272662306a36Sopenharmony_ci	int rc;
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	buf[0] = cpu_to_le32(l->sens);
272962306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
273062306a36Sopenharmony_ci	if (rc)
273162306a36Sopenharmony_ci		return rc;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	rc = ebitmap_write(&l->cat, fp);
273462306a36Sopenharmony_ci	if (rc)
273562306a36Sopenharmony_ci		return rc;
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	return 0;
273862306a36Sopenharmony_ci}
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci/*
274162306a36Sopenharmony_ci * Write a MLS range structure to a policydb binary
274262306a36Sopenharmony_ci * representation file.
274362306a36Sopenharmony_ci */
274462306a36Sopenharmony_cistatic int mls_write_range_helper(struct mls_range *r, void *fp)
274562306a36Sopenharmony_ci{
274662306a36Sopenharmony_ci	__le32 buf[3];
274762306a36Sopenharmony_ci	size_t items;
274862306a36Sopenharmony_ci	int rc, eq;
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	eq = mls_level_eq(&r->level[1], &r->level[0]);
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	if (eq)
275362306a36Sopenharmony_ci		items = 2;
275462306a36Sopenharmony_ci	else
275562306a36Sopenharmony_ci		items = 3;
275662306a36Sopenharmony_ci	buf[0] = cpu_to_le32(items-1);
275762306a36Sopenharmony_ci	buf[1] = cpu_to_le32(r->level[0].sens);
275862306a36Sopenharmony_ci	if (!eq)
275962306a36Sopenharmony_ci		buf[2] = cpu_to_le32(r->level[1].sens);
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	BUG_ON(items > ARRAY_SIZE(buf));
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), items, fp);
276462306a36Sopenharmony_ci	if (rc)
276562306a36Sopenharmony_ci		return rc;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	rc = ebitmap_write(&r->level[0].cat, fp);
276862306a36Sopenharmony_ci	if (rc)
276962306a36Sopenharmony_ci		return rc;
277062306a36Sopenharmony_ci	if (!eq) {
277162306a36Sopenharmony_ci		rc = ebitmap_write(&r->level[1].cat, fp);
277262306a36Sopenharmony_ci		if (rc)
277362306a36Sopenharmony_ci			return rc;
277462306a36Sopenharmony_ci	}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	return 0;
277762306a36Sopenharmony_ci}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_cistatic int sens_write(void *vkey, void *datum, void *ptr)
278062306a36Sopenharmony_ci{
278162306a36Sopenharmony_ci	char *key = vkey;
278262306a36Sopenharmony_ci	struct level_datum *levdatum = datum;
278362306a36Sopenharmony_ci	struct policy_data *pd = ptr;
278462306a36Sopenharmony_ci	void *fp = pd->fp;
278562306a36Sopenharmony_ci	__le32 buf[2];
278662306a36Sopenharmony_ci	size_t len;
278762306a36Sopenharmony_ci	int rc;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	len = strlen(key);
279062306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
279162306a36Sopenharmony_ci	buf[1] = cpu_to_le32(levdatum->isalias);
279262306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 2, fp);
279362306a36Sopenharmony_ci	if (rc)
279462306a36Sopenharmony_ci		return rc;
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
279762306a36Sopenharmony_ci	if (rc)
279862306a36Sopenharmony_ci		return rc;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	rc = mls_write_level(levdatum->level, fp);
280162306a36Sopenharmony_ci	if (rc)
280262306a36Sopenharmony_ci		return rc;
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	return 0;
280562306a36Sopenharmony_ci}
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_cistatic int cat_write(void *vkey, void *datum, void *ptr)
280862306a36Sopenharmony_ci{
280962306a36Sopenharmony_ci	char *key = vkey;
281062306a36Sopenharmony_ci	struct cat_datum *catdatum = datum;
281162306a36Sopenharmony_ci	struct policy_data *pd = ptr;
281262306a36Sopenharmony_ci	void *fp = pd->fp;
281362306a36Sopenharmony_ci	__le32 buf[3];
281462306a36Sopenharmony_ci	size_t len;
281562306a36Sopenharmony_ci	int rc;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	len = strlen(key);
281862306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
281962306a36Sopenharmony_ci	buf[1] = cpu_to_le32(catdatum->value);
282062306a36Sopenharmony_ci	buf[2] = cpu_to_le32(catdatum->isalias);
282162306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 3, fp);
282262306a36Sopenharmony_ci	if (rc)
282362306a36Sopenharmony_ci		return rc;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
282662306a36Sopenharmony_ci	if (rc)
282762306a36Sopenharmony_ci		return rc;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	return 0;
283062306a36Sopenharmony_ci}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_cistatic int role_trans_write_one(void *key, void *datum, void *ptr)
283362306a36Sopenharmony_ci{
283462306a36Sopenharmony_ci	struct role_trans_key *rtk = key;
283562306a36Sopenharmony_ci	struct role_trans_datum *rtd = datum;
283662306a36Sopenharmony_ci	struct policy_data *pd = ptr;
283762306a36Sopenharmony_ci	void *fp = pd->fp;
283862306a36Sopenharmony_ci	struct policydb *p = pd->p;
283962306a36Sopenharmony_ci	__le32 buf[3];
284062306a36Sopenharmony_ci	int rc;
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	buf[0] = cpu_to_le32(rtk->role);
284362306a36Sopenharmony_ci	buf[1] = cpu_to_le32(rtk->type);
284462306a36Sopenharmony_ci	buf[2] = cpu_to_le32(rtd->new_role);
284562306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 3, fp);
284662306a36Sopenharmony_ci	if (rc)
284762306a36Sopenharmony_ci		return rc;
284862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
284962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(rtk->tclass);
285062306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
285162306a36Sopenharmony_ci		if (rc)
285262306a36Sopenharmony_ci			return rc;
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci	return 0;
285562306a36Sopenharmony_ci}
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_cistatic int role_trans_write(struct policydb *p, void *fp)
285862306a36Sopenharmony_ci{
285962306a36Sopenharmony_ci	struct policy_data pd = { .p = p, .fp = fp };
286062306a36Sopenharmony_ci	__le32 buf[1];
286162306a36Sopenharmony_ci	int rc;
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	buf[0] = cpu_to_le32(p->role_tr.nel);
286462306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
286562306a36Sopenharmony_ci	if (rc)
286662306a36Sopenharmony_ci		return rc;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	return hashtab_map(&p->role_tr, role_trans_write_one, &pd);
286962306a36Sopenharmony_ci}
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_cistatic int role_allow_write(struct role_allow *r, void *fp)
287262306a36Sopenharmony_ci{
287362306a36Sopenharmony_ci	struct role_allow *ra;
287462306a36Sopenharmony_ci	__le32 buf[2];
287562306a36Sopenharmony_ci	size_t nel;
287662306a36Sopenharmony_ci	int rc;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	nel = 0;
287962306a36Sopenharmony_ci	for (ra = r; ra; ra = ra->next)
288062306a36Sopenharmony_ci		nel++;
288162306a36Sopenharmony_ci	buf[0] = cpu_to_le32(nel);
288262306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
288362306a36Sopenharmony_ci	if (rc)
288462306a36Sopenharmony_ci		return rc;
288562306a36Sopenharmony_ci	for (ra = r; ra; ra = ra->next) {
288662306a36Sopenharmony_ci		buf[0] = cpu_to_le32(ra->role);
288762306a36Sopenharmony_ci		buf[1] = cpu_to_le32(ra->new_role);
288862306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 2, fp);
288962306a36Sopenharmony_ci		if (rc)
289062306a36Sopenharmony_ci			return rc;
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci	return 0;
289362306a36Sopenharmony_ci}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci/*
289662306a36Sopenharmony_ci * Write a security context structure
289762306a36Sopenharmony_ci * to a policydb binary representation file.
289862306a36Sopenharmony_ci */
289962306a36Sopenharmony_cistatic int context_write(struct policydb *p, struct context *c,
290062306a36Sopenharmony_ci			 void *fp)
290162306a36Sopenharmony_ci{
290262306a36Sopenharmony_ci	int rc;
290362306a36Sopenharmony_ci	__le32 buf[3];
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	buf[0] = cpu_to_le32(c->user);
290662306a36Sopenharmony_ci	buf[1] = cpu_to_le32(c->role);
290762306a36Sopenharmony_ci	buf[2] = cpu_to_le32(c->type);
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 3, fp);
291062306a36Sopenharmony_ci	if (rc)
291162306a36Sopenharmony_ci		return rc;
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	rc = mls_write_range_helper(&c->range, fp);
291462306a36Sopenharmony_ci	if (rc)
291562306a36Sopenharmony_ci		return rc;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	return 0;
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci/*
292162306a36Sopenharmony_ci * The following *_write functions are used to
292262306a36Sopenharmony_ci * write the symbol data to a policy database
292362306a36Sopenharmony_ci * binary representation file.
292462306a36Sopenharmony_ci */
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_cistatic int perm_write(void *vkey, void *datum, void *fp)
292762306a36Sopenharmony_ci{
292862306a36Sopenharmony_ci	char *key = vkey;
292962306a36Sopenharmony_ci	struct perm_datum *perdatum = datum;
293062306a36Sopenharmony_ci	__le32 buf[2];
293162306a36Sopenharmony_ci	size_t len;
293262306a36Sopenharmony_ci	int rc;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	len = strlen(key);
293562306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
293662306a36Sopenharmony_ci	buf[1] = cpu_to_le32(perdatum->value);
293762306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 2, fp);
293862306a36Sopenharmony_ci	if (rc)
293962306a36Sopenharmony_ci		return rc;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
294262306a36Sopenharmony_ci	if (rc)
294362306a36Sopenharmony_ci		return rc;
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	return 0;
294662306a36Sopenharmony_ci}
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_cistatic int common_write(void *vkey, void *datum, void *ptr)
294962306a36Sopenharmony_ci{
295062306a36Sopenharmony_ci	char *key = vkey;
295162306a36Sopenharmony_ci	struct common_datum *comdatum = datum;
295262306a36Sopenharmony_ci	struct policy_data *pd = ptr;
295362306a36Sopenharmony_ci	void *fp = pd->fp;
295462306a36Sopenharmony_ci	__le32 buf[4];
295562306a36Sopenharmony_ci	size_t len;
295662306a36Sopenharmony_ci	int rc;
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	len = strlen(key);
295962306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
296062306a36Sopenharmony_ci	buf[1] = cpu_to_le32(comdatum->value);
296162306a36Sopenharmony_ci	buf[2] = cpu_to_le32(comdatum->permissions.nprim);
296262306a36Sopenharmony_ci	buf[3] = cpu_to_le32(comdatum->permissions.table.nel);
296362306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 4, fp);
296462306a36Sopenharmony_ci	if (rc)
296562306a36Sopenharmony_ci		return rc;
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
296862306a36Sopenharmony_ci	if (rc)
296962306a36Sopenharmony_ci		return rc;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	rc = hashtab_map(&comdatum->permissions.table, perm_write, fp);
297262306a36Sopenharmony_ci	if (rc)
297362306a36Sopenharmony_ci		return rc;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	return 0;
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic int type_set_write(struct type_set *t, void *fp)
297962306a36Sopenharmony_ci{
298062306a36Sopenharmony_ci	int rc;
298162306a36Sopenharmony_ci	__le32 buf[1];
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	if (ebitmap_write(&t->types, fp))
298462306a36Sopenharmony_ci		return -EINVAL;
298562306a36Sopenharmony_ci	if (ebitmap_write(&t->negset, fp))
298662306a36Sopenharmony_ci		return -EINVAL;
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	buf[0] = cpu_to_le32(t->flags);
298962306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
299062306a36Sopenharmony_ci	if (rc)
299162306a36Sopenharmony_ci		return -EINVAL;
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	return 0;
299462306a36Sopenharmony_ci}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_cistatic int write_cons_helper(struct policydb *p, struct constraint_node *node,
299762306a36Sopenharmony_ci			     void *fp)
299862306a36Sopenharmony_ci{
299962306a36Sopenharmony_ci	struct constraint_node *c;
300062306a36Sopenharmony_ci	struct constraint_expr *e;
300162306a36Sopenharmony_ci	__le32 buf[3];
300262306a36Sopenharmony_ci	u32 nel;
300362306a36Sopenharmony_ci	int rc;
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	for (c = node; c; c = c->next) {
300662306a36Sopenharmony_ci		nel = 0;
300762306a36Sopenharmony_ci		for (e = c->expr; e; e = e->next)
300862306a36Sopenharmony_ci			nel++;
300962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(c->permissions);
301062306a36Sopenharmony_ci		buf[1] = cpu_to_le32(nel);
301162306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 2, fp);
301262306a36Sopenharmony_ci		if (rc)
301362306a36Sopenharmony_ci			return rc;
301462306a36Sopenharmony_ci		for (e = c->expr; e; e = e->next) {
301562306a36Sopenharmony_ci			buf[0] = cpu_to_le32(e->expr_type);
301662306a36Sopenharmony_ci			buf[1] = cpu_to_le32(e->attr);
301762306a36Sopenharmony_ci			buf[2] = cpu_to_le32(e->op);
301862306a36Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 3, fp);
301962306a36Sopenharmony_ci			if (rc)
302062306a36Sopenharmony_ci				return rc;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci			switch (e->expr_type) {
302362306a36Sopenharmony_ci			case CEXPR_NAMES:
302462306a36Sopenharmony_ci				rc = ebitmap_write(&e->names, fp);
302562306a36Sopenharmony_ci				if (rc)
302662306a36Sopenharmony_ci					return rc;
302762306a36Sopenharmony_ci				if (p->policyvers >=
302862306a36Sopenharmony_ci					POLICYDB_VERSION_CONSTRAINT_NAMES) {
302962306a36Sopenharmony_ci					rc = type_set_write(e->type_names, fp);
303062306a36Sopenharmony_ci					if (rc)
303162306a36Sopenharmony_ci						return rc;
303262306a36Sopenharmony_ci				}
303362306a36Sopenharmony_ci				break;
303462306a36Sopenharmony_ci			default:
303562306a36Sopenharmony_ci				break;
303662306a36Sopenharmony_ci			}
303762306a36Sopenharmony_ci		}
303862306a36Sopenharmony_ci	}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	return 0;
304162306a36Sopenharmony_ci}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_cistatic int class_write(void *vkey, void *datum, void *ptr)
304462306a36Sopenharmony_ci{
304562306a36Sopenharmony_ci	char *key = vkey;
304662306a36Sopenharmony_ci	struct class_datum *cladatum = datum;
304762306a36Sopenharmony_ci	struct policy_data *pd = ptr;
304862306a36Sopenharmony_ci	void *fp = pd->fp;
304962306a36Sopenharmony_ci	struct policydb *p = pd->p;
305062306a36Sopenharmony_ci	struct constraint_node *c;
305162306a36Sopenharmony_ci	__le32 buf[6];
305262306a36Sopenharmony_ci	u32 ncons;
305362306a36Sopenharmony_ci	size_t len, len2;
305462306a36Sopenharmony_ci	int rc;
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	len = strlen(key);
305762306a36Sopenharmony_ci	if (cladatum->comkey)
305862306a36Sopenharmony_ci		len2 = strlen(cladatum->comkey);
305962306a36Sopenharmony_ci	else
306062306a36Sopenharmony_ci		len2 = 0;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	ncons = 0;
306362306a36Sopenharmony_ci	for (c = cladatum->constraints; c; c = c->next)
306462306a36Sopenharmony_ci		ncons++;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
306762306a36Sopenharmony_ci	buf[1] = cpu_to_le32(len2);
306862306a36Sopenharmony_ci	buf[2] = cpu_to_le32(cladatum->value);
306962306a36Sopenharmony_ci	buf[3] = cpu_to_le32(cladatum->permissions.nprim);
307062306a36Sopenharmony_ci	buf[4] = cpu_to_le32(cladatum->permissions.table.nel);
307162306a36Sopenharmony_ci	buf[5] = cpu_to_le32(ncons);
307262306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 6, fp);
307362306a36Sopenharmony_ci	if (rc)
307462306a36Sopenharmony_ci		return rc;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
307762306a36Sopenharmony_ci	if (rc)
307862306a36Sopenharmony_ci		return rc;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	if (cladatum->comkey) {
308162306a36Sopenharmony_ci		rc = put_entry(cladatum->comkey, 1, len2, fp);
308262306a36Sopenharmony_ci		if (rc)
308362306a36Sopenharmony_ci			return rc;
308462306a36Sopenharmony_ci	}
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	rc = hashtab_map(&cladatum->permissions.table, perm_write, fp);
308762306a36Sopenharmony_ci	if (rc)
308862306a36Sopenharmony_ci		return rc;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	rc = write_cons_helper(p, cladatum->constraints, fp);
309162306a36Sopenharmony_ci	if (rc)
309262306a36Sopenharmony_ci		return rc;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	/* write out the validatetrans rule */
309562306a36Sopenharmony_ci	ncons = 0;
309662306a36Sopenharmony_ci	for (c = cladatum->validatetrans; c; c = c->next)
309762306a36Sopenharmony_ci		ncons++;
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	buf[0] = cpu_to_le32(ncons);
310062306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
310162306a36Sopenharmony_ci	if (rc)
310262306a36Sopenharmony_ci		return rc;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	rc = write_cons_helper(p, cladatum->validatetrans, fp);
310562306a36Sopenharmony_ci	if (rc)
310662306a36Sopenharmony_ci		return rc;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
310962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(cladatum->default_user);
311062306a36Sopenharmony_ci		buf[1] = cpu_to_le32(cladatum->default_role);
311162306a36Sopenharmony_ci		buf[2] = cpu_to_le32(cladatum->default_range);
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(uint32_t), 3, fp);
311462306a36Sopenharmony_ci		if (rc)
311562306a36Sopenharmony_ci			return rc;
311662306a36Sopenharmony_ci	}
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
311962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(cladatum->default_type);
312062306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(uint32_t), 1, fp);
312162306a36Sopenharmony_ci		if (rc)
312262306a36Sopenharmony_ci			return rc;
312362306a36Sopenharmony_ci	}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	return 0;
312662306a36Sopenharmony_ci}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_cistatic int role_write(void *vkey, void *datum, void *ptr)
312962306a36Sopenharmony_ci{
313062306a36Sopenharmony_ci	char *key = vkey;
313162306a36Sopenharmony_ci	struct role_datum *role = datum;
313262306a36Sopenharmony_ci	struct policy_data *pd = ptr;
313362306a36Sopenharmony_ci	void *fp = pd->fp;
313462306a36Sopenharmony_ci	struct policydb *p = pd->p;
313562306a36Sopenharmony_ci	__le32 buf[3];
313662306a36Sopenharmony_ci	size_t items, len;
313762306a36Sopenharmony_ci	int rc;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	len = strlen(key);
314062306a36Sopenharmony_ci	items = 0;
314162306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(len);
314262306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(role->value);
314362306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
314462306a36Sopenharmony_ci		buf[items++] = cpu_to_le32(role->bounds);
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	BUG_ON(items > ARRAY_SIZE(buf));
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), items, fp);
314962306a36Sopenharmony_ci	if (rc)
315062306a36Sopenharmony_ci		return rc;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
315362306a36Sopenharmony_ci	if (rc)
315462306a36Sopenharmony_ci		return rc;
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	rc = ebitmap_write(&role->dominates, fp);
315762306a36Sopenharmony_ci	if (rc)
315862306a36Sopenharmony_ci		return rc;
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	rc = ebitmap_write(&role->types, fp);
316162306a36Sopenharmony_ci	if (rc)
316262306a36Sopenharmony_ci		return rc;
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	return 0;
316562306a36Sopenharmony_ci}
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_cistatic int type_write(void *vkey, void *datum, void *ptr)
316862306a36Sopenharmony_ci{
316962306a36Sopenharmony_ci	char *key = vkey;
317062306a36Sopenharmony_ci	struct type_datum *typdatum = datum;
317162306a36Sopenharmony_ci	struct policy_data *pd = ptr;
317262306a36Sopenharmony_ci	struct policydb *p = pd->p;
317362306a36Sopenharmony_ci	void *fp = pd->fp;
317462306a36Sopenharmony_ci	__le32 buf[4];
317562306a36Sopenharmony_ci	int rc;
317662306a36Sopenharmony_ci	size_t items, len;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	len = strlen(key);
317962306a36Sopenharmony_ci	items = 0;
318062306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(len);
318162306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(typdatum->value);
318262306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
318362306a36Sopenharmony_ci		u32 properties = 0;
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci		if (typdatum->primary)
318662306a36Sopenharmony_ci			properties |= TYPEDATUM_PROPERTY_PRIMARY;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci		if (typdatum->attribute)
318962306a36Sopenharmony_ci			properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci		buf[items++] = cpu_to_le32(properties);
319262306a36Sopenharmony_ci		buf[items++] = cpu_to_le32(typdatum->bounds);
319362306a36Sopenharmony_ci	} else {
319462306a36Sopenharmony_ci		buf[items++] = cpu_to_le32(typdatum->primary);
319562306a36Sopenharmony_ci	}
319662306a36Sopenharmony_ci	BUG_ON(items > ARRAY_SIZE(buf));
319762306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), items, fp);
319862306a36Sopenharmony_ci	if (rc)
319962306a36Sopenharmony_ci		return rc;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
320262306a36Sopenharmony_ci	if (rc)
320362306a36Sopenharmony_ci		return rc;
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	return 0;
320662306a36Sopenharmony_ci}
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_cistatic int user_write(void *vkey, void *datum, void *ptr)
320962306a36Sopenharmony_ci{
321062306a36Sopenharmony_ci	char *key = vkey;
321162306a36Sopenharmony_ci	struct user_datum *usrdatum = datum;
321262306a36Sopenharmony_ci	struct policy_data *pd = ptr;
321362306a36Sopenharmony_ci	struct policydb *p = pd->p;
321462306a36Sopenharmony_ci	void *fp = pd->fp;
321562306a36Sopenharmony_ci	__le32 buf[3];
321662306a36Sopenharmony_ci	size_t items, len;
321762306a36Sopenharmony_ci	int rc;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	len = strlen(key);
322062306a36Sopenharmony_ci	items = 0;
322162306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(len);
322262306a36Sopenharmony_ci	buf[items++] = cpu_to_le32(usrdatum->value);
322362306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
322462306a36Sopenharmony_ci		buf[items++] = cpu_to_le32(usrdatum->bounds);
322562306a36Sopenharmony_ci	BUG_ON(items > ARRAY_SIZE(buf));
322662306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), items, fp);
322762306a36Sopenharmony_ci	if (rc)
322862306a36Sopenharmony_ci		return rc;
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	rc = put_entry(key, 1, len, fp);
323162306a36Sopenharmony_ci	if (rc)
323262306a36Sopenharmony_ci		return rc;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	rc = ebitmap_write(&usrdatum->roles, fp);
323562306a36Sopenharmony_ci	if (rc)
323662306a36Sopenharmony_ci		return rc;
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ci	rc = mls_write_range_helper(&usrdatum->range, fp);
323962306a36Sopenharmony_ci	if (rc)
324062306a36Sopenharmony_ci		return rc;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	rc = mls_write_level(&usrdatum->dfltlevel, fp);
324362306a36Sopenharmony_ci	if (rc)
324462306a36Sopenharmony_ci		return rc;
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	return 0;
324762306a36Sopenharmony_ci}
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_cistatic int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
325062306a36Sopenharmony_ci	common_write,
325162306a36Sopenharmony_ci	class_write,
325262306a36Sopenharmony_ci	role_write,
325362306a36Sopenharmony_ci	type_write,
325462306a36Sopenharmony_ci	user_write,
325562306a36Sopenharmony_ci	cond_write_bool,
325662306a36Sopenharmony_ci	sens_write,
325762306a36Sopenharmony_ci	cat_write,
325862306a36Sopenharmony_ci};
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_cistatic int ocontext_write(struct policydb *p, const struct policydb_compat_info *info,
326162306a36Sopenharmony_ci			  void *fp)
326262306a36Sopenharmony_ci{
326362306a36Sopenharmony_ci	unsigned int i, j;
326462306a36Sopenharmony_ci	int rc;
326562306a36Sopenharmony_ci	size_t nel, len;
326662306a36Sopenharmony_ci	__be64 prefixbuf[1];
326762306a36Sopenharmony_ci	__le32 buf[3];
326862306a36Sopenharmony_ci	u32 nodebuf[8];
326962306a36Sopenharmony_ci	struct ocontext *c;
327062306a36Sopenharmony_ci	for (i = 0; i < info->ocon_num; i++) {
327162306a36Sopenharmony_ci		nel = 0;
327262306a36Sopenharmony_ci		for (c = p->ocontexts[i]; c; c = c->next)
327362306a36Sopenharmony_ci			nel++;
327462306a36Sopenharmony_ci		buf[0] = cpu_to_le32(nel);
327562306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
327662306a36Sopenharmony_ci		if (rc)
327762306a36Sopenharmony_ci			return rc;
327862306a36Sopenharmony_ci		for (c = p->ocontexts[i]; c; c = c->next) {
327962306a36Sopenharmony_ci			switch (i) {
328062306a36Sopenharmony_ci			case OCON_ISID:
328162306a36Sopenharmony_ci				buf[0] = cpu_to_le32(c->sid[0]);
328262306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 1, fp);
328362306a36Sopenharmony_ci				if (rc)
328462306a36Sopenharmony_ci					return rc;
328562306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
328662306a36Sopenharmony_ci				if (rc)
328762306a36Sopenharmony_ci					return rc;
328862306a36Sopenharmony_ci				break;
328962306a36Sopenharmony_ci			case OCON_FS:
329062306a36Sopenharmony_ci			case OCON_NETIF:
329162306a36Sopenharmony_ci				len = strlen(c->u.name);
329262306a36Sopenharmony_ci				buf[0] = cpu_to_le32(len);
329362306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 1, fp);
329462306a36Sopenharmony_ci				if (rc)
329562306a36Sopenharmony_ci					return rc;
329662306a36Sopenharmony_ci				rc = put_entry(c->u.name, 1, len, fp);
329762306a36Sopenharmony_ci				if (rc)
329862306a36Sopenharmony_ci					return rc;
329962306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
330062306a36Sopenharmony_ci				if (rc)
330162306a36Sopenharmony_ci					return rc;
330262306a36Sopenharmony_ci				rc = context_write(p, &c->context[1], fp);
330362306a36Sopenharmony_ci				if (rc)
330462306a36Sopenharmony_ci					return rc;
330562306a36Sopenharmony_ci				break;
330662306a36Sopenharmony_ci			case OCON_PORT:
330762306a36Sopenharmony_ci				buf[0] = cpu_to_le32(c->u.port.protocol);
330862306a36Sopenharmony_ci				buf[1] = cpu_to_le32(c->u.port.low_port);
330962306a36Sopenharmony_ci				buf[2] = cpu_to_le32(c->u.port.high_port);
331062306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 3, fp);
331162306a36Sopenharmony_ci				if (rc)
331262306a36Sopenharmony_ci					return rc;
331362306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
331462306a36Sopenharmony_ci				if (rc)
331562306a36Sopenharmony_ci					return rc;
331662306a36Sopenharmony_ci				break;
331762306a36Sopenharmony_ci			case OCON_NODE:
331862306a36Sopenharmony_ci				nodebuf[0] = c->u.node.addr; /* network order */
331962306a36Sopenharmony_ci				nodebuf[1] = c->u.node.mask; /* network order */
332062306a36Sopenharmony_ci				rc = put_entry(nodebuf, sizeof(u32), 2, fp);
332162306a36Sopenharmony_ci				if (rc)
332262306a36Sopenharmony_ci					return rc;
332362306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
332462306a36Sopenharmony_ci				if (rc)
332562306a36Sopenharmony_ci					return rc;
332662306a36Sopenharmony_ci				break;
332762306a36Sopenharmony_ci			case OCON_FSUSE:
332862306a36Sopenharmony_ci				buf[0] = cpu_to_le32(c->v.behavior);
332962306a36Sopenharmony_ci				len = strlen(c->u.name);
333062306a36Sopenharmony_ci				buf[1] = cpu_to_le32(len);
333162306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 2, fp);
333262306a36Sopenharmony_ci				if (rc)
333362306a36Sopenharmony_ci					return rc;
333462306a36Sopenharmony_ci				rc = put_entry(c->u.name, 1, len, fp);
333562306a36Sopenharmony_ci				if (rc)
333662306a36Sopenharmony_ci					return rc;
333762306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
333862306a36Sopenharmony_ci				if (rc)
333962306a36Sopenharmony_ci					return rc;
334062306a36Sopenharmony_ci				break;
334162306a36Sopenharmony_ci			case OCON_NODE6:
334262306a36Sopenharmony_ci				for (j = 0; j < 4; j++)
334362306a36Sopenharmony_ci					nodebuf[j] = c->u.node6.addr[j]; /* network order */
334462306a36Sopenharmony_ci				for (j = 0; j < 4; j++)
334562306a36Sopenharmony_ci					nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
334662306a36Sopenharmony_ci				rc = put_entry(nodebuf, sizeof(u32), 8, fp);
334762306a36Sopenharmony_ci				if (rc)
334862306a36Sopenharmony_ci					return rc;
334962306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
335062306a36Sopenharmony_ci				if (rc)
335162306a36Sopenharmony_ci					return rc;
335262306a36Sopenharmony_ci				break;
335362306a36Sopenharmony_ci			case OCON_IBPKEY:
335462306a36Sopenharmony_ci				/* subnet_prefix is in CPU order */
335562306a36Sopenharmony_ci				prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci				rc = put_entry(prefixbuf, sizeof(u64), 1, fp);
335862306a36Sopenharmony_ci				if (rc)
335962306a36Sopenharmony_ci					return rc;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci				buf[0] = cpu_to_le32(c->u.ibpkey.low_pkey);
336262306a36Sopenharmony_ci				buf[1] = cpu_to_le32(c->u.ibpkey.high_pkey);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 2, fp);
336562306a36Sopenharmony_ci				if (rc)
336662306a36Sopenharmony_ci					return rc;
336762306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
336862306a36Sopenharmony_ci				if (rc)
336962306a36Sopenharmony_ci					return rc;
337062306a36Sopenharmony_ci				break;
337162306a36Sopenharmony_ci			case OCON_IBENDPORT:
337262306a36Sopenharmony_ci				len = strlen(c->u.ibendport.dev_name);
337362306a36Sopenharmony_ci				buf[0] = cpu_to_le32(len);
337462306a36Sopenharmony_ci				buf[1] = cpu_to_le32(c->u.ibendport.port);
337562306a36Sopenharmony_ci				rc = put_entry(buf, sizeof(u32), 2, fp);
337662306a36Sopenharmony_ci				if (rc)
337762306a36Sopenharmony_ci					return rc;
337862306a36Sopenharmony_ci				rc = put_entry(c->u.ibendport.dev_name, 1, len, fp);
337962306a36Sopenharmony_ci				if (rc)
338062306a36Sopenharmony_ci					return rc;
338162306a36Sopenharmony_ci				rc = context_write(p, &c->context[0], fp);
338262306a36Sopenharmony_ci				if (rc)
338362306a36Sopenharmony_ci					return rc;
338462306a36Sopenharmony_ci				break;
338562306a36Sopenharmony_ci			}
338662306a36Sopenharmony_ci		}
338762306a36Sopenharmony_ci	}
338862306a36Sopenharmony_ci	return 0;
338962306a36Sopenharmony_ci}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_cistatic int genfs_write(struct policydb *p, void *fp)
339262306a36Sopenharmony_ci{
339362306a36Sopenharmony_ci	struct genfs *genfs;
339462306a36Sopenharmony_ci	struct ocontext *c;
339562306a36Sopenharmony_ci	size_t len;
339662306a36Sopenharmony_ci	__le32 buf[1];
339762306a36Sopenharmony_ci	int rc;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	len = 0;
340062306a36Sopenharmony_ci	for (genfs = p->genfs; genfs; genfs = genfs->next)
340162306a36Sopenharmony_ci		len++;
340262306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
340362306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
340462306a36Sopenharmony_ci	if (rc)
340562306a36Sopenharmony_ci		return rc;
340662306a36Sopenharmony_ci	for (genfs = p->genfs; genfs; genfs = genfs->next) {
340762306a36Sopenharmony_ci		len = strlen(genfs->fstype);
340862306a36Sopenharmony_ci		buf[0] = cpu_to_le32(len);
340962306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
341062306a36Sopenharmony_ci		if (rc)
341162306a36Sopenharmony_ci			return rc;
341262306a36Sopenharmony_ci		rc = put_entry(genfs->fstype, 1, len, fp);
341362306a36Sopenharmony_ci		if (rc)
341462306a36Sopenharmony_ci			return rc;
341562306a36Sopenharmony_ci		len = 0;
341662306a36Sopenharmony_ci		for (c = genfs->head; c; c = c->next)
341762306a36Sopenharmony_ci			len++;
341862306a36Sopenharmony_ci		buf[0] = cpu_to_le32(len);
341962306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
342062306a36Sopenharmony_ci		if (rc)
342162306a36Sopenharmony_ci			return rc;
342262306a36Sopenharmony_ci		for (c = genfs->head; c; c = c->next) {
342362306a36Sopenharmony_ci			len = strlen(c->u.name);
342462306a36Sopenharmony_ci			buf[0] = cpu_to_le32(len);
342562306a36Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 1, fp);
342662306a36Sopenharmony_ci			if (rc)
342762306a36Sopenharmony_ci				return rc;
342862306a36Sopenharmony_ci			rc = put_entry(c->u.name, 1, len, fp);
342962306a36Sopenharmony_ci			if (rc)
343062306a36Sopenharmony_ci				return rc;
343162306a36Sopenharmony_ci			buf[0] = cpu_to_le32(c->v.sclass);
343262306a36Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 1, fp);
343362306a36Sopenharmony_ci			if (rc)
343462306a36Sopenharmony_ci				return rc;
343562306a36Sopenharmony_ci			rc = context_write(p, &c->context[0], fp);
343662306a36Sopenharmony_ci			if (rc)
343762306a36Sopenharmony_ci				return rc;
343862306a36Sopenharmony_ci		}
343962306a36Sopenharmony_ci	}
344062306a36Sopenharmony_ci	return 0;
344162306a36Sopenharmony_ci}
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_cistatic int range_write_helper(void *key, void *data, void *ptr)
344462306a36Sopenharmony_ci{
344562306a36Sopenharmony_ci	__le32 buf[2];
344662306a36Sopenharmony_ci	struct range_trans *rt = key;
344762306a36Sopenharmony_ci	struct mls_range *r = data;
344862306a36Sopenharmony_ci	struct policy_data *pd = ptr;
344962306a36Sopenharmony_ci	void *fp = pd->fp;
345062306a36Sopenharmony_ci	struct policydb *p = pd->p;
345162306a36Sopenharmony_ci	int rc;
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci	buf[0] = cpu_to_le32(rt->source_type);
345462306a36Sopenharmony_ci	buf[1] = cpu_to_le32(rt->target_type);
345562306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 2, fp);
345662306a36Sopenharmony_ci	if (rc)
345762306a36Sopenharmony_ci		return rc;
345862306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
345962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(rt->target_class);
346062306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
346162306a36Sopenharmony_ci		if (rc)
346262306a36Sopenharmony_ci			return rc;
346362306a36Sopenharmony_ci	}
346462306a36Sopenharmony_ci	rc = mls_write_range_helper(r, fp);
346562306a36Sopenharmony_ci	if (rc)
346662306a36Sopenharmony_ci		return rc;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	return 0;
346962306a36Sopenharmony_ci}
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_cistatic int range_write(struct policydb *p, void *fp)
347262306a36Sopenharmony_ci{
347362306a36Sopenharmony_ci	__le32 buf[1];
347462306a36Sopenharmony_ci	int rc;
347562306a36Sopenharmony_ci	struct policy_data pd;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	pd.p = p;
347862306a36Sopenharmony_ci	pd.fp = fp;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	buf[0] = cpu_to_le32(p->range_tr.nel);
348162306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
348262306a36Sopenharmony_ci	if (rc)
348362306a36Sopenharmony_ci		return rc;
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	/* actually write all of the entries */
348662306a36Sopenharmony_ci	rc = hashtab_map(&p->range_tr, range_write_helper, &pd);
348762306a36Sopenharmony_ci	if (rc)
348862306a36Sopenharmony_ci		return rc;
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	return 0;
349162306a36Sopenharmony_ci}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_cistatic int filename_write_helper_compat(void *key, void *data, void *ptr)
349462306a36Sopenharmony_ci{
349562306a36Sopenharmony_ci	struct filename_trans_key *ft = key;
349662306a36Sopenharmony_ci	struct filename_trans_datum *datum = data;
349762306a36Sopenharmony_ci	struct ebitmap_node *node;
349862306a36Sopenharmony_ci	void *fp = ptr;
349962306a36Sopenharmony_ci	__le32 buf[4];
350062306a36Sopenharmony_ci	int rc;
350162306a36Sopenharmony_ci	u32 bit, len = strlen(ft->name);
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	do {
350462306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
350562306a36Sopenharmony_ci			buf[0] = cpu_to_le32(len);
350662306a36Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 1, fp);
350762306a36Sopenharmony_ci			if (rc)
350862306a36Sopenharmony_ci				return rc;
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci			rc = put_entry(ft->name, sizeof(char), len, fp);
351162306a36Sopenharmony_ci			if (rc)
351262306a36Sopenharmony_ci				return rc;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci			buf[0] = cpu_to_le32(bit + 1);
351562306a36Sopenharmony_ci			buf[1] = cpu_to_le32(ft->ttype);
351662306a36Sopenharmony_ci			buf[2] = cpu_to_le32(ft->tclass);
351762306a36Sopenharmony_ci			buf[3] = cpu_to_le32(datum->otype);
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci			rc = put_entry(buf, sizeof(u32), 4, fp);
352062306a36Sopenharmony_ci			if (rc)
352162306a36Sopenharmony_ci				return rc;
352262306a36Sopenharmony_ci		}
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci		datum = datum->next;
352562306a36Sopenharmony_ci	} while (unlikely(datum));
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci	return 0;
352862306a36Sopenharmony_ci}
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_cistatic int filename_write_helper(void *key, void *data, void *ptr)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	struct filename_trans_key *ft = key;
353362306a36Sopenharmony_ci	struct filename_trans_datum *datum;
353462306a36Sopenharmony_ci	void *fp = ptr;
353562306a36Sopenharmony_ci	__le32 buf[3];
353662306a36Sopenharmony_ci	int rc;
353762306a36Sopenharmony_ci	u32 ndatum, len = strlen(ft->name);
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	buf[0] = cpu_to_le32(len);
354062306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 1, fp);
354162306a36Sopenharmony_ci	if (rc)
354262306a36Sopenharmony_ci		return rc;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	rc = put_entry(ft->name, sizeof(char), len, fp);
354562306a36Sopenharmony_ci	if (rc)
354662306a36Sopenharmony_ci		return rc;
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci	ndatum = 0;
354962306a36Sopenharmony_ci	datum = data;
355062306a36Sopenharmony_ci	do {
355162306a36Sopenharmony_ci		ndatum++;
355262306a36Sopenharmony_ci		datum = datum->next;
355362306a36Sopenharmony_ci	} while (unlikely(datum));
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	buf[0] = cpu_to_le32(ft->ttype);
355662306a36Sopenharmony_ci	buf[1] = cpu_to_le32(ft->tclass);
355762306a36Sopenharmony_ci	buf[2] = cpu_to_le32(ndatum);
355862306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 3, fp);
355962306a36Sopenharmony_ci	if (rc)
356062306a36Sopenharmony_ci		return rc;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	datum = data;
356362306a36Sopenharmony_ci	do {
356462306a36Sopenharmony_ci		rc = ebitmap_write(&datum->stypes, fp);
356562306a36Sopenharmony_ci		if (rc)
356662306a36Sopenharmony_ci			return rc;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci		buf[0] = cpu_to_le32(datum->otype);
356962306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
357062306a36Sopenharmony_ci		if (rc)
357162306a36Sopenharmony_ci			return rc;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci		datum = datum->next;
357462306a36Sopenharmony_ci	} while (unlikely(datum));
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	return 0;
357762306a36Sopenharmony_ci}
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_cistatic int filename_trans_write(struct policydb *p, void *fp)
358062306a36Sopenharmony_ci{
358162306a36Sopenharmony_ci	__le32 buf[1];
358262306a36Sopenharmony_ci	int rc;
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
358562306a36Sopenharmony_ci		return 0;
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) {
358862306a36Sopenharmony_ci		buf[0] = cpu_to_le32(p->compat_filename_trans_count);
358962306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
359062306a36Sopenharmony_ci		if (rc)
359162306a36Sopenharmony_ci			return rc;
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci		rc = hashtab_map(&p->filename_trans,
359462306a36Sopenharmony_ci				 filename_write_helper_compat, fp);
359562306a36Sopenharmony_ci	} else {
359662306a36Sopenharmony_ci		buf[0] = cpu_to_le32(p->filename_trans.nel);
359762306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 1, fp);
359862306a36Sopenharmony_ci		if (rc)
359962306a36Sopenharmony_ci			return rc;
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci		rc = hashtab_map(&p->filename_trans, filename_write_helper, fp);
360262306a36Sopenharmony_ci	}
360362306a36Sopenharmony_ci	return rc;
360462306a36Sopenharmony_ci}
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci/*
360762306a36Sopenharmony_ci * Write the configuration data in a policy database
360862306a36Sopenharmony_ci * structure to a policy database binary representation
360962306a36Sopenharmony_ci * file.
361062306a36Sopenharmony_ci */
361162306a36Sopenharmony_ciint policydb_write(struct policydb *p, void *fp)
361262306a36Sopenharmony_ci{
361362306a36Sopenharmony_ci	unsigned int num_syms;
361462306a36Sopenharmony_ci	int rc;
361562306a36Sopenharmony_ci	__le32 buf[4];
361662306a36Sopenharmony_ci	u32 config, i;
361762306a36Sopenharmony_ci	size_t len;
361862306a36Sopenharmony_ci	const struct policydb_compat_info *info;
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	/*
362162306a36Sopenharmony_ci	 * refuse to write policy older than compressed avtab
362262306a36Sopenharmony_ci	 * to simplify the writer.  There are other tests dropped
362362306a36Sopenharmony_ci	 * since we assume this throughout the writer code.  Be
362462306a36Sopenharmony_ci	 * careful if you ever try to remove this restriction
362562306a36Sopenharmony_ci	 */
362662306a36Sopenharmony_ci	if (p->policyvers < POLICYDB_VERSION_AVTAB) {
362762306a36Sopenharmony_ci		pr_err("SELinux: refusing to write policy version %d."
362862306a36Sopenharmony_ci		       "  Because it is less than version %d\n", p->policyvers,
362962306a36Sopenharmony_ci		       POLICYDB_VERSION_AVTAB);
363062306a36Sopenharmony_ci		return -EINVAL;
363162306a36Sopenharmony_ci	}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	config = 0;
363462306a36Sopenharmony_ci	if (p->mls_enabled)
363562306a36Sopenharmony_ci		config |= POLICYDB_CONFIG_MLS;
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	if (p->reject_unknown)
363862306a36Sopenharmony_ci		config |= REJECT_UNKNOWN;
363962306a36Sopenharmony_ci	if (p->allow_unknown)
364062306a36Sopenharmony_ci		config |= ALLOW_UNKNOWN;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	/* Write the magic number and string identifiers. */
364362306a36Sopenharmony_ci	buf[0] = cpu_to_le32(POLICYDB_MAGIC);
364462306a36Sopenharmony_ci	len = strlen(POLICYDB_STRING);
364562306a36Sopenharmony_ci	buf[1] = cpu_to_le32(len);
364662306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 2, fp);
364762306a36Sopenharmony_ci	if (rc)
364862306a36Sopenharmony_ci		return rc;
364962306a36Sopenharmony_ci	rc = put_entry(POLICYDB_STRING, 1, len, fp);
365062306a36Sopenharmony_ci	if (rc)
365162306a36Sopenharmony_ci		return rc;
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	/* Write the version, config, and table sizes. */
365462306a36Sopenharmony_ci	info = policydb_lookup_compat(p->policyvers);
365562306a36Sopenharmony_ci	if (!info) {
365662306a36Sopenharmony_ci		pr_err("SELinux: compatibility lookup failed for policy "
365762306a36Sopenharmony_ci		    "version %d\n", p->policyvers);
365862306a36Sopenharmony_ci		return -EINVAL;
365962306a36Sopenharmony_ci	}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	buf[0] = cpu_to_le32(p->policyvers);
366262306a36Sopenharmony_ci	buf[1] = cpu_to_le32(config);
366362306a36Sopenharmony_ci	buf[2] = cpu_to_le32(info->sym_num);
366462306a36Sopenharmony_ci	buf[3] = cpu_to_le32(info->ocon_num);
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	rc = put_entry(buf, sizeof(u32), 4, fp);
366762306a36Sopenharmony_ci	if (rc)
366862306a36Sopenharmony_ci		return rc;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
367162306a36Sopenharmony_ci		rc = ebitmap_write(&p->policycaps, fp);
367262306a36Sopenharmony_ci		if (rc)
367362306a36Sopenharmony_ci			return rc;
367462306a36Sopenharmony_ci	}
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
367762306a36Sopenharmony_ci		rc = ebitmap_write(&p->permissive_map, fp);
367862306a36Sopenharmony_ci		if (rc)
367962306a36Sopenharmony_ci			return rc;
368062306a36Sopenharmony_ci	}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci	num_syms = info->sym_num;
368362306a36Sopenharmony_ci	for (i = 0; i < num_syms; i++) {
368462306a36Sopenharmony_ci		struct policy_data pd;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci		pd.fp = fp;
368762306a36Sopenharmony_ci		pd.p = p;
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci		buf[0] = cpu_to_le32(p->symtab[i].nprim);
369062306a36Sopenharmony_ci		buf[1] = cpu_to_le32(p->symtab[i].table.nel);
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci		rc = put_entry(buf, sizeof(u32), 2, fp);
369362306a36Sopenharmony_ci		if (rc)
369462306a36Sopenharmony_ci			return rc;
369562306a36Sopenharmony_ci		rc = hashtab_map(&p->symtab[i].table, write_f[i], &pd);
369662306a36Sopenharmony_ci		if (rc)
369762306a36Sopenharmony_ci			return rc;
369862306a36Sopenharmony_ci	}
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	rc = avtab_write(p, &p->te_avtab, fp);
370162306a36Sopenharmony_ci	if (rc)
370262306a36Sopenharmony_ci		return rc;
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	rc = cond_write_list(p, fp);
370562306a36Sopenharmony_ci	if (rc)
370662306a36Sopenharmony_ci		return rc;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	rc = role_trans_write(p, fp);
370962306a36Sopenharmony_ci	if (rc)
371062306a36Sopenharmony_ci		return rc;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	rc = role_allow_write(p->role_allow, fp);
371362306a36Sopenharmony_ci	if (rc)
371462306a36Sopenharmony_ci		return rc;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	rc = filename_trans_write(p, fp);
371762306a36Sopenharmony_ci	if (rc)
371862306a36Sopenharmony_ci		return rc;
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	rc = ocontext_write(p, info, fp);
372162306a36Sopenharmony_ci	if (rc)
372262306a36Sopenharmony_ci		return rc;
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	rc = genfs_write(p, fp);
372562306a36Sopenharmony_ci	if (rc)
372662306a36Sopenharmony_ci		return rc;
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci	rc = range_write(p, fp);
372962306a36Sopenharmony_ci	if (rc)
373062306a36Sopenharmony_ci		return rc;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	for (i = 0; i < p->p_types.nprim; i++) {
373362306a36Sopenharmony_ci		struct ebitmap *e = &p->type_attr_map_array[i];
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci		rc = ebitmap_write(e, fp);
373662306a36Sopenharmony_ci		if (rc)
373762306a36Sopenharmony_ci			return rc;
373862306a36Sopenharmony_ci	}
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	return 0;
374162306a36Sopenharmony_ci}
3742