162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Implementation of the security services.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors : Stephen Smalley, <stephen.smalley.work@gmail.com>
662306a36Sopenharmony_ci *	     James Morris <jmorris@redhat.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *	Support for enhanced MLS infrastructure.
1162306a36Sopenharmony_ci *	Support for context based audit filters.
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 NetLabel
2062306a36Sopenharmony_ci *      Added support for the policy capability bitmap
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Updated: Chad Sellers <csellers@tresys.com>
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci *  Added validation of kernel classes and permissions
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *  Added support for bounds domain and audit messaged on masked permissions
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Updated: Guido Trentalancia <guido@trentalancia.com>
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *  Added support for runtime switching of the policy type
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * Copyright (C) 2008, 2009 NEC Corporation
3562306a36Sopenharmony_ci * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
3662306a36Sopenharmony_ci * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
3762306a36Sopenharmony_ci * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
3862306a36Sopenharmony_ci * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci#include <linux/kernel.h>
4162306a36Sopenharmony_ci#include <linux/slab.h>
4262306a36Sopenharmony_ci#include <linux/string.h>
4362306a36Sopenharmony_ci#include <linux/spinlock.h>
4462306a36Sopenharmony_ci#include <linux/rcupdate.h>
4562306a36Sopenharmony_ci#include <linux/errno.h>
4662306a36Sopenharmony_ci#include <linux/in.h>
4762306a36Sopenharmony_ci#include <linux/sched.h>
4862306a36Sopenharmony_ci#include <linux/audit.h>
4962306a36Sopenharmony_ci#include <linux/vmalloc.h>
5062306a36Sopenharmony_ci#include <linux/lsm_hooks.h>
5162306a36Sopenharmony_ci#include <net/netlabel.h>
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#include "flask.h"
5462306a36Sopenharmony_ci#include "avc.h"
5562306a36Sopenharmony_ci#include "avc_ss.h"
5662306a36Sopenharmony_ci#include "security.h"
5762306a36Sopenharmony_ci#include "context.h"
5862306a36Sopenharmony_ci#include "policydb.h"
5962306a36Sopenharmony_ci#include "sidtab.h"
6062306a36Sopenharmony_ci#include "services.h"
6162306a36Sopenharmony_ci#include "conditional.h"
6262306a36Sopenharmony_ci#include "mls.h"
6362306a36Sopenharmony_ci#include "objsec.h"
6462306a36Sopenharmony_ci#include "netlabel.h"
6562306a36Sopenharmony_ci#include "xfrm.h"
6662306a36Sopenharmony_ci#include "ebitmap.h"
6762306a36Sopenharmony_ci#include "audit.h"
6862306a36Sopenharmony_ci#include "policycap_names.h"
6962306a36Sopenharmony_ci#include "ima.h"
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct selinux_policy_convert_data {
7262306a36Sopenharmony_ci	struct convert_context_args args;
7362306a36Sopenharmony_ci	struct sidtab_convert_params sidtab_params;
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Forward declaration. */
7762306a36Sopenharmony_cistatic int context_struct_to_string(struct policydb *policydb,
7862306a36Sopenharmony_ci				    struct context *context,
7962306a36Sopenharmony_ci				    char **scontext,
8062306a36Sopenharmony_ci				    u32 *scontext_len);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *policydb,
8362306a36Sopenharmony_ci				  struct sidtab *sidtab,
8462306a36Sopenharmony_ci				  struct sidtab_entry *entry,
8562306a36Sopenharmony_ci				  char **scontext,
8662306a36Sopenharmony_ci				  u32 *scontext_len);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb,
8962306a36Sopenharmony_ci				      struct context *scontext,
9062306a36Sopenharmony_ci				      struct context *tcontext,
9162306a36Sopenharmony_ci				      u16 tclass,
9262306a36Sopenharmony_ci				      struct av_decision *avd,
9362306a36Sopenharmony_ci				      struct extended_perms *xperms);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int selinux_set_mapping(struct policydb *pol,
9662306a36Sopenharmony_ci			       const struct security_class_mapping *map,
9762306a36Sopenharmony_ci			       struct selinux_map *out_map)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	u16 i, j;
10062306a36Sopenharmony_ci	bool print_unknown_handle = false;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* Find number of classes in the input mapping */
10362306a36Sopenharmony_ci	if (!map)
10462306a36Sopenharmony_ci		return -EINVAL;
10562306a36Sopenharmony_ci	i = 0;
10662306a36Sopenharmony_ci	while (map[i].name)
10762306a36Sopenharmony_ci		i++;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Allocate space for the class records, plus one for class zero */
11062306a36Sopenharmony_ci	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
11162306a36Sopenharmony_ci	if (!out_map->mapping)
11262306a36Sopenharmony_ci		return -ENOMEM;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Store the raw class and permission values */
11562306a36Sopenharmony_ci	j = 0;
11662306a36Sopenharmony_ci	while (map[j].name) {
11762306a36Sopenharmony_ci		const struct security_class_mapping *p_in = map + (j++);
11862306a36Sopenharmony_ci		struct selinux_mapping *p_out = out_map->mapping + j;
11962306a36Sopenharmony_ci		u16 k;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		/* An empty class string skips ahead */
12262306a36Sopenharmony_ci		if (!strcmp(p_in->name, "")) {
12362306a36Sopenharmony_ci			p_out->num_perms = 0;
12462306a36Sopenharmony_ci			continue;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		p_out->value = string_to_security_class(pol, p_in->name);
12862306a36Sopenharmony_ci		if (!p_out->value) {
12962306a36Sopenharmony_ci			pr_info("SELinux:  Class %s not defined in policy.\n",
13062306a36Sopenharmony_ci			       p_in->name);
13162306a36Sopenharmony_ci			if (pol->reject_unknown)
13262306a36Sopenharmony_ci				goto err;
13362306a36Sopenharmony_ci			p_out->num_perms = 0;
13462306a36Sopenharmony_ci			print_unknown_handle = true;
13562306a36Sopenharmony_ci			continue;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		k = 0;
13962306a36Sopenharmony_ci		while (p_in->perms[k]) {
14062306a36Sopenharmony_ci			/* An empty permission string skips ahead */
14162306a36Sopenharmony_ci			if (!*p_in->perms[k]) {
14262306a36Sopenharmony_ci				k++;
14362306a36Sopenharmony_ci				continue;
14462306a36Sopenharmony_ci			}
14562306a36Sopenharmony_ci			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
14662306a36Sopenharmony_ci							    p_in->perms[k]);
14762306a36Sopenharmony_ci			if (!p_out->perms[k]) {
14862306a36Sopenharmony_ci				pr_info("SELinux:  Permission %s in class %s not defined in policy.\n",
14962306a36Sopenharmony_ci				       p_in->perms[k], p_in->name);
15062306a36Sopenharmony_ci				if (pol->reject_unknown)
15162306a36Sopenharmony_ci					goto err;
15262306a36Sopenharmony_ci				print_unknown_handle = true;
15362306a36Sopenharmony_ci			}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci			k++;
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci		p_out->num_perms = k;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (print_unknown_handle)
16162306a36Sopenharmony_ci		pr_info("SELinux: the above unknown classes and permissions will be %s\n",
16262306a36Sopenharmony_ci		       pol->allow_unknown ? "allowed" : "denied");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	out_map->size = i;
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_cierr:
16762306a36Sopenharmony_ci	kfree(out_map->mapping);
16862306a36Sopenharmony_ci	out_map->mapping = NULL;
16962306a36Sopenharmony_ci	return -EINVAL;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Get real, policy values from mapped values
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic u16 unmap_class(struct selinux_map *map, u16 tclass)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	if (tclass < map->size)
17962306a36Sopenharmony_ci		return map->mapping[tclass].value;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return tclass;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/*
18562306a36Sopenharmony_ci * Get kernel value for class from its policy value
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic u16 map_class(struct selinux_map *map, u16 pol_value)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	u16 i;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	for (i = 1; i < map->size; i++) {
19262306a36Sopenharmony_ci		if (map->mapping[i].value == pol_value)
19362306a36Sopenharmony_ci			return i;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return SECCLASS_NULL;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void map_decision(struct selinux_map *map,
20062306a36Sopenharmony_ci			 u16 tclass, struct av_decision *avd,
20162306a36Sopenharmony_ci			 int allow_unknown)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	if (tclass < map->size) {
20462306a36Sopenharmony_ci		struct selinux_mapping *mapping = &map->mapping[tclass];
20562306a36Sopenharmony_ci		unsigned int i, n = mapping->num_perms;
20662306a36Sopenharmony_ci		u32 result;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		for (i = 0, result = 0; i < n; i++) {
20962306a36Sopenharmony_ci			if (avd->allowed & mapping->perms[i])
21062306a36Sopenharmony_ci				result |= (u32)1<<i;
21162306a36Sopenharmony_ci			if (allow_unknown && !mapping->perms[i])
21262306a36Sopenharmony_ci				result |= (u32)1<<i;
21362306a36Sopenharmony_ci		}
21462306a36Sopenharmony_ci		avd->allowed = result;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		for (i = 0, result = 0; i < n; i++)
21762306a36Sopenharmony_ci			if (avd->auditallow & mapping->perms[i])
21862306a36Sopenharmony_ci				result |= (u32)1<<i;
21962306a36Sopenharmony_ci		avd->auditallow = result;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		for (i = 0, result = 0; i < n; i++) {
22262306a36Sopenharmony_ci			if (avd->auditdeny & mapping->perms[i])
22362306a36Sopenharmony_ci				result |= (u32)1<<i;
22462306a36Sopenharmony_ci			if (!allow_unknown && !mapping->perms[i])
22562306a36Sopenharmony_ci				result |= (u32)1<<i;
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci		/*
22862306a36Sopenharmony_ci		 * In case the kernel has a bug and requests a permission
22962306a36Sopenharmony_ci		 * between num_perms and the maximum permission number, we
23062306a36Sopenharmony_ci		 * should audit that denial
23162306a36Sopenharmony_ci		 */
23262306a36Sopenharmony_ci		for (; i < (sizeof(u32)*8); i++)
23362306a36Sopenharmony_ci			result |= (u32)1<<i;
23462306a36Sopenharmony_ci		avd->auditdeny = result;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciint security_mls_enabled(void)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	int mls_enabled;
24162306a36Sopenharmony_ci	struct selinux_policy *policy;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (!selinux_initialized())
24462306a36Sopenharmony_ci		return 0;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	rcu_read_lock();
24762306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
24862306a36Sopenharmony_ci	mls_enabled = policy->policydb.mls_enabled;
24962306a36Sopenharmony_ci	rcu_read_unlock();
25062306a36Sopenharmony_ci	return mls_enabled;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/*
25462306a36Sopenharmony_ci * Return the boolean value of a constraint expression
25562306a36Sopenharmony_ci * when it is applied to the specified source and target
25662306a36Sopenharmony_ci * security contexts.
25762306a36Sopenharmony_ci *
25862306a36Sopenharmony_ci * xcontext is a special beast...  It is used by the validatetrans rules
25962306a36Sopenharmony_ci * only.  For these rules, scontext is the context before the transition,
26062306a36Sopenharmony_ci * tcontext is the context after the transition, and xcontext is the context
26162306a36Sopenharmony_ci * of the process performing the transition.  All other callers of
26262306a36Sopenharmony_ci * constraint_expr_eval should pass in NULL for xcontext.
26362306a36Sopenharmony_ci */
26462306a36Sopenharmony_cistatic int constraint_expr_eval(struct policydb *policydb,
26562306a36Sopenharmony_ci				struct context *scontext,
26662306a36Sopenharmony_ci				struct context *tcontext,
26762306a36Sopenharmony_ci				struct context *xcontext,
26862306a36Sopenharmony_ci				struct constraint_expr *cexpr)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u32 val1, val2;
27162306a36Sopenharmony_ci	struct context *c;
27262306a36Sopenharmony_ci	struct role_datum *r1, *r2;
27362306a36Sopenharmony_ci	struct mls_level *l1, *l2;
27462306a36Sopenharmony_ci	struct constraint_expr *e;
27562306a36Sopenharmony_ci	int s[CEXPR_MAXDEPTH];
27662306a36Sopenharmony_ci	int sp = -1;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for (e = cexpr; e; e = e->next) {
27962306a36Sopenharmony_ci		switch (e->expr_type) {
28062306a36Sopenharmony_ci		case CEXPR_NOT:
28162306a36Sopenharmony_ci			BUG_ON(sp < 0);
28262306a36Sopenharmony_ci			s[sp] = !s[sp];
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci		case CEXPR_AND:
28562306a36Sopenharmony_ci			BUG_ON(sp < 1);
28662306a36Sopenharmony_ci			sp--;
28762306a36Sopenharmony_ci			s[sp] &= s[sp + 1];
28862306a36Sopenharmony_ci			break;
28962306a36Sopenharmony_ci		case CEXPR_OR:
29062306a36Sopenharmony_ci			BUG_ON(sp < 1);
29162306a36Sopenharmony_ci			sp--;
29262306a36Sopenharmony_ci			s[sp] |= s[sp + 1];
29362306a36Sopenharmony_ci			break;
29462306a36Sopenharmony_ci		case CEXPR_ATTR:
29562306a36Sopenharmony_ci			if (sp == (CEXPR_MAXDEPTH - 1))
29662306a36Sopenharmony_ci				return 0;
29762306a36Sopenharmony_ci			switch (e->attr) {
29862306a36Sopenharmony_ci			case CEXPR_USER:
29962306a36Sopenharmony_ci				val1 = scontext->user;
30062306a36Sopenharmony_ci				val2 = tcontext->user;
30162306a36Sopenharmony_ci				break;
30262306a36Sopenharmony_ci			case CEXPR_TYPE:
30362306a36Sopenharmony_ci				val1 = scontext->type;
30462306a36Sopenharmony_ci				val2 = tcontext->type;
30562306a36Sopenharmony_ci				break;
30662306a36Sopenharmony_ci			case CEXPR_ROLE:
30762306a36Sopenharmony_ci				val1 = scontext->role;
30862306a36Sopenharmony_ci				val2 = tcontext->role;
30962306a36Sopenharmony_ci				r1 = policydb->role_val_to_struct[val1 - 1];
31062306a36Sopenharmony_ci				r2 = policydb->role_val_to_struct[val2 - 1];
31162306a36Sopenharmony_ci				switch (e->op) {
31262306a36Sopenharmony_ci				case CEXPR_DOM:
31362306a36Sopenharmony_ci					s[++sp] = ebitmap_get_bit(&r1->dominates,
31462306a36Sopenharmony_ci								  val2 - 1);
31562306a36Sopenharmony_ci					continue;
31662306a36Sopenharmony_ci				case CEXPR_DOMBY:
31762306a36Sopenharmony_ci					s[++sp] = ebitmap_get_bit(&r2->dominates,
31862306a36Sopenharmony_ci								  val1 - 1);
31962306a36Sopenharmony_ci					continue;
32062306a36Sopenharmony_ci				case CEXPR_INCOMP:
32162306a36Sopenharmony_ci					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
32262306a36Sopenharmony_ci								    val2 - 1) &&
32362306a36Sopenharmony_ci						   !ebitmap_get_bit(&r2->dominates,
32462306a36Sopenharmony_ci								    val1 - 1));
32562306a36Sopenharmony_ci					continue;
32662306a36Sopenharmony_ci				default:
32762306a36Sopenharmony_ci					break;
32862306a36Sopenharmony_ci				}
32962306a36Sopenharmony_ci				break;
33062306a36Sopenharmony_ci			case CEXPR_L1L2:
33162306a36Sopenharmony_ci				l1 = &(scontext->range.level[0]);
33262306a36Sopenharmony_ci				l2 = &(tcontext->range.level[0]);
33362306a36Sopenharmony_ci				goto mls_ops;
33462306a36Sopenharmony_ci			case CEXPR_L1H2:
33562306a36Sopenharmony_ci				l1 = &(scontext->range.level[0]);
33662306a36Sopenharmony_ci				l2 = &(tcontext->range.level[1]);
33762306a36Sopenharmony_ci				goto mls_ops;
33862306a36Sopenharmony_ci			case CEXPR_H1L2:
33962306a36Sopenharmony_ci				l1 = &(scontext->range.level[1]);
34062306a36Sopenharmony_ci				l2 = &(tcontext->range.level[0]);
34162306a36Sopenharmony_ci				goto mls_ops;
34262306a36Sopenharmony_ci			case CEXPR_H1H2:
34362306a36Sopenharmony_ci				l1 = &(scontext->range.level[1]);
34462306a36Sopenharmony_ci				l2 = &(tcontext->range.level[1]);
34562306a36Sopenharmony_ci				goto mls_ops;
34662306a36Sopenharmony_ci			case CEXPR_L1H1:
34762306a36Sopenharmony_ci				l1 = &(scontext->range.level[0]);
34862306a36Sopenharmony_ci				l2 = &(scontext->range.level[1]);
34962306a36Sopenharmony_ci				goto mls_ops;
35062306a36Sopenharmony_ci			case CEXPR_L2H2:
35162306a36Sopenharmony_ci				l1 = &(tcontext->range.level[0]);
35262306a36Sopenharmony_ci				l2 = &(tcontext->range.level[1]);
35362306a36Sopenharmony_ci				goto mls_ops;
35462306a36Sopenharmony_cimls_ops:
35562306a36Sopenharmony_ci				switch (e->op) {
35662306a36Sopenharmony_ci				case CEXPR_EQ:
35762306a36Sopenharmony_ci					s[++sp] = mls_level_eq(l1, l2);
35862306a36Sopenharmony_ci					continue;
35962306a36Sopenharmony_ci				case CEXPR_NEQ:
36062306a36Sopenharmony_ci					s[++sp] = !mls_level_eq(l1, l2);
36162306a36Sopenharmony_ci					continue;
36262306a36Sopenharmony_ci				case CEXPR_DOM:
36362306a36Sopenharmony_ci					s[++sp] = mls_level_dom(l1, l2);
36462306a36Sopenharmony_ci					continue;
36562306a36Sopenharmony_ci				case CEXPR_DOMBY:
36662306a36Sopenharmony_ci					s[++sp] = mls_level_dom(l2, l1);
36762306a36Sopenharmony_ci					continue;
36862306a36Sopenharmony_ci				case CEXPR_INCOMP:
36962306a36Sopenharmony_ci					s[++sp] = mls_level_incomp(l2, l1);
37062306a36Sopenharmony_ci					continue;
37162306a36Sopenharmony_ci				default:
37262306a36Sopenharmony_ci					BUG();
37362306a36Sopenharmony_ci					return 0;
37462306a36Sopenharmony_ci				}
37562306a36Sopenharmony_ci				break;
37662306a36Sopenharmony_ci			default:
37762306a36Sopenharmony_ci				BUG();
37862306a36Sopenharmony_ci				return 0;
37962306a36Sopenharmony_ci			}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci			switch (e->op) {
38262306a36Sopenharmony_ci			case CEXPR_EQ:
38362306a36Sopenharmony_ci				s[++sp] = (val1 == val2);
38462306a36Sopenharmony_ci				break;
38562306a36Sopenharmony_ci			case CEXPR_NEQ:
38662306a36Sopenharmony_ci				s[++sp] = (val1 != val2);
38762306a36Sopenharmony_ci				break;
38862306a36Sopenharmony_ci			default:
38962306a36Sopenharmony_ci				BUG();
39062306a36Sopenharmony_ci				return 0;
39162306a36Sopenharmony_ci			}
39262306a36Sopenharmony_ci			break;
39362306a36Sopenharmony_ci		case CEXPR_NAMES:
39462306a36Sopenharmony_ci			if (sp == (CEXPR_MAXDEPTH-1))
39562306a36Sopenharmony_ci				return 0;
39662306a36Sopenharmony_ci			c = scontext;
39762306a36Sopenharmony_ci			if (e->attr & CEXPR_TARGET)
39862306a36Sopenharmony_ci				c = tcontext;
39962306a36Sopenharmony_ci			else if (e->attr & CEXPR_XTARGET) {
40062306a36Sopenharmony_ci				c = xcontext;
40162306a36Sopenharmony_ci				if (!c) {
40262306a36Sopenharmony_ci					BUG();
40362306a36Sopenharmony_ci					return 0;
40462306a36Sopenharmony_ci				}
40562306a36Sopenharmony_ci			}
40662306a36Sopenharmony_ci			if (e->attr & CEXPR_USER)
40762306a36Sopenharmony_ci				val1 = c->user;
40862306a36Sopenharmony_ci			else if (e->attr & CEXPR_ROLE)
40962306a36Sopenharmony_ci				val1 = c->role;
41062306a36Sopenharmony_ci			else if (e->attr & CEXPR_TYPE)
41162306a36Sopenharmony_ci				val1 = c->type;
41262306a36Sopenharmony_ci			else {
41362306a36Sopenharmony_ci				BUG();
41462306a36Sopenharmony_ci				return 0;
41562306a36Sopenharmony_ci			}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci			switch (e->op) {
41862306a36Sopenharmony_ci			case CEXPR_EQ:
41962306a36Sopenharmony_ci				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
42062306a36Sopenharmony_ci				break;
42162306a36Sopenharmony_ci			case CEXPR_NEQ:
42262306a36Sopenharmony_ci				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
42362306a36Sopenharmony_ci				break;
42462306a36Sopenharmony_ci			default:
42562306a36Sopenharmony_ci				BUG();
42662306a36Sopenharmony_ci				return 0;
42762306a36Sopenharmony_ci			}
42862306a36Sopenharmony_ci			break;
42962306a36Sopenharmony_ci		default:
43062306a36Sopenharmony_ci			BUG();
43162306a36Sopenharmony_ci			return 0;
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	BUG_ON(sp != 0);
43662306a36Sopenharmony_ci	return s[0];
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/*
44062306a36Sopenharmony_ci * security_dump_masked_av - dumps masked permissions during
44162306a36Sopenharmony_ci * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int dump_masked_av_helper(void *k, void *d, void *args)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	struct perm_datum *pdatum = d;
44662306a36Sopenharmony_ci	char **permission_names = args;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	permission_names[pdatum->value - 1] = (char *)k;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void security_dump_masked_av(struct policydb *policydb,
45662306a36Sopenharmony_ci				    struct context *scontext,
45762306a36Sopenharmony_ci				    struct context *tcontext,
45862306a36Sopenharmony_ci				    u16 tclass,
45962306a36Sopenharmony_ci				    u32 permissions,
46062306a36Sopenharmony_ci				    const char *reason)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct common_datum *common_dat;
46362306a36Sopenharmony_ci	struct class_datum *tclass_dat;
46462306a36Sopenharmony_ci	struct audit_buffer *ab;
46562306a36Sopenharmony_ci	char *tclass_name;
46662306a36Sopenharmony_ci	char *scontext_name = NULL;
46762306a36Sopenharmony_ci	char *tcontext_name = NULL;
46862306a36Sopenharmony_ci	char *permission_names[32];
46962306a36Sopenharmony_ci	int index;
47062306a36Sopenharmony_ci	u32 length;
47162306a36Sopenharmony_ci	bool need_comma = false;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (!permissions)
47462306a36Sopenharmony_ci		return;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
47762306a36Sopenharmony_ci	tclass_dat = policydb->class_val_to_struct[tclass - 1];
47862306a36Sopenharmony_ci	common_dat = tclass_dat->comdatum;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* init permission_names */
48162306a36Sopenharmony_ci	if (common_dat &&
48262306a36Sopenharmony_ci	    hashtab_map(&common_dat->permissions.table,
48362306a36Sopenharmony_ci			dump_masked_av_helper, permission_names) < 0)
48462306a36Sopenharmony_ci		goto out;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (hashtab_map(&tclass_dat->permissions.table,
48762306a36Sopenharmony_ci			dump_masked_av_helper, permission_names) < 0)
48862306a36Sopenharmony_ci		goto out;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* get scontext/tcontext in text form */
49162306a36Sopenharmony_ci	if (context_struct_to_string(policydb, scontext,
49262306a36Sopenharmony_ci				     &scontext_name, &length) < 0)
49362306a36Sopenharmony_ci		goto out;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (context_struct_to_string(policydb, tcontext,
49662306a36Sopenharmony_ci				     &tcontext_name, &length) < 0)
49762306a36Sopenharmony_ci		goto out;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* audit a message */
50062306a36Sopenharmony_ci	ab = audit_log_start(audit_context(),
50162306a36Sopenharmony_ci			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
50262306a36Sopenharmony_ci	if (!ab)
50362306a36Sopenharmony_ci		goto out;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	audit_log_format(ab, "op=security_compute_av reason=%s "
50662306a36Sopenharmony_ci			 "scontext=%s tcontext=%s tclass=%s perms=",
50762306a36Sopenharmony_ci			 reason, scontext_name, tcontext_name, tclass_name);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	for (index = 0; index < 32; index++) {
51062306a36Sopenharmony_ci		u32 mask = (1 << index);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		if ((mask & permissions) == 0)
51362306a36Sopenharmony_ci			continue;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		audit_log_format(ab, "%s%s",
51662306a36Sopenharmony_ci				 need_comma ? "," : "",
51762306a36Sopenharmony_ci				 permission_names[index]
51862306a36Sopenharmony_ci				 ? permission_names[index] : "????");
51962306a36Sopenharmony_ci		need_comma = true;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci	audit_log_end(ab);
52262306a36Sopenharmony_ciout:
52362306a36Sopenharmony_ci	/* release scontext/tcontext */
52462306a36Sopenharmony_ci	kfree(tcontext_name);
52562306a36Sopenharmony_ci	kfree(scontext_name);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/*
52962306a36Sopenharmony_ci * security_boundary_permission - drops violated permissions
53062306a36Sopenharmony_ci * on boundary constraint.
53162306a36Sopenharmony_ci */
53262306a36Sopenharmony_cistatic void type_attribute_bounds_av(struct policydb *policydb,
53362306a36Sopenharmony_ci				     struct context *scontext,
53462306a36Sopenharmony_ci				     struct context *tcontext,
53562306a36Sopenharmony_ci				     u16 tclass,
53662306a36Sopenharmony_ci				     struct av_decision *avd)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct context lo_scontext;
53962306a36Sopenharmony_ci	struct context lo_tcontext, *tcontextp = tcontext;
54062306a36Sopenharmony_ci	struct av_decision lo_avd;
54162306a36Sopenharmony_ci	struct type_datum *source;
54262306a36Sopenharmony_ci	struct type_datum *target;
54362306a36Sopenharmony_ci	u32 masked = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	source = policydb->type_val_to_struct[scontext->type - 1];
54662306a36Sopenharmony_ci	BUG_ON(!source);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (!source->bounds)
54962306a36Sopenharmony_ci		return;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	target = policydb->type_val_to_struct[tcontext->type - 1];
55262306a36Sopenharmony_ci	BUG_ON(!target);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	memset(&lo_avd, 0, sizeof(lo_avd));
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
55762306a36Sopenharmony_ci	lo_scontext.type = source->bounds;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (target->bounds) {
56062306a36Sopenharmony_ci		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
56162306a36Sopenharmony_ci		lo_tcontext.type = target->bounds;
56262306a36Sopenharmony_ci		tcontextp = &lo_tcontext;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	context_struct_compute_av(policydb, &lo_scontext,
56662306a36Sopenharmony_ci				  tcontextp,
56762306a36Sopenharmony_ci				  tclass,
56862306a36Sopenharmony_ci				  &lo_avd,
56962306a36Sopenharmony_ci				  NULL);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	masked = ~lo_avd.allowed & avd->allowed;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (likely(!masked))
57462306a36Sopenharmony_ci		return;		/* no masked permission */
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* mask violated permissions */
57762306a36Sopenharmony_ci	avd->allowed &= ~masked;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* audit masked permissions */
58062306a36Sopenharmony_ci	security_dump_masked_av(policydb, scontext, tcontext,
58162306a36Sopenharmony_ci				tclass, masked, "bounds");
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/*
58562306a36Sopenharmony_ci * flag which drivers have permissions
58662306a36Sopenharmony_ci * only looking for ioctl based extended permissions
58762306a36Sopenharmony_ci */
58862306a36Sopenharmony_civoid services_compute_xperms_drivers(
58962306a36Sopenharmony_ci		struct extended_perms *xperms,
59062306a36Sopenharmony_ci		struct avtab_node *node)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	unsigned int i;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
59562306a36Sopenharmony_ci		/* if one or more driver has all permissions allowed */
59662306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
59762306a36Sopenharmony_ci			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
59862306a36Sopenharmony_ci	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
59962306a36Sopenharmony_ci		/* if allowing permissions within a driver */
60062306a36Sopenharmony_ci		security_xperm_set(xperms->drivers.p,
60162306a36Sopenharmony_ci					node->datum.u.xperms->driver);
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	xperms->len = 1;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci/*
60862306a36Sopenharmony_ci * Compute access vectors and extended permissions based on a context
60962306a36Sopenharmony_ci * structure pair for the permissions in a particular class.
61062306a36Sopenharmony_ci */
61162306a36Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb,
61262306a36Sopenharmony_ci				      struct context *scontext,
61362306a36Sopenharmony_ci				      struct context *tcontext,
61462306a36Sopenharmony_ci				      u16 tclass,
61562306a36Sopenharmony_ci				      struct av_decision *avd,
61662306a36Sopenharmony_ci				      struct extended_perms *xperms)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct constraint_node *constraint;
61962306a36Sopenharmony_ci	struct role_allow *ra;
62062306a36Sopenharmony_ci	struct avtab_key avkey;
62162306a36Sopenharmony_ci	struct avtab_node *node;
62262306a36Sopenharmony_ci	struct class_datum *tclass_datum;
62362306a36Sopenharmony_ci	struct ebitmap *sattr, *tattr;
62462306a36Sopenharmony_ci	struct ebitmap_node *snode, *tnode;
62562306a36Sopenharmony_ci	unsigned int i, j;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	avd->allowed = 0;
62862306a36Sopenharmony_ci	avd->auditallow = 0;
62962306a36Sopenharmony_ci	avd->auditdeny = 0xffffffff;
63062306a36Sopenharmony_ci	if (xperms) {
63162306a36Sopenharmony_ci		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
63262306a36Sopenharmony_ci		xperms->len = 0;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
63662306a36Sopenharmony_ci		if (printk_ratelimit())
63762306a36Sopenharmony_ci			pr_warn("SELinux:  Invalid class %hu\n", tclass);
63862306a36Sopenharmony_ci		return;
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	tclass_datum = policydb->class_val_to_struct[tclass - 1];
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/*
64462306a36Sopenharmony_ci	 * If a specific type enforcement rule was defined for
64562306a36Sopenharmony_ci	 * this permission check, then use it.
64662306a36Sopenharmony_ci	 */
64762306a36Sopenharmony_ci	avkey.target_class = tclass;
64862306a36Sopenharmony_ci	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
64962306a36Sopenharmony_ci	sattr = &policydb->type_attr_map_array[scontext->type - 1];
65062306a36Sopenharmony_ci	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
65162306a36Sopenharmony_ci	ebitmap_for_each_positive_bit(sattr, snode, i) {
65262306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(tattr, tnode, j) {
65362306a36Sopenharmony_ci			avkey.source_type = i + 1;
65462306a36Sopenharmony_ci			avkey.target_type = j + 1;
65562306a36Sopenharmony_ci			for (node = avtab_search_node(&policydb->te_avtab,
65662306a36Sopenharmony_ci						      &avkey);
65762306a36Sopenharmony_ci			     node;
65862306a36Sopenharmony_ci			     node = avtab_search_node_next(node, avkey.specified)) {
65962306a36Sopenharmony_ci				if (node->key.specified == AVTAB_ALLOWED)
66062306a36Sopenharmony_ci					avd->allowed |= node->datum.u.data;
66162306a36Sopenharmony_ci				else if (node->key.specified == AVTAB_AUDITALLOW)
66262306a36Sopenharmony_ci					avd->auditallow |= node->datum.u.data;
66362306a36Sopenharmony_ci				else if (node->key.specified == AVTAB_AUDITDENY)
66462306a36Sopenharmony_ci					avd->auditdeny &= node->datum.u.data;
66562306a36Sopenharmony_ci				else if (xperms && (node->key.specified & AVTAB_XPERMS))
66662306a36Sopenharmony_ci					services_compute_xperms_drivers(xperms, node);
66762306a36Sopenharmony_ci			}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci			/* Check conditional av table for additional permissions */
67062306a36Sopenharmony_ci			cond_compute_av(&policydb->te_cond_avtab, &avkey,
67162306a36Sopenharmony_ci					avd, xperms);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/*
67762306a36Sopenharmony_ci	 * Remove any permissions prohibited by a constraint (this includes
67862306a36Sopenharmony_ci	 * the MLS policy).
67962306a36Sopenharmony_ci	 */
68062306a36Sopenharmony_ci	constraint = tclass_datum->constraints;
68162306a36Sopenharmony_ci	while (constraint) {
68262306a36Sopenharmony_ci		if ((constraint->permissions & (avd->allowed)) &&
68362306a36Sopenharmony_ci		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
68462306a36Sopenharmony_ci					  constraint->expr)) {
68562306a36Sopenharmony_ci			avd->allowed &= ~(constraint->permissions);
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		constraint = constraint->next;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/*
69162306a36Sopenharmony_ci	 * If checking process transition permission and the
69262306a36Sopenharmony_ci	 * role is changing, then check the (current_role, new_role)
69362306a36Sopenharmony_ci	 * pair.
69462306a36Sopenharmony_ci	 */
69562306a36Sopenharmony_ci	if (tclass == policydb->process_class &&
69662306a36Sopenharmony_ci	    (avd->allowed & policydb->process_trans_perms) &&
69762306a36Sopenharmony_ci	    scontext->role != tcontext->role) {
69862306a36Sopenharmony_ci		for (ra = policydb->role_allow; ra; ra = ra->next) {
69962306a36Sopenharmony_ci			if (scontext->role == ra->role &&
70062306a36Sopenharmony_ci			    tcontext->role == ra->new_role)
70162306a36Sopenharmony_ci				break;
70262306a36Sopenharmony_ci		}
70362306a36Sopenharmony_ci		if (!ra)
70462306a36Sopenharmony_ci			avd->allowed &= ~policydb->process_trans_perms;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/*
70862306a36Sopenharmony_ci	 * If the given source and target types have boundary
70962306a36Sopenharmony_ci	 * constraint, lazy checks have to mask any violated
71062306a36Sopenharmony_ci	 * permission and notice it to userspace via audit.
71162306a36Sopenharmony_ci	 */
71262306a36Sopenharmony_ci	type_attribute_bounds_av(policydb, scontext, tcontext,
71362306a36Sopenharmony_ci				 tclass, avd);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int security_validtrans_handle_fail(struct selinux_policy *policy,
71762306a36Sopenharmony_ci					struct sidtab_entry *oentry,
71862306a36Sopenharmony_ci					struct sidtab_entry *nentry,
71962306a36Sopenharmony_ci					struct sidtab_entry *tentry,
72062306a36Sopenharmony_ci					u16 tclass)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct policydb *p = &policy->policydb;
72362306a36Sopenharmony_ci	struct sidtab *sidtab = policy->sidtab;
72462306a36Sopenharmony_ci	char *o = NULL, *n = NULL, *t = NULL;
72562306a36Sopenharmony_ci	u32 olen, nlen, tlen;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen))
72862306a36Sopenharmony_ci		goto out;
72962306a36Sopenharmony_ci	if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen))
73062306a36Sopenharmony_ci		goto out;
73162306a36Sopenharmony_ci	if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen))
73262306a36Sopenharmony_ci		goto out;
73362306a36Sopenharmony_ci	audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
73462306a36Sopenharmony_ci		  "op=security_validate_transition seresult=denied"
73562306a36Sopenharmony_ci		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
73662306a36Sopenharmony_ci		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
73762306a36Sopenharmony_ciout:
73862306a36Sopenharmony_ci	kfree(o);
73962306a36Sopenharmony_ci	kfree(n);
74062306a36Sopenharmony_ci	kfree(t);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (!enforcing_enabled())
74362306a36Sopenharmony_ci		return 0;
74462306a36Sopenharmony_ci	return -EPERM;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
74862306a36Sopenharmony_ci					  u16 orig_tclass, bool user)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct selinux_policy *policy;
75162306a36Sopenharmony_ci	struct policydb *policydb;
75262306a36Sopenharmony_ci	struct sidtab *sidtab;
75362306a36Sopenharmony_ci	struct sidtab_entry *oentry;
75462306a36Sopenharmony_ci	struct sidtab_entry *nentry;
75562306a36Sopenharmony_ci	struct sidtab_entry *tentry;
75662306a36Sopenharmony_ci	struct class_datum *tclass_datum;
75762306a36Sopenharmony_ci	struct constraint_node *constraint;
75862306a36Sopenharmony_ci	u16 tclass;
75962306a36Sopenharmony_ci	int rc = 0;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (!selinux_initialized())
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	rcu_read_lock();
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
76862306a36Sopenharmony_ci	policydb = &policy->policydb;
76962306a36Sopenharmony_ci	sidtab = policy->sidtab;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (!user)
77262306a36Sopenharmony_ci		tclass = unmap_class(&policy->map, orig_tclass);
77362306a36Sopenharmony_ci	else
77462306a36Sopenharmony_ci		tclass = orig_tclass;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (!tclass || tclass > policydb->p_classes.nprim) {
77762306a36Sopenharmony_ci		rc = -EINVAL;
77862306a36Sopenharmony_ci		goto out;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci	tclass_datum = policydb->class_val_to_struct[tclass - 1];
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	oentry = sidtab_search_entry(sidtab, oldsid);
78362306a36Sopenharmony_ci	if (!oentry) {
78462306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
78562306a36Sopenharmony_ci			__func__, oldsid);
78662306a36Sopenharmony_ci		rc = -EINVAL;
78762306a36Sopenharmony_ci		goto out;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	nentry = sidtab_search_entry(sidtab, newsid);
79162306a36Sopenharmony_ci	if (!nentry) {
79262306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
79362306a36Sopenharmony_ci			__func__, newsid);
79462306a36Sopenharmony_ci		rc = -EINVAL;
79562306a36Sopenharmony_ci		goto out;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	tentry = sidtab_search_entry(sidtab, tasksid);
79962306a36Sopenharmony_ci	if (!tentry) {
80062306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
80162306a36Sopenharmony_ci			__func__, tasksid);
80262306a36Sopenharmony_ci		rc = -EINVAL;
80362306a36Sopenharmony_ci		goto out;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	constraint = tclass_datum->validatetrans;
80762306a36Sopenharmony_ci	while (constraint) {
80862306a36Sopenharmony_ci		if (!constraint_expr_eval(policydb, &oentry->context,
80962306a36Sopenharmony_ci					  &nentry->context, &tentry->context,
81062306a36Sopenharmony_ci					  constraint->expr)) {
81162306a36Sopenharmony_ci			if (user)
81262306a36Sopenharmony_ci				rc = -EPERM;
81362306a36Sopenharmony_ci			else
81462306a36Sopenharmony_ci				rc = security_validtrans_handle_fail(policy,
81562306a36Sopenharmony_ci								oentry,
81662306a36Sopenharmony_ci								nentry,
81762306a36Sopenharmony_ci								tentry,
81862306a36Sopenharmony_ci								tclass);
81962306a36Sopenharmony_ci			goto out;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci		constraint = constraint->next;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ciout:
82562306a36Sopenharmony_ci	rcu_read_unlock();
82662306a36Sopenharmony_ci	return rc;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ciint security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
83062306a36Sopenharmony_ci				      u16 tclass)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	return security_compute_validatetrans(oldsid, newsid, tasksid,
83362306a36Sopenharmony_ci					      tclass, true);
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ciint security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
83762306a36Sopenharmony_ci				 u16 orig_tclass)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	return security_compute_validatetrans(oldsid, newsid, tasksid,
84062306a36Sopenharmony_ci					      orig_tclass, false);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/*
84462306a36Sopenharmony_ci * security_bounded_transition - check whether the given
84562306a36Sopenharmony_ci * transition is directed to bounded, or not.
84662306a36Sopenharmony_ci * It returns 0, if @newsid is bounded by @oldsid.
84762306a36Sopenharmony_ci * Otherwise, it returns error code.
84862306a36Sopenharmony_ci *
84962306a36Sopenharmony_ci * @oldsid : current security identifier
85062306a36Sopenharmony_ci * @newsid : destinated security identifier
85162306a36Sopenharmony_ci */
85262306a36Sopenharmony_ciint security_bounded_transition(u32 old_sid, u32 new_sid)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct selinux_policy *policy;
85562306a36Sopenharmony_ci	struct policydb *policydb;
85662306a36Sopenharmony_ci	struct sidtab *sidtab;
85762306a36Sopenharmony_ci	struct sidtab_entry *old_entry, *new_entry;
85862306a36Sopenharmony_ci	struct type_datum *type;
85962306a36Sopenharmony_ci	u32 index;
86062306a36Sopenharmony_ci	int rc;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (!selinux_initialized())
86362306a36Sopenharmony_ci		return 0;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	rcu_read_lock();
86662306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
86762306a36Sopenharmony_ci	policydb = &policy->policydb;
86862306a36Sopenharmony_ci	sidtab = policy->sidtab;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	rc = -EINVAL;
87162306a36Sopenharmony_ci	old_entry = sidtab_search_entry(sidtab, old_sid);
87262306a36Sopenharmony_ci	if (!old_entry) {
87362306a36Sopenharmony_ci		pr_err("SELinux: %s: unrecognized SID %u\n",
87462306a36Sopenharmony_ci		       __func__, old_sid);
87562306a36Sopenharmony_ci		goto out;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	rc = -EINVAL;
87962306a36Sopenharmony_ci	new_entry = sidtab_search_entry(sidtab, new_sid);
88062306a36Sopenharmony_ci	if (!new_entry) {
88162306a36Sopenharmony_ci		pr_err("SELinux: %s: unrecognized SID %u\n",
88262306a36Sopenharmony_ci		       __func__, new_sid);
88362306a36Sopenharmony_ci		goto out;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	rc = 0;
88762306a36Sopenharmony_ci	/* type/domain unchanged */
88862306a36Sopenharmony_ci	if (old_entry->context.type == new_entry->context.type)
88962306a36Sopenharmony_ci		goto out;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	index = new_entry->context.type;
89262306a36Sopenharmony_ci	while (true) {
89362306a36Sopenharmony_ci		type = policydb->type_val_to_struct[index - 1];
89462306a36Sopenharmony_ci		BUG_ON(!type);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		/* not bounded anymore */
89762306a36Sopenharmony_ci		rc = -EPERM;
89862306a36Sopenharmony_ci		if (!type->bounds)
89962306a36Sopenharmony_ci			break;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		/* @newsid is bounded by @oldsid */
90262306a36Sopenharmony_ci		rc = 0;
90362306a36Sopenharmony_ci		if (type->bounds == old_entry->context.type)
90462306a36Sopenharmony_ci			break;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci		index = type->bounds;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (rc) {
91062306a36Sopenharmony_ci		char *old_name = NULL;
91162306a36Sopenharmony_ci		char *new_name = NULL;
91262306a36Sopenharmony_ci		u32 length;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		if (!sidtab_entry_to_string(policydb, sidtab, old_entry,
91562306a36Sopenharmony_ci					    &old_name, &length) &&
91662306a36Sopenharmony_ci		    !sidtab_entry_to_string(policydb, sidtab, new_entry,
91762306a36Sopenharmony_ci					    &new_name, &length)) {
91862306a36Sopenharmony_ci			audit_log(audit_context(),
91962306a36Sopenharmony_ci				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
92062306a36Sopenharmony_ci				  "op=security_bounded_transition "
92162306a36Sopenharmony_ci				  "seresult=denied "
92262306a36Sopenharmony_ci				  "oldcontext=%s newcontext=%s",
92362306a36Sopenharmony_ci				  old_name, new_name);
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci		kfree(new_name);
92662306a36Sopenharmony_ci		kfree(old_name);
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ciout:
92962306a36Sopenharmony_ci	rcu_read_unlock();
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	return rc;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic void avd_init(struct selinux_policy *policy, struct av_decision *avd)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	avd->allowed = 0;
93762306a36Sopenharmony_ci	avd->auditallow = 0;
93862306a36Sopenharmony_ci	avd->auditdeny = 0xffffffff;
93962306a36Sopenharmony_ci	if (policy)
94062306a36Sopenharmony_ci		avd->seqno = policy->latest_granting;
94162306a36Sopenharmony_ci	else
94262306a36Sopenharmony_ci		avd->seqno = 0;
94362306a36Sopenharmony_ci	avd->flags = 0;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_civoid services_compute_xperms_decision(struct extended_perms_decision *xpermd,
94762306a36Sopenharmony_ci					struct avtab_node *node)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	unsigned int i;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
95262306a36Sopenharmony_ci		if (xpermd->driver != node->datum.u.xperms->driver)
95362306a36Sopenharmony_ci			return;
95462306a36Sopenharmony_ci	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
95562306a36Sopenharmony_ci		if (!security_xperm_test(node->datum.u.xperms->perms.p,
95662306a36Sopenharmony_ci					xpermd->driver))
95762306a36Sopenharmony_ci			return;
95862306a36Sopenharmony_ci	} else {
95962306a36Sopenharmony_ci		BUG();
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
96362306a36Sopenharmony_ci		xpermd->used |= XPERMS_ALLOWED;
96462306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
96562306a36Sopenharmony_ci			memset(xpermd->allowed->p, 0xff,
96662306a36Sopenharmony_ci					sizeof(xpermd->allowed->p));
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
96962306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
97062306a36Sopenharmony_ci				xpermd->allowed->p[i] |=
97162306a36Sopenharmony_ci					node->datum.u.xperms->perms.p[i];
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
97462306a36Sopenharmony_ci		xpermd->used |= XPERMS_AUDITALLOW;
97562306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
97662306a36Sopenharmony_ci			memset(xpermd->auditallow->p, 0xff,
97762306a36Sopenharmony_ci					sizeof(xpermd->auditallow->p));
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
98062306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
98162306a36Sopenharmony_ci				xpermd->auditallow->p[i] |=
98262306a36Sopenharmony_ci					node->datum.u.xperms->perms.p[i];
98362306a36Sopenharmony_ci		}
98462306a36Sopenharmony_ci	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
98562306a36Sopenharmony_ci		xpermd->used |= XPERMS_DONTAUDIT;
98662306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
98762306a36Sopenharmony_ci			memset(xpermd->dontaudit->p, 0xff,
98862306a36Sopenharmony_ci					sizeof(xpermd->dontaudit->p));
98962306a36Sopenharmony_ci		}
99062306a36Sopenharmony_ci		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
99162306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
99262306a36Sopenharmony_ci				xpermd->dontaudit->p[i] |=
99362306a36Sopenharmony_ci					node->datum.u.xperms->perms.p[i];
99462306a36Sopenharmony_ci		}
99562306a36Sopenharmony_ci	} else {
99662306a36Sopenharmony_ci		BUG();
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_civoid security_compute_xperms_decision(u32 ssid,
100162306a36Sopenharmony_ci				      u32 tsid,
100262306a36Sopenharmony_ci				      u16 orig_tclass,
100362306a36Sopenharmony_ci				      u8 driver,
100462306a36Sopenharmony_ci				      struct extended_perms_decision *xpermd)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct selinux_policy *policy;
100762306a36Sopenharmony_ci	struct policydb *policydb;
100862306a36Sopenharmony_ci	struct sidtab *sidtab;
100962306a36Sopenharmony_ci	u16 tclass;
101062306a36Sopenharmony_ci	struct context *scontext, *tcontext;
101162306a36Sopenharmony_ci	struct avtab_key avkey;
101262306a36Sopenharmony_ci	struct avtab_node *node;
101362306a36Sopenharmony_ci	struct ebitmap *sattr, *tattr;
101462306a36Sopenharmony_ci	struct ebitmap_node *snode, *tnode;
101562306a36Sopenharmony_ci	unsigned int i, j;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	xpermd->driver = driver;
101862306a36Sopenharmony_ci	xpermd->used = 0;
101962306a36Sopenharmony_ci	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
102062306a36Sopenharmony_ci	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
102162306a36Sopenharmony_ci	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	rcu_read_lock();
102462306a36Sopenharmony_ci	if (!selinux_initialized())
102562306a36Sopenharmony_ci		goto allow;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
102862306a36Sopenharmony_ci	policydb = &policy->policydb;
102962306a36Sopenharmony_ci	sidtab = policy->sidtab;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	scontext = sidtab_search(sidtab, ssid);
103262306a36Sopenharmony_ci	if (!scontext) {
103362306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
103462306a36Sopenharmony_ci		       __func__, ssid);
103562306a36Sopenharmony_ci		goto out;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	tcontext = sidtab_search(sidtab, tsid);
103962306a36Sopenharmony_ci	if (!tcontext) {
104062306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
104162306a36Sopenharmony_ci		       __func__, tsid);
104262306a36Sopenharmony_ci		goto out;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	tclass = unmap_class(&policy->map, orig_tclass);
104662306a36Sopenharmony_ci	if (unlikely(orig_tclass && !tclass)) {
104762306a36Sopenharmony_ci		if (policydb->allow_unknown)
104862306a36Sopenharmony_ci			goto allow;
104962306a36Sopenharmony_ci		goto out;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
105462306a36Sopenharmony_ci		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
105562306a36Sopenharmony_ci		goto out;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	avkey.target_class = tclass;
105962306a36Sopenharmony_ci	avkey.specified = AVTAB_XPERMS;
106062306a36Sopenharmony_ci	sattr = &policydb->type_attr_map_array[scontext->type - 1];
106162306a36Sopenharmony_ci	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
106262306a36Sopenharmony_ci	ebitmap_for_each_positive_bit(sattr, snode, i) {
106362306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(tattr, tnode, j) {
106462306a36Sopenharmony_ci			avkey.source_type = i + 1;
106562306a36Sopenharmony_ci			avkey.target_type = j + 1;
106662306a36Sopenharmony_ci			for (node = avtab_search_node(&policydb->te_avtab,
106762306a36Sopenharmony_ci						      &avkey);
106862306a36Sopenharmony_ci			     node;
106962306a36Sopenharmony_ci			     node = avtab_search_node_next(node, avkey.specified))
107062306a36Sopenharmony_ci				services_compute_xperms_decision(xpermd, node);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci			cond_compute_xperms(&policydb->te_cond_avtab,
107362306a36Sopenharmony_ci						&avkey, xpermd);
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ciout:
107762306a36Sopenharmony_ci	rcu_read_unlock();
107862306a36Sopenharmony_ci	return;
107962306a36Sopenharmony_ciallow:
108062306a36Sopenharmony_ci	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
108162306a36Sopenharmony_ci	goto out;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci/**
108562306a36Sopenharmony_ci * security_compute_av - Compute access vector decisions.
108662306a36Sopenharmony_ci * @ssid: source security identifier
108762306a36Sopenharmony_ci * @tsid: target security identifier
108862306a36Sopenharmony_ci * @orig_tclass: target security class
108962306a36Sopenharmony_ci * @avd: access vector decisions
109062306a36Sopenharmony_ci * @xperms: extended permissions
109162306a36Sopenharmony_ci *
109262306a36Sopenharmony_ci * Compute a set of access vector decisions based on the
109362306a36Sopenharmony_ci * SID pair (@ssid, @tsid) for the permissions in @tclass.
109462306a36Sopenharmony_ci */
109562306a36Sopenharmony_civoid security_compute_av(u32 ssid,
109662306a36Sopenharmony_ci			 u32 tsid,
109762306a36Sopenharmony_ci			 u16 orig_tclass,
109862306a36Sopenharmony_ci			 struct av_decision *avd,
109962306a36Sopenharmony_ci			 struct extended_perms *xperms)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	struct selinux_policy *policy;
110262306a36Sopenharmony_ci	struct policydb *policydb;
110362306a36Sopenharmony_ci	struct sidtab *sidtab;
110462306a36Sopenharmony_ci	u16 tclass;
110562306a36Sopenharmony_ci	struct context *scontext = NULL, *tcontext = NULL;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	rcu_read_lock();
110862306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
110962306a36Sopenharmony_ci	avd_init(policy, avd);
111062306a36Sopenharmony_ci	xperms->len = 0;
111162306a36Sopenharmony_ci	if (!selinux_initialized())
111262306a36Sopenharmony_ci		goto allow;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	policydb = &policy->policydb;
111562306a36Sopenharmony_ci	sidtab = policy->sidtab;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	scontext = sidtab_search(sidtab, ssid);
111862306a36Sopenharmony_ci	if (!scontext) {
111962306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
112062306a36Sopenharmony_ci		       __func__, ssid);
112162306a36Sopenharmony_ci		goto out;
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	/* permissive domain? */
112562306a36Sopenharmony_ci	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
112662306a36Sopenharmony_ci		avd->flags |= AVD_FLAGS_PERMISSIVE;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	tcontext = sidtab_search(sidtab, tsid);
112962306a36Sopenharmony_ci	if (!tcontext) {
113062306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
113162306a36Sopenharmony_ci		       __func__, tsid);
113262306a36Sopenharmony_ci		goto out;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	tclass = unmap_class(&policy->map, orig_tclass);
113662306a36Sopenharmony_ci	if (unlikely(orig_tclass && !tclass)) {
113762306a36Sopenharmony_ci		if (policydb->allow_unknown)
113862306a36Sopenharmony_ci			goto allow;
113962306a36Sopenharmony_ci		goto out;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
114262306a36Sopenharmony_ci				  xperms);
114362306a36Sopenharmony_ci	map_decision(&policy->map, orig_tclass, avd,
114462306a36Sopenharmony_ci		     policydb->allow_unknown);
114562306a36Sopenharmony_ciout:
114662306a36Sopenharmony_ci	rcu_read_unlock();
114762306a36Sopenharmony_ci	return;
114862306a36Sopenharmony_ciallow:
114962306a36Sopenharmony_ci	avd->allowed = 0xffffffff;
115062306a36Sopenharmony_ci	goto out;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_civoid security_compute_av_user(u32 ssid,
115462306a36Sopenharmony_ci			      u32 tsid,
115562306a36Sopenharmony_ci			      u16 tclass,
115662306a36Sopenharmony_ci			      struct av_decision *avd)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	struct selinux_policy *policy;
115962306a36Sopenharmony_ci	struct policydb *policydb;
116062306a36Sopenharmony_ci	struct sidtab *sidtab;
116162306a36Sopenharmony_ci	struct context *scontext = NULL, *tcontext = NULL;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	rcu_read_lock();
116462306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
116562306a36Sopenharmony_ci	avd_init(policy, avd);
116662306a36Sopenharmony_ci	if (!selinux_initialized())
116762306a36Sopenharmony_ci		goto allow;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	policydb = &policy->policydb;
117062306a36Sopenharmony_ci	sidtab = policy->sidtab;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	scontext = sidtab_search(sidtab, ssid);
117362306a36Sopenharmony_ci	if (!scontext) {
117462306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
117562306a36Sopenharmony_ci		       __func__, ssid);
117662306a36Sopenharmony_ci		goto out;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* permissive domain? */
118062306a36Sopenharmony_ci	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
118162306a36Sopenharmony_ci		avd->flags |= AVD_FLAGS_PERMISSIVE;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	tcontext = sidtab_search(sidtab, tsid);
118462306a36Sopenharmony_ci	if (!tcontext) {
118562306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
118662306a36Sopenharmony_ci		       __func__, tsid);
118762306a36Sopenharmony_ci		goto out;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (unlikely(!tclass)) {
119162306a36Sopenharmony_ci		if (policydb->allow_unknown)
119262306a36Sopenharmony_ci			goto allow;
119362306a36Sopenharmony_ci		goto out;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
119762306a36Sopenharmony_ci				  NULL);
119862306a36Sopenharmony_ci out:
119962306a36Sopenharmony_ci	rcu_read_unlock();
120062306a36Sopenharmony_ci	return;
120162306a36Sopenharmony_ciallow:
120262306a36Sopenharmony_ci	avd->allowed = 0xffffffff;
120362306a36Sopenharmony_ci	goto out;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci/*
120762306a36Sopenharmony_ci * Write the security context string representation of
120862306a36Sopenharmony_ci * the context structure `context' into a dynamically
120962306a36Sopenharmony_ci * allocated string of the correct size.  Set `*scontext'
121062306a36Sopenharmony_ci * to point to this string and set `*scontext_len' to
121162306a36Sopenharmony_ci * the length of the string.
121262306a36Sopenharmony_ci */
121362306a36Sopenharmony_cistatic int context_struct_to_string(struct policydb *p,
121462306a36Sopenharmony_ci				    struct context *context,
121562306a36Sopenharmony_ci				    char **scontext, u32 *scontext_len)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	char *scontextp;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (scontext)
122062306a36Sopenharmony_ci		*scontext = NULL;
122162306a36Sopenharmony_ci	*scontext_len = 0;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (context->len) {
122462306a36Sopenharmony_ci		*scontext_len = context->len;
122562306a36Sopenharmony_ci		if (scontext) {
122662306a36Sopenharmony_ci			*scontext = kstrdup(context->str, GFP_ATOMIC);
122762306a36Sopenharmony_ci			if (!(*scontext))
122862306a36Sopenharmony_ci				return -ENOMEM;
122962306a36Sopenharmony_ci		}
123062306a36Sopenharmony_ci		return 0;
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* Compute the size of the context. */
123462306a36Sopenharmony_ci	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
123562306a36Sopenharmony_ci	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
123662306a36Sopenharmony_ci	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
123762306a36Sopenharmony_ci	*scontext_len += mls_compute_context_len(p, context);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (!scontext)
124062306a36Sopenharmony_ci		return 0;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* Allocate space for the context; caller must free this space. */
124362306a36Sopenharmony_ci	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
124462306a36Sopenharmony_ci	if (!scontextp)
124562306a36Sopenharmony_ci		return -ENOMEM;
124662306a36Sopenharmony_ci	*scontext = scontextp;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/*
124962306a36Sopenharmony_ci	 * Copy the user name, role name and type name into the context.
125062306a36Sopenharmony_ci	 */
125162306a36Sopenharmony_ci	scontextp += sprintf(scontextp, "%s:%s:%s",
125262306a36Sopenharmony_ci		sym_name(p, SYM_USERS, context->user - 1),
125362306a36Sopenharmony_ci		sym_name(p, SYM_ROLES, context->role - 1),
125462306a36Sopenharmony_ci		sym_name(p, SYM_TYPES, context->type - 1));
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	mls_sid_to_context(p, context, &scontextp);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	*scontextp = 0;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	return 0;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *p,
126462306a36Sopenharmony_ci				  struct sidtab *sidtab,
126562306a36Sopenharmony_ci				  struct sidtab_entry *entry,
126662306a36Sopenharmony_ci				  char **scontext, u32 *scontext_len)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if (rc != -ENOENT)
127162306a36Sopenharmony_ci		return rc;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	rc = context_struct_to_string(p, &entry->context, scontext,
127462306a36Sopenharmony_ci				      scontext_len);
127562306a36Sopenharmony_ci	if (!rc && scontext)
127662306a36Sopenharmony_ci		sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
127762306a36Sopenharmony_ci	return rc;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci#include "initial_sid_to_string.h"
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ciint security_sidtab_hash_stats(char *page)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct selinux_policy *policy;
128562306a36Sopenharmony_ci	int rc;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (!selinux_initialized()) {
128862306a36Sopenharmony_ci		pr_err("SELinux: %s:  called before initial load_policy\n",
128962306a36Sopenharmony_ci		       __func__);
129062306a36Sopenharmony_ci		return -EINVAL;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	rcu_read_lock();
129462306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
129562306a36Sopenharmony_ci	rc = sidtab_hash_stats(policy->sidtab, page);
129662306a36Sopenharmony_ci	rcu_read_unlock();
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	return rc;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ciconst char *security_get_initial_sid_context(u32 sid)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	if (unlikely(sid > SECINITSID_NUM))
130462306a36Sopenharmony_ci		return NULL;
130562306a36Sopenharmony_ci	return initial_sid_to_string[sid];
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int security_sid_to_context_core(u32 sid, char **scontext,
130962306a36Sopenharmony_ci					u32 *scontext_len, int force,
131062306a36Sopenharmony_ci					int only_invalid)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	struct selinux_policy *policy;
131362306a36Sopenharmony_ci	struct policydb *policydb;
131462306a36Sopenharmony_ci	struct sidtab *sidtab;
131562306a36Sopenharmony_ci	struct sidtab_entry *entry;
131662306a36Sopenharmony_ci	int rc = 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (scontext)
131962306a36Sopenharmony_ci		*scontext = NULL;
132062306a36Sopenharmony_ci	*scontext_len  = 0;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (!selinux_initialized()) {
132362306a36Sopenharmony_ci		if (sid <= SECINITSID_NUM) {
132462306a36Sopenharmony_ci			char *scontextp;
132562306a36Sopenharmony_ci			const char *s = initial_sid_to_string[sid];
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci			if (!s)
132862306a36Sopenharmony_ci				return -EINVAL;
132962306a36Sopenharmony_ci			*scontext_len = strlen(s) + 1;
133062306a36Sopenharmony_ci			if (!scontext)
133162306a36Sopenharmony_ci				return 0;
133262306a36Sopenharmony_ci			scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
133362306a36Sopenharmony_ci			if (!scontextp)
133462306a36Sopenharmony_ci				return -ENOMEM;
133562306a36Sopenharmony_ci			*scontext = scontextp;
133662306a36Sopenharmony_ci			return 0;
133762306a36Sopenharmony_ci		}
133862306a36Sopenharmony_ci		pr_err("SELinux: %s:  called before initial "
133962306a36Sopenharmony_ci		       "load_policy on unknown SID %d\n", __func__, sid);
134062306a36Sopenharmony_ci		return -EINVAL;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	rcu_read_lock();
134362306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
134462306a36Sopenharmony_ci	policydb = &policy->policydb;
134562306a36Sopenharmony_ci	sidtab = policy->sidtab;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (force)
134862306a36Sopenharmony_ci		entry = sidtab_search_entry_force(sidtab, sid);
134962306a36Sopenharmony_ci	else
135062306a36Sopenharmony_ci		entry = sidtab_search_entry(sidtab, sid);
135162306a36Sopenharmony_ci	if (!entry) {
135262306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
135362306a36Sopenharmony_ci			__func__, sid);
135462306a36Sopenharmony_ci		rc = -EINVAL;
135562306a36Sopenharmony_ci		goto out_unlock;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci	if (only_invalid && !entry->context.len)
135862306a36Sopenharmony_ci		goto out_unlock;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
136162306a36Sopenharmony_ci				    scontext_len);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ciout_unlock:
136462306a36Sopenharmony_ci	rcu_read_unlock();
136562306a36Sopenharmony_ci	return rc;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci/**
137062306a36Sopenharmony_ci * security_sid_to_context - Obtain a context for a given SID.
137162306a36Sopenharmony_ci * @sid: security identifier, SID
137262306a36Sopenharmony_ci * @scontext: security context
137362306a36Sopenharmony_ci * @scontext_len: length in bytes
137462306a36Sopenharmony_ci *
137562306a36Sopenharmony_ci * Write the string representation of the context associated with @sid
137662306a36Sopenharmony_ci * into a dynamically allocated string of the correct size.  Set @scontext
137762306a36Sopenharmony_ci * to point to this string and set @scontext_len to the length of the string.
137862306a36Sopenharmony_ci */
137962306a36Sopenharmony_ciint security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
138062306a36Sopenharmony_ci{
138162306a36Sopenharmony_ci	return security_sid_to_context_core(sid, scontext,
138262306a36Sopenharmony_ci					    scontext_len, 0, 0);
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ciint security_sid_to_context_force(u32 sid,
138662306a36Sopenharmony_ci				  char **scontext, u32 *scontext_len)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	return security_sid_to_context_core(sid, scontext,
138962306a36Sopenharmony_ci					    scontext_len, 1, 0);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci/**
139362306a36Sopenharmony_ci * security_sid_to_context_inval - Obtain a context for a given SID if it
139462306a36Sopenharmony_ci *                                 is invalid.
139562306a36Sopenharmony_ci * @sid: security identifier, SID
139662306a36Sopenharmony_ci * @scontext: security context
139762306a36Sopenharmony_ci * @scontext_len: length in bytes
139862306a36Sopenharmony_ci *
139962306a36Sopenharmony_ci * Write the string representation of the context associated with @sid
140062306a36Sopenharmony_ci * into a dynamically allocated string of the correct size, but only if the
140162306a36Sopenharmony_ci * context is invalid in the current policy.  Set @scontext to point to
140262306a36Sopenharmony_ci * this string (or NULL if the context is valid) and set @scontext_len to
140362306a36Sopenharmony_ci * the length of the string (or 0 if the context is valid).
140462306a36Sopenharmony_ci */
140562306a36Sopenharmony_ciint security_sid_to_context_inval(u32 sid,
140662306a36Sopenharmony_ci				  char **scontext, u32 *scontext_len)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	return security_sid_to_context_core(sid, scontext,
140962306a36Sopenharmony_ci					    scontext_len, 1, 1);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci/*
141362306a36Sopenharmony_ci * Caveat:  Mutates scontext.
141462306a36Sopenharmony_ci */
141562306a36Sopenharmony_cistatic int string_to_context_struct(struct policydb *pol,
141662306a36Sopenharmony_ci				    struct sidtab *sidtabp,
141762306a36Sopenharmony_ci				    char *scontext,
141862306a36Sopenharmony_ci				    struct context *ctx,
141962306a36Sopenharmony_ci				    u32 def_sid)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	struct role_datum *role;
142262306a36Sopenharmony_ci	struct type_datum *typdatum;
142362306a36Sopenharmony_ci	struct user_datum *usrdatum;
142462306a36Sopenharmony_ci	char *scontextp, *p, oldc;
142562306a36Sopenharmony_ci	int rc = 0;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	context_init(ctx);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/* Parse the security context. */
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	rc = -EINVAL;
143262306a36Sopenharmony_ci	scontextp = scontext;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	/* Extract the user. */
143562306a36Sopenharmony_ci	p = scontextp;
143662306a36Sopenharmony_ci	while (*p && *p != ':')
143762306a36Sopenharmony_ci		p++;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (*p == 0)
144062306a36Sopenharmony_ci		goto out;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	*p++ = 0;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	usrdatum = symtab_search(&pol->p_users, scontextp);
144562306a36Sopenharmony_ci	if (!usrdatum)
144662306a36Sopenharmony_ci		goto out;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	ctx->user = usrdatum->value;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* Extract role. */
145162306a36Sopenharmony_ci	scontextp = p;
145262306a36Sopenharmony_ci	while (*p && *p != ':')
145362306a36Sopenharmony_ci		p++;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (*p == 0)
145662306a36Sopenharmony_ci		goto out;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	*p++ = 0;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	role = symtab_search(&pol->p_roles, scontextp);
146162306a36Sopenharmony_ci	if (!role)
146262306a36Sopenharmony_ci		goto out;
146362306a36Sopenharmony_ci	ctx->role = role->value;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* Extract type. */
146662306a36Sopenharmony_ci	scontextp = p;
146762306a36Sopenharmony_ci	while (*p && *p != ':')
146862306a36Sopenharmony_ci		p++;
146962306a36Sopenharmony_ci	oldc = *p;
147062306a36Sopenharmony_ci	*p++ = 0;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	typdatum = symtab_search(&pol->p_types, scontextp);
147362306a36Sopenharmony_ci	if (!typdatum || typdatum->attribute)
147462306a36Sopenharmony_ci		goto out;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	ctx->type = typdatum->value;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
147962306a36Sopenharmony_ci	if (rc)
148062306a36Sopenharmony_ci		goto out;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	/* Check the validity of the new context. */
148362306a36Sopenharmony_ci	rc = -EINVAL;
148462306a36Sopenharmony_ci	if (!policydb_context_isvalid(pol, ctx))
148562306a36Sopenharmony_ci		goto out;
148662306a36Sopenharmony_ci	rc = 0;
148762306a36Sopenharmony_ciout:
148862306a36Sopenharmony_ci	if (rc)
148962306a36Sopenharmony_ci		context_destroy(ctx);
149062306a36Sopenharmony_ci	return rc;
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic int security_context_to_sid_core(const char *scontext, u32 scontext_len,
149462306a36Sopenharmony_ci					u32 *sid, u32 def_sid, gfp_t gfp_flags,
149562306a36Sopenharmony_ci					int force)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	struct selinux_policy *policy;
149862306a36Sopenharmony_ci	struct policydb *policydb;
149962306a36Sopenharmony_ci	struct sidtab *sidtab;
150062306a36Sopenharmony_ci	char *scontext2, *str = NULL;
150162306a36Sopenharmony_ci	struct context context;
150262306a36Sopenharmony_ci	int rc = 0;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	/* An empty security context is never valid. */
150562306a36Sopenharmony_ci	if (!scontext_len)
150662306a36Sopenharmony_ci		return -EINVAL;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* Copy the string to allow changes and ensure a NUL terminator */
150962306a36Sopenharmony_ci	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
151062306a36Sopenharmony_ci	if (!scontext2)
151162306a36Sopenharmony_ci		return -ENOMEM;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!selinux_initialized()) {
151462306a36Sopenharmony_ci		u32 i;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		for (i = 1; i < SECINITSID_NUM; i++) {
151762306a36Sopenharmony_ci			const char *s = initial_sid_to_string[i];
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci			if (s && !strcmp(s, scontext2)) {
152062306a36Sopenharmony_ci				*sid = i;
152162306a36Sopenharmony_ci				goto out;
152262306a36Sopenharmony_ci			}
152362306a36Sopenharmony_ci		}
152462306a36Sopenharmony_ci		*sid = SECINITSID_KERNEL;
152562306a36Sopenharmony_ci		goto out;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci	*sid = SECSID_NULL;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (force) {
153062306a36Sopenharmony_ci		/* Save another copy for storing in uninterpreted form */
153162306a36Sopenharmony_ci		rc = -ENOMEM;
153262306a36Sopenharmony_ci		str = kstrdup(scontext2, gfp_flags);
153362306a36Sopenharmony_ci		if (!str)
153462306a36Sopenharmony_ci			goto out;
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ciretry:
153762306a36Sopenharmony_ci	rcu_read_lock();
153862306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
153962306a36Sopenharmony_ci	policydb = &policy->policydb;
154062306a36Sopenharmony_ci	sidtab = policy->sidtab;
154162306a36Sopenharmony_ci	rc = string_to_context_struct(policydb, sidtab, scontext2,
154262306a36Sopenharmony_ci				      &context, def_sid);
154362306a36Sopenharmony_ci	if (rc == -EINVAL && force) {
154462306a36Sopenharmony_ci		context.str = str;
154562306a36Sopenharmony_ci		context.len = strlen(str) + 1;
154662306a36Sopenharmony_ci		str = NULL;
154762306a36Sopenharmony_ci	} else if (rc)
154862306a36Sopenharmony_ci		goto out_unlock;
154962306a36Sopenharmony_ci	rc = sidtab_context_to_sid(sidtab, &context, sid);
155062306a36Sopenharmony_ci	if (rc == -ESTALE) {
155162306a36Sopenharmony_ci		rcu_read_unlock();
155262306a36Sopenharmony_ci		if (context.str) {
155362306a36Sopenharmony_ci			str = context.str;
155462306a36Sopenharmony_ci			context.str = NULL;
155562306a36Sopenharmony_ci		}
155662306a36Sopenharmony_ci		context_destroy(&context);
155762306a36Sopenharmony_ci		goto retry;
155862306a36Sopenharmony_ci	}
155962306a36Sopenharmony_ci	context_destroy(&context);
156062306a36Sopenharmony_ciout_unlock:
156162306a36Sopenharmony_ci	rcu_read_unlock();
156262306a36Sopenharmony_ciout:
156362306a36Sopenharmony_ci	kfree(scontext2);
156462306a36Sopenharmony_ci	kfree(str);
156562306a36Sopenharmony_ci	return rc;
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci/**
156962306a36Sopenharmony_ci * security_context_to_sid - Obtain a SID for a given security context.
157062306a36Sopenharmony_ci * @scontext: security context
157162306a36Sopenharmony_ci * @scontext_len: length in bytes
157262306a36Sopenharmony_ci * @sid: security identifier, SID
157362306a36Sopenharmony_ci * @gfp: context for the allocation
157462306a36Sopenharmony_ci *
157562306a36Sopenharmony_ci * Obtains a SID associated with the security context that
157662306a36Sopenharmony_ci * has the string representation specified by @scontext.
157762306a36Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
157862306a36Sopenharmony_ci * memory is available, or 0 on success.
157962306a36Sopenharmony_ci */
158062306a36Sopenharmony_ciint security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
158162306a36Sopenharmony_ci			    gfp_t gfp)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	return security_context_to_sid_core(scontext, scontext_len,
158462306a36Sopenharmony_ci					    sid, SECSID_NULL, gfp, 0);
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ciint security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	return security_context_to_sid(scontext, strlen(scontext),
159062306a36Sopenharmony_ci				       sid, gfp);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci/**
159462306a36Sopenharmony_ci * security_context_to_sid_default - Obtain a SID for a given security context,
159562306a36Sopenharmony_ci * falling back to specified default if needed.
159662306a36Sopenharmony_ci *
159762306a36Sopenharmony_ci * @scontext: security context
159862306a36Sopenharmony_ci * @scontext_len: length in bytes
159962306a36Sopenharmony_ci * @sid: security identifier, SID
160062306a36Sopenharmony_ci * @def_sid: default SID to assign on error
160162306a36Sopenharmony_ci * @gfp_flags: the allocator get-free-page (GFP) flags
160262306a36Sopenharmony_ci *
160362306a36Sopenharmony_ci * Obtains a SID associated with the security context that
160462306a36Sopenharmony_ci * has the string representation specified by @scontext.
160562306a36Sopenharmony_ci * The default SID is passed to the MLS layer to be used to allow
160662306a36Sopenharmony_ci * kernel labeling of the MLS field if the MLS field is not present
160762306a36Sopenharmony_ci * (for upgrading to MLS without full relabel).
160862306a36Sopenharmony_ci * Implicitly forces adding of the context even if it cannot be mapped yet.
160962306a36Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
161062306a36Sopenharmony_ci * memory is available, or 0 on success.
161162306a36Sopenharmony_ci */
161262306a36Sopenharmony_ciint security_context_to_sid_default(const char *scontext, u32 scontext_len,
161362306a36Sopenharmony_ci				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
161462306a36Sopenharmony_ci{
161562306a36Sopenharmony_ci	return security_context_to_sid_core(scontext, scontext_len,
161662306a36Sopenharmony_ci					    sid, def_sid, gfp_flags, 1);
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ciint security_context_to_sid_force(const char *scontext, u32 scontext_len,
162062306a36Sopenharmony_ci				  u32 *sid)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	return security_context_to_sid_core(scontext, scontext_len,
162362306a36Sopenharmony_ci					    sid, SECSID_NULL, GFP_KERNEL, 1);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cistatic int compute_sid_handle_invalid_context(
162762306a36Sopenharmony_ci	struct selinux_policy *policy,
162862306a36Sopenharmony_ci	struct sidtab_entry *sentry,
162962306a36Sopenharmony_ci	struct sidtab_entry *tentry,
163062306a36Sopenharmony_ci	u16 tclass,
163162306a36Sopenharmony_ci	struct context *newcontext)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	struct policydb *policydb = &policy->policydb;
163462306a36Sopenharmony_ci	struct sidtab *sidtab = policy->sidtab;
163562306a36Sopenharmony_ci	char *s = NULL, *t = NULL, *n = NULL;
163662306a36Sopenharmony_ci	u32 slen, tlen, nlen;
163762306a36Sopenharmony_ci	struct audit_buffer *ab;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
164062306a36Sopenharmony_ci		goto out;
164162306a36Sopenharmony_ci	if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
164262306a36Sopenharmony_ci		goto out;
164362306a36Sopenharmony_ci	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
164462306a36Sopenharmony_ci		goto out;
164562306a36Sopenharmony_ci	ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
164662306a36Sopenharmony_ci	if (!ab)
164762306a36Sopenharmony_ci		goto out;
164862306a36Sopenharmony_ci	audit_log_format(ab,
164962306a36Sopenharmony_ci			 "op=security_compute_sid invalid_context=");
165062306a36Sopenharmony_ci	/* no need to record the NUL with untrusted strings */
165162306a36Sopenharmony_ci	audit_log_n_untrustedstring(ab, n, nlen - 1);
165262306a36Sopenharmony_ci	audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
165362306a36Sopenharmony_ci			 s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
165462306a36Sopenharmony_ci	audit_log_end(ab);
165562306a36Sopenharmony_ciout:
165662306a36Sopenharmony_ci	kfree(s);
165762306a36Sopenharmony_ci	kfree(t);
165862306a36Sopenharmony_ci	kfree(n);
165962306a36Sopenharmony_ci	if (!enforcing_enabled())
166062306a36Sopenharmony_ci		return 0;
166162306a36Sopenharmony_ci	return -EACCES;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic void filename_compute_type(struct policydb *policydb,
166562306a36Sopenharmony_ci				  struct context *newcontext,
166662306a36Sopenharmony_ci				  u32 stype, u32 ttype, u16 tclass,
166762306a36Sopenharmony_ci				  const char *objname)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct filename_trans_key ft;
167062306a36Sopenharmony_ci	struct filename_trans_datum *datum;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	/*
167362306a36Sopenharmony_ci	 * Most filename trans rules are going to live in specific directories
167462306a36Sopenharmony_ci	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
167562306a36Sopenharmony_ci	 * if the ttype does not contain any rules.
167662306a36Sopenharmony_ci	 */
167762306a36Sopenharmony_ci	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
167862306a36Sopenharmony_ci		return;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	ft.ttype = ttype;
168162306a36Sopenharmony_ci	ft.tclass = tclass;
168262306a36Sopenharmony_ci	ft.name = objname;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	datum = policydb_filenametr_search(policydb, &ft);
168562306a36Sopenharmony_ci	while (datum) {
168662306a36Sopenharmony_ci		if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
168762306a36Sopenharmony_ci			newcontext->type = datum->otype;
168862306a36Sopenharmony_ci			return;
168962306a36Sopenharmony_ci		}
169062306a36Sopenharmony_ci		datum = datum->next;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic int security_compute_sid(u32 ssid,
169562306a36Sopenharmony_ci				u32 tsid,
169662306a36Sopenharmony_ci				u16 orig_tclass,
169762306a36Sopenharmony_ci				u16 specified,
169862306a36Sopenharmony_ci				const char *objname,
169962306a36Sopenharmony_ci				u32 *out_sid,
170062306a36Sopenharmony_ci				bool kern)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	struct selinux_policy *policy;
170362306a36Sopenharmony_ci	struct policydb *policydb;
170462306a36Sopenharmony_ci	struct sidtab *sidtab;
170562306a36Sopenharmony_ci	struct class_datum *cladatum;
170662306a36Sopenharmony_ci	struct context *scontext, *tcontext, newcontext;
170762306a36Sopenharmony_ci	struct sidtab_entry *sentry, *tentry;
170862306a36Sopenharmony_ci	struct avtab_key avkey;
170962306a36Sopenharmony_ci	struct avtab_node *avnode, *node;
171062306a36Sopenharmony_ci	u16 tclass;
171162306a36Sopenharmony_ci	int rc = 0;
171262306a36Sopenharmony_ci	bool sock;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	if (!selinux_initialized()) {
171562306a36Sopenharmony_ci		switch (orig_tclass) {
171662306a36Sopenharmony_ci		case SECCLASS_PROCESS: /* kernel value */
171762306a36Sopenharmony_ci			*out_sid = ssid;
171862306a36Sopenharmony_ci			break;
171962306a36Sopenharmony_ci		default:
172062306a36Sopenharmony_ci			*out_sid = tsid;
172162306a36Sopenharmony_ci			break;
172262306a36Sopenharmony_ci		}
172362306a36Sopenharmony_ci		goto out;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ciretry:
172762306a36Sopenharmony_ci	cladatum = NULL;
172862306a36Sopenharmony_ci	context_init(&newcontext);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	rcu_read_lock();
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	if (kern) {
173562306a36Sopenharmony_ci		tclass = unmap_class(&policy->map, orig_tclass);
173662306a36Sopenharmony_ci		sock = security_is_socket_class(orig_tclass);
173762306a36Sopenharmony_ci	} else {
173862306a36Sopenharmony_ci		tclass = orig_tclass;
173962306a36Sopenharmony_ci		sock = security_is_socket_class(map_class(&policy->map,
174062306a36Sopenharmony_ci							  tclass));
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	policydb = &policy->policydb;
174462306a36Sopenharmony_ci	sidtab = policy->sidtab;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	sentry = sidtab_search_entry(sidtab, ssid);
174762306a36Sopenharmony_ci	if (!sentry) {
174862306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
174962306a36Sopenharmony_ci		       __func__, ssid);
175062306a36Sopenharmony_ci		rc = -EINVAL;
175162306a36Sopenharmony_ci		goto out_unlock;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci	tentry = sidtab_search_entry(sidtab, tsid);
175462306a36Sopenharmony_ci	if (!tentry) {
175562306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
175662306a36Sopenharmony_ci		       __func__, tsid);
175762306a36Sopenharmony_ci		rc = -EINVAL;
175862306a36Sopenharmony_ci		goto out_unlock;
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	scontext = &sentry->context;
176262306a36Sopenharmony_ci	tcontext = &tentry->context;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (tclass && tclass <= policydb->p_classes.nprim)
176562306a36Sopenharmony_ci		cladatum = policydb->class_val_to_struct[tclass - 1];
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	/* Set the user identity. */
176862306a36Sopenharmony_ci	switch (specified) {
176962306a36Sopenharmony_ci	case AVTAB_TRANSITION:
177062306a36Sopenharmony_ci	case AVTAB_CHANGE:
177162306a36Sopenharmony_ci		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
177262306a36Sopenharmony_ci			newcontext.user = tcontext->user;
177362306a36Sopenharmony_ci		} else {
177462306a36Sopenharmony_ci			/* notice this gets both DEFAULT_SOURCE and unset */
177562306a36Sopenharmony_ci			/* Use the process user identity. */
177662306a36Sopenharmony_ci			newcontext.user = scontext->user;
177762306a36Sopenharmony_ci		}
177862306a36Sopenharmony_ci		break;
177962306a36Sopenharmony_ci	case AVTAB_MEMBER:
178062306a36Sopenharmony_ci		/* Use the related object owner. */
178162306a36Sopenharmony_ci		newcontext.user = tcontext->user;
178262306a36Sopenharmony_ci		break;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	/* Set the role to default values. */
178662306a36Sopenharmony_ci	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
178762306a36Sopenharmony_ci		newcontext.role = scontext->role;
178862306a36Sopenharmony_ci	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
178962306a36Sopenharmony_ci		newcontext.role = tcontext->role;
179062306a36Sopenharmony_ci	} else {
179162306a36Sopenharmony_ci		if ((tclass == policydb->process_class) || sock)
179262306a36Sopenharmony_ci			newcontext.role = scontext->role;
179362306a36Sopenharmony_ci		else
179462306a36Sopenharmony_ci			newcontext.role = OBJECT_R_VAL;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* Set the type to default values. */
179862306a36Sopenharmony_ci	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
179962306a36Sopenharmony_ci		newcontext.type = scontext->type;
180062306a36Sopenharmony_ci	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
180162306a36Sopenharmony_ci		newcontext.type = tcontext->type;
180262306a36Sopenharmony_ci	} else {
180362306a36Sopenharmony_ci		if ((tclass == policydb->process_class) || sock) {
180462306a36Sopenharmony_ci			/* Use the type of process. */
180562306a36Sopenharmony_ci			newcontext.type = scontext->type;
180662306a36Sopenharmony_ci		} else {
180762306a36Sopenharmony_ci			/* Use the type of the related object. */
180862306a36Sopenharmony_ci			newcontext.type = tcontext->type;
180962306a36Sopenharmony_ci		}
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/* Look for a type transition/member/change rule. */
181362306a36Sopenharmony_ci	avkey.source_type = scontext->type;
181462306a36Sopenharmony_ci	avkey.target_type = tcontext->type;
181562306a36Sopenharmony_ci	avkey.target_class = tclass;
181662306a36Sopenharmony_ci	avkey.specified = specified;
181762306a36Sopenharmony_ci	avnode = avtab_search_node(&policydb->te_avtab, &avkey);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	/* If no permanent rule, also check for enabled conditional rules */
182062306a36Sopenharmony_ci	if (!avnode) {
182162306a36Sopenharmony_ci		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
182262306a36Sopenharmony_ci		for (; node; node = avtab_search_node_next(node, specified)) {
182362306a36Sopenharmony_ci			if (node->key.specified & AVTAB_ENABLED) {
182462306a36Sopenharmony_ci				avnode = node;
182562306a36Sopenharmony_ci				break;
182662306a36Sopenharmony_ci			}
182762306a36Sopenharmony_ci		}
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	if (avnode) {
183162306a36Sopenharmony_ci		/* Use the type from the type transition/member/change rule. */
183262306a36Sopenharmony_ci		newcontext.type = avnode->datum.u.data;
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	/* if we have a objname this is a file trans check so check those rules */
183662306a36Sopenharmony_ci	if (objname)
183762306a36Sopenharmony_ci		filename_compute_type(policydb, &newcontext, scontext->type,
183862306a36Sopenharmony_ci				      tcontext->type, tclass, objname);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	/* Check for class-specific changes. */
184162306a36Sopenharmony_ci	if (specified & AVTAB_TRANSITION) {
184262306a36Sopenharmony_ci		/* Look for a role transition rule. */
184362306a36Sopenharmony_ci		struct role_trans_datum *rtd;
184462306a36Sopenharmony_ci		struct role_trans_key rtk = {
184562306a36Sopenharmony_ci			.role = scontext->role,
184662306a36Sopenharmony_ci			.type = tcontext->type,
184762306a36Sopenharmony_ci			.tclass = tclass,
184862306a36Sopenharmony_ci		};
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci		rtd = policydb_roletr_search(policydb, &rtk);
185162306a36Sopenharmony_ci		if (rtd)
185262306a36Sopenharmony_ci			newcontext.role = rtd->new_role;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	/* Set the MLS attributes.
185662306a36Sopenharmony_ci	   This is done last because it may allocate memory. */
185762306a36Sopenharmony_ci	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
185862306a36Sopenharmony_ci			     &newcontext, sock);
185962306a36Sopenharmony_ci	if (rc)
186062306a36Sopenharmony_ci		goto out_unlock;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	/* Check the validity of the context. */
186362306a36Sopenharmony_ci	if (!policydb_context_isvalid(policydb, &newcontext)) {
186462306a36Sopenharmony_ci		rc = compute_sid_handle_invalid_context(policy, sentry,
186562306a36Sopenharmony_ci							tentry, tclass,
186662306a36Sopenharmony_ci							&newcontext);
186762306a36Sopenharmony_ci		if (rc)
186862306a36Sopenharmony_ci			goto out_unlock;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci	/* Obtain the sid for the context. */
187162306a36Sopenharmony_ci	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
187262306a36Sopenharmony_ci	if (rc == -ESTALE) {
187362306a36Sopenharmony_ci		rcu_read_unlock();
187462306a36Sopenharmony_ci		context_destroy(&newcontext);
187562306a36Sopenharmony_ci		goto retry;
187662306a36Sopenharmony_ci	}
187762306a36Sopenharmony_ciout_unlock:
187862306a36Sopenharmony_ci	rcu_read_unlock();
187962306a36Sopenharmony_ci	context_destroy(&newcontext);
188062306a36Sopenharmony_ciout:
188162306a36Sopenharmony_ci	return rc;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci/**
188562306a36Sopenharmony_ci * security_transition_sid - Compute the SID for a new subject/object.
188662306a36Sopenharmony_ci * @ssid: source security identifier
188762306a36Sopenharmony_ci * @tsid: target security identifier
188862306a36Sopenharmony_ci * @tclass: target security class
188962306a36Sopenharmony_ci * @qstr: object name
189062306a36Sopenharmony_ci * @out_sid: security identifier for new subject/object
189162306a36Sopenharmony_ci *
189262306a36Sopenharmony_ci * Compute a SID to use for labeling a new subject or object in the
189362306a36Sopenharmony_ci * class @tclass based on a SID pair (@ssid, @tsid).
189462306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
189562306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the new SID was
189662306a36Sopenharmony_ci * computed successfully.
189762306a36Sopenharmony_ci */
189862306a36Sopenharmony_ciint security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
189962306a36Sopenharmony_ci			    const struct qstr *qstr, u32 *out_sid)
190062306a36Sopenharmony_ci{
190162306a36Sopenharmony_ci	return security_compute_sid(ssid, tsid, tclass,
190262306a36Sopenharmony_ci				    AVTAB_TRANSITION,
190362306a36Sopenharmony_ci				    qstr ? qstr->name : NULL, out_sid, true);
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ciint security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
190762306a36Sopenharmony_ci				 const char *objname, u32 *out_sid)
190862306a36Sopenharmony_ci{
190962306a36Sopenharmony_ci	return security_compute_sid(ssid, tsid, tclass,
191062306a36Sopenharmony_ci				    AVTAB_TRANSITION,
191162306a36Sopenharmony_ci				    objname, out_sid, false);
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci/**
191562306a36Sopenharmony_ci * security_member_sid - Compute the SID for member selection.
191662306a36Sopenharmony_ci * @ssid: source security identifier
191762306a36Sopenharmony_ci * @tsid: target security identifier
191862306a36Sopenharmony_ci * @tclass: target security class
191962306a36Sopenharmony_ci * @out_sid: security identifier for selected member
192062306a36Sopenharmony_ci *
192162306a36Sopenharmony_ci * Compute a SID to use when selecting a member of a polyinstantiated
192262306a36Sopenharmony_ci * object of class @tclass based on a SID pair (@ssid, @tsid).
192362306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
192462306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was
192562306a36Sopenharmony_ci * computed successfully.
192662306a36Sopenharmony_ci */
192762306a36Sopenharmony_ciint security_member_sid(u32 ssid,
192862306a36Sopenharmony_ci			u32 tsid,
192962306a36Sopenharmony_ci			u16 tclass,
193062306a36Sopenharmony_ci			u32 *out_sid)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	return security_compute_sid(ssid, tsid, tclass,
193362306a36Sopenharmony_ci				    AVTAB_MEMBER, NULL,
193462306a36Sopenharmony_ci				    out_sid, false);
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci/**
193862306a36Sopenharmony_ci * security_change_sid - Compute the SID for object relabeling.
193962306a36Sopenharmony_ci * @ssid: source security identifier
194062306a36Sopenharmony_ci * @tsid: target security identifier
194162306a36Sopenharmony_ci * @tclass: target security class
194262306a36Sopenharmony_ci * @out_sid: security identifier for selected member
194362306a36Sopenharmony_ci *
194462306a36Sopenharmony_ci * Compute a SID to use for relabeling an object of class @tclass
194562306a36Sopenharmony_ci * based on a SID pair (@ssid, @tsid).
194662306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
194762306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was
194862306a36Sopenharmony_ci * computed successfully.
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_ciint security_change_sid(u32 ssid,
195162306a36Sopenharmony_ci			u32 tsid,
195262306a36Sopenharmony_ci			u16 tclass,
195362306a36Sopenharmony_ci			u32 *out_sid)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
195662306a36Sopenharmony_ci				    out_sid, false);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic inline int convert_context_handle_invalid_context(
196062306a36Sopenharmony_ci	struct policydb *policydb,
196162306a36Sopenharmony_ci	struct context *context)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	char *s;
196462306a36Sopenharmony_ci	u32 len;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	if (enforcing_enabled())
196762306a36Sopenharmony_ci		return -EINVAL;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	if (!context_struct_to_string(policydb, context, &s, &len)) {
197062306a36Sopenharmony_ci		pr_warn("SELinux:  Context %s would be invalid if enforcing\n",
197162306a36Sopenharmony_ci			s);
197262306a36Sopenharmony_ci		kfree(s);
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci	return 0;
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci/**
197862306a36Sopenharmony_ci * services_convert_context - Convert a security context across policies.
197962306a36Sopenharmony_ci * @args: populated convert_context_args struct
198062306a36Sopenharmony_ci * @oldc: original context
198162306a36Sopenharmony_ci * @newc: converted context
198262306a36Sopenharmony_ci * @gfp_flags: allocation flags
198362306a36Sopenharmony_ci *
198462306a36Sopenharmony_ci * Convert the values in the security context structure @oldc from the values
198562306a36Sopenharmony_ci * specified in the policy @args->oldp to the values specified in the policy
198662306a36Sopenharmony_ci * @args->newp, storing the new context in @newc, and verifying that the
198762306a36Sopenharmony_ci * context is valid under the new policy.
198862306a36Sopenharmony_ci */
198962306a36Sopenharmony_ciint services_convert_context(struct convert_context_args *args,
199062306a36Sopenharmony_ci			     struct context *oldc, struct context *newc,
199162306a36Sopenharmony_ci			     gfp_t gfp_flags)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	struct ocontext *oc;
199462306a36Sopenharmony_ci	struct role_datum *role;
199562306a36Sopenharmony_ci	struct type_datum *typdatum;
199662306a36Sopenharmony_ci	struct user_datum *usrdatum;
199762306a36Sopenharmony_ci	char *s;
199862306a36Sopenharmony_ci	u32 len;
199962306a36Sopenharmony_ci	int rc;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	if (oldc->str) {
200262306a36Sopenharmony_ci		s = kstrdup(oldc->str, gfp_flags);
200362306a36Sopenharmony_ci		if (!s)
200462306a36Sopenharmony_ci			return -ENOMEM;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci		rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
200762306a36Sopenharmony_ci		if (rc == -EINVAL) {
200862306a36Sopenharmony_ci			/*
200962306a36Sopenharmony_ci			 * Retain string representation for later mapping.
201062306a36Sopenharmony_ci			 *
201162306a36Sopenharmony_ci			 * IMPORTANT: We need to copy the contents of oldc->str
201262306a36Sopenharmony_ci			 * back into s again because string_to_context_struct()
201362306a36Sopenharmony_ci			 * may have garbled it.
201462306a36Sopenharmony_ci			 */
201562306a36Sopenharmony_ci			memcpy(s, oldc->str, oldc->len);
201662306a36Sopenharmony_ci			context_init(newc);
201762306a36Sopenharmony_ci			newc->str = s;
201862306a36Sopenharmony_ci			newc->len = oldc->len;
201962306a36Sopenharmony_ci			return 0;
202062306a36Sopenharmony_ci		}
202162306a36Sopenharmony_ci		kfree(s);
202262306a36Sopenharmony_ci		if (rc) {
202362306a36Sopenharmony_ci			/* Other error condition, e.g. ENOMEM. */
202462306a36Sopenharmony_ci			pr_err("SELinux:   Unable to map context %s, rc = %d.\n",
202562306a36Sopenharmony_ci			       oldc->str, -rc);
202662306a36Sopenharmony_ci			return rc;
202762306a36Sopenharmony_ci		}
202862306a36Sopenharmony_ci		pr_info("SELinux:  Context %s became valid (mapped).\n",
202962306a36Sopenharmony_ci			oldc->str);
203062306a36Sopenharmony_ci		return 0;
203162306a36Sopenharmony_ci	}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	context_init(newc);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	/* Convert the user. */
203662306a36Sopenharmony_ci	usrdatum = symtab_search(&args->newp->p_users,
203762306a36Sopenharmony_ci				 sym_name(args->oldp, SYM_USERS, oldc->user - 1));
203862306a36Sopenharmony_ci	if (!usrdatum)
203962306a36Sopenharmony_ci		goto bad;
204062306a36Sopenharmony_ci	newc->user = usrdatum->value;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	/* Convert the role. */
204362306a36Sopenharmony_ci	role = symtab_search(&args->newp->p_roles,
204462306a36Sopenharmony_ci			     sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
204562306a36Sopenharmony_ci	if (!role)
204662306a36Sopenharmony_ci		goto bad;
204762306a36Sopenharmony_ci	newc->role = role->value;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	/* Convert the type. */
205062306a36Sopenharmony_ci	typdatum = symtab_search(&args->newp->p_types,
205162306a36Sopenharmony_ci				 sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
205262306a36Sopenharmony_ci	if (!typdatum)
205362306a36Sopenharmony_ci		goto bad;
205462306a36Sopenharmony_ci	newc->type = typdatum->value;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* Convert the MLS fields if dealing with MLS policies */
205762306a36Sopenharmony_ci	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
205862306a36Sopenharmony_ci		rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
205962306a36Sopenharmony_ci		if (rc)
206062306a36Sopenharmony_ci			goto bad;
206162306a36Sopenharmony_ci	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
206262306a36Sopenharmony_ci		/*
206362306a36Sopenharmony_ci		 * Switching between non-MLS and MLS policy:
206462306a36Sopenharmony_ci		 * ensure that the MLS fields of the context for all
206562306a36Sopenharmony_ci		 * existing entries in the sidtab are filled in with a
206662306a36Sopenharmony_ci		 * suitable default value, likely taken from one of the
206762306a36Sopenharmony_ci		 * initial SIDs.
206862306a36Sopenharmony_ci		 */
206962306a36Sopenharmony_ci		oc = args->newp->ocontexts[OCON_ISID];
207062306a36Sopenharmony_ci		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
207162306a36Sopenharmony_ci			oc = oc->next;
207262306a36Sopenharmony_ci		if (!oc) {
207362306a36Sopenharmony_ci			pr_err("SELinux:  unable to look up"
207462306a36Sopenharmony_ci				" the initial SIDs list\n");
207562306a36Sopenharmony_ci			goto bad;
207662306a36Sopenharmony_ci		}
207762306a36Sopenharmony_ci		rc = mls_range_set(newc, &oc->context[0].range);
207862306a36Sopenharmony_ci		if (rc)
207962306a36Sopenharmony_ci			goto bad;
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	/* Check the validity of the new context. */
208362306a36Sopenharmony_ci	if (!policydb_context_isvalid(args->newp, newc)) {
208462306a36Sopenharmony_ci		rc = convert_context_handle_invalid_context(args->oldp, oldc);
208562306a36Sopenharmony_ci		if (rc)
208662306a36Sopenharmony_ci			goto bad;
208762306a36Sopenharmony_ci	}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	return 0;
209062306a36Sopenharmony_cibad:
209162306a36Sopenharmony_ci	/* Map old representation to string and save it. */
209262306a36Sopenharmony_ci	rc = context_struct_to_string(args->oldp, oldc, &s, &len);
209362306a36Sopenharmony_ci	if (rc)
209462306a36Sopenharmony_ci		return rc;
209562306a36Sopenharmony_ci	context_destroy(newc);
209662306a36Sopenharmony_ci	newc->str = s;
209762306a36Sopenharmony_ci	newc->len = len;
209862306a36Sopenharmony_ci	pr_info("SELinux:  Context %s became invalid (unmapped).\n",
209962306a36Sopenharmony_ci		newc->str);
210062306a36Sopenharmony_ci	return 0;
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic void security_load_policycaps(struct selinux_policy *policy)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	struct policydb *p;
210662306a36Sopenharmony_ci	unsigned int i;
210762306a36Sopenharmony_ci	struct ebitmap_node *node;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	p = &policy->policydb;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
211262306a36Sopenharmony_ci		WRITE_ONCE(selinux_state.policycap[i],
211362306a36Sopenharmony_ci			ebitmap_get_bit(&p->policycaps, i));
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
211662306a36Sopenharmony_ci		pr_info("SELinux:  policy capability %s=%d\n",
211762306a36Sopenharmony_ci			selinux_policycap_names[i],
211862306a36Sopenharmony_ci			ebitmap_get_bit(&p->policycaps, i));
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
212162306a36Sopenharmony_ci		if (i >= ARRAY_SIZE(selinux_policycap_names))
212262306a36Sopenharmony_ci			pr_info("SELinux:  unknown policy capability %u\n",
212362306a36Sopenharmony_ci				i);
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy,
212862306a36Sopenharmony_ci				struct selinux_policy *newpolicy);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_cistatic void selinux_policy_free(struct selinux_policy *policy)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	if (!policy)
213362306a36Sopenharmony_ci		return;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	sidtab_destroy(policy->sidtab);
213662306a36Sopenharmony_ci	kfree(policy->map.mapping);
213762306a36Sopenharmony_ci	policydb_destroy(&policy->policydb);
213862306a36Sopenharmony_ci	kfree(policy->sidtab);
213962306a36Sopenharmony_ci	kfree(policy);
214062306a36Sopenharmony_ci}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_cistatic void selinux_policy_cond_free(struct selinux_policy *policy)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	cond_policydb_destroy_dup(&policy->policydb);
214562306a36Sopenharmony_ci	kfree(policy);
214662306a36Sopenharmony_ci}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_civoid selinux_policy_cancel(struct selinux_load_state *load_state)
214962306a36Sopenharmony_ci{
215062306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
215162306a36Sopenharmony_ci	struct selinux_policy *oldpolicy;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	oldpolicy = rcu_dereference_protected(state->policy,
215462306a36Sopenharmony_ci					lockdep_is_held(&state->policy_mutex));
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	sidtab_cancel_convert(oldpolicy->sidtab);
215762306a36Sopenharmony_ci	selinux_policy_free(load_state->policy);
215862306a36Sopenharmony_ci	kfree(load_state->convert_data);
215962306a36Sopenharmony_ci}
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_cistatic void selinux_notify_policy_change(u32 seqno)
216262306a36Sopenharmony_ci{
216362306a36Sopenharmony_ci	/* Flush external caches and notify userspace of policy load */
216462306a36Sopenharmony_ci	avc_ss_reset(seqno);
216562306a36Sopenharmony_ci	selnl_notify_policyload(seqno);
216662306a36Sopenharmony_ci	selinux_status_update_policyload(seqno);
216762306a36Sopenharmony_ci	selinux_netlbl_cache_invalidate();
216862306a36Sopenharmony_ci	selinux_xfrm_notify_policyload();
216962306a36Sopenharmony_ci	selinux_ima_measure_state_locked();
217062306a36Sopenharmony_ci}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_civoid selinux_policy_commit(struct selinux_load_state *load_state)
217362306a36Sopenharmony_ci{
217462306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
217562306a36Sopenharmony_ci	struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
217662306a36Sopenharmony_ci	unsigned long flags;
217762306a36Sopenharmony_ci	u32 seqno;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	oldpolicy = rcu_dereference_protected(state->policy,
218062306a36Sopenharmony_ci					lockdep_is_held(&state->policy_mutex));
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	/* If switching between different policy types, log MLS status */
218362306a36Sopenharmony_ci	if (oldpolicy) {
218462306a36Sopenharmony_ci		if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
218562306a36Sopenharmony_ci			pr_info("SELinux: Disabling MLS support...\n");
218662306a36Sopenharmony_ci		else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
218762306a36Sopenharmony_ci			pr_info("SELinux: Enabling MLS support...\n");
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	/* Set latest granting seqno for new policy. */
219162306a36Sopenharmony_ci	if (oldpolicy)
219262306a36Sopenharmony_ci		newpolicy->latest_granting = oldpolicy->latest_granting + 1;
219362306a36Sopenharmony_ci	else
219462306a36Sopenharmony_ci		newpolicy->latest_granting = 1;
219562306a36Sopenharmony_ci	seqno = newpolicy->latest_granting;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	/* Install the new policy. */
219862306a36Sopenharmony_ci	if (oldpolicy) {
219962306a36Sopenharmony_ci		sidtab_freeze_begin(oldpolicy->sidtab, &flags);
220062306a36Sopenharmony_ci		rcu_assign_pointer(state->policy, newpolicy);
220162306a36Sopenharmony_ci		sidtab_freeze_end(oldpolicy->sidtab, &flags);
220262306a36Sopenharmony_ci	} else {
220362306a36Sopenharmony_ci		rcu_assign_pointer(state->policy, newpolicy);
220462306a36Sopenharmony_ci	}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/* Load the policycaps from the new policy */
220762306a36Sopenharmony_ci	security_load_policycaps(newpolicy);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	if (!selinux_initialized()) {
221062306a36Sopenharmony_ci		/*
221162306a36Sopenharmony_ci		 * After first policy load, the security server is
221262306a36Sopenharmony_ci		 * marked as initialized and ready to handle requests and
221362306a36Sopenharmony_ci		 * any objects created prior to policy load are then labeled.
221462306a36Sopenharmony_ci		 */
221562306a36Sopenharmony_ci		selinux_mark_initialized();
221662306a36Sopenharmony_ci		selinux_complete_init();
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Free the old policy */
222062306a36Sopenharmony_ci	synchronize_rcu();
222162306a36Sopenharmony_ci	selinux_policy_free(oldpolicy);
222262306a36Sopenharmony_ci	kfree(load_state->convert_data);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	/* Notify others of the policy change */
222562306a36Sopenharmony_ci	selinux_notify_policy_change(seqno);
222662306a36Sopenharmony_ci}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci/**
222962306a36Sopenharmony_ci * security_load_policy - Load a security policy configuration.
223062306a36Sopenharmony_ci * @data: binary policy data
223162306a36Sopenharmony_ci * @len: length of data in bytes
223262306a36Sopenharmony_ci * @load_state: policy load state
223362306a36Sopenharmony_ci *
223462306a36Sopenharmony_ci * Load a new set of security policy configuration data,
223562306a36Sopenharmony_ci * validate it and convert the SID table as necessary.
223662306a36Sopenharmony_ci * This function will flush the access vector cache after
223762306a36Sopenharmony_ci * loading the new policy.
223862306a36Sopenharmony_ci */
223962306a36Sopenharmony_ciint security_load_policy(void *data, size_t len,
224062306a36Sopenharmony_ci			 struct selinux_load_state *load_state)
224162306a36Sopenharmony_ci{
224262306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
224362306a36Sopenharmony_ci	struct selinux_policy *newpolicy, *oldpolicy;
224462306a36Sopenharmony_ci	struct selinux_policy_convert_data *convert_data;
224562306a36Sopenharmony_ci	int rc = 0;
224662306a36Sopenharmony_ci	struct policy_file file = { data, len }, *fp = &file;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
224962306a36Sopenharmony_ci	if (!newpolicy)
225062306a36Sopenharmony_ci		return -ENOMEM;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
225362306a36Sopenharmony_ci	if (!newpolicy->sidtab) {
225462306a36Sopenharmony_ci		rc = -ENOMEM;
225562306a36Sopenharmony_ci		goto err_policy;
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	rc = policydb_read(&newpolicy->policydb, fp);
225962306a36Sopenharmony_ci	if (rc)
226062306a36Sopenharmony_ci		goto err_sidtab;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	newpolicy->policydb.len = len;
226362306a36Sopenharmony_ci	rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
226462306a36Sopenharmony_ci				&newpolicy->map);
226562306a36Sopenharmony_ci	if (rc)
226662306a36Sopenharmony_ci		goto err_policydb;
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
226962306a36Sopenharmony_ci	if (rc) {
227062306a36Sopenharmony_ci		pr_err("SELinux:  unable to load the initial SIDs\n");
227162306a36Sopenharmony_ci		goto err_mapping;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	if (!selinux_initialized()) {
227562306a36Sopenharmony_ci		/* First policy load, so no need to preserve state from old policy */
227662306a36Sopenharmony_ci		load_state->policy = newpolicy;
227762306a36Sopenharmony_ci		load_state->convert_data = NULL;
227862306a36Sopenharmony_ci		return 0;
227962306a36Sopenharmony_ci	}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	oldpolicy = rcu_dereference_protected(state->policy,
228262306a36Sopenharmony_ci					lockdep_is_held(&state->policy_mutex));
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/* Preserve active boolean values from the old policy */
228562306a36Sopenharmony_ci	rc = security_preserve_bools(oldpolicy, newpolicy);
228662306a36Sopenharmony_ci	if (rc) {
228762306a36Sopenharmony_ci		pr_err("SELinux:  unable to preserve booleans\n");
228862306a36Sopenharmony_ci		goto err_free_isids;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/*
229262306a36Sopenharmony_ci	 * Convert the internal representations of contexts
229362306a36Sopenharmony_ci	 * in the new SID table.
229462306a36Sopenharmony_ci	 */
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
229762306a36Sopenharmony_ci	if (!convert_data) {
229862306a36Sopenharmony_ci		rc = -ENOMEM;
229962306a36Sopenharmony_ci		goto err_free_isids;
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	convert_data->args.oldp = &oldpolicy->policydb;
230362306a36Sopenharmony_ci	convert_data->args.newp = &newpolicy->policydb;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	convert_data->sidtab_params.args = &convert_data->args;
230662306a36Sopenharmony_ci	convert_data->sidtab_params.target = newpolicy->sidtab;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
230962306a36Sopenharmony_ci	if (rc) {
231062306a36Sopenharmony_ci		pr_err("SELinux:  unable to convert the internal"
231162306a36Sopenharmony_ci			" representation of contexts in the new SID"
231262306a36Sopenharmony_ci			" table\n");
231362306a36Sopenharmony_ci		goto err_free_convert_data;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	load_state->policy = newpolicy;
231762306a36Sopenharmony_ci	load_state->convert_data = convert_data;
231862306a36Sopenharmony_ci	return 0;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_cierr_free_convert_data:
232162306a36Sopenharmony_ci	kfree(convert_data);
232262306a36Sopenharmony_cierr_free_isids:
232362306a36Sopenharmony_ci	sidtab_destroy(newpolicy->sidtab);
232462306a36Sopenharmony_cierr_mapping:
232562306a36Sopenharmony_ci	kfree(newpolicy->map.mapping);
232662306a36Sopenharmony_cierr_policydb:
232762306a36Sopenharmony_ci	policydb_destroy(&newpolicy->policydb);
232862306a36Sopenharmony_cierr_sidtab:
232962306a36Sopenharmony_ci	kfree(newpolicy->sidtab);
233062306a36Sopenharmony_cierr_policy:
233162306a36Sopenharmony_ci	kfree(newpolicy);
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	return rc;
233462306a36Sopenharmony_ci}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci/**
233762306a36Sopenharmony_ci * ocontext_to_sid - Helper to safely get sid for an ocontext
233862306a36Sopenharmony_ci * @sidtab: SID table
233962306a36Sopenharmony_ci * @c: ocontext structure
234062306a36Sopenharmony_ci * @index: index of the context entry (0 or 1)
234162306a36Sopenharmony_ci * @out_sid: pointer to the resulting SID value
234262306a36Sopenharmony_ci *
234362306a36Sopenharmony_ci * For all ocontexts except OCON_ISID the SID fields are populated
234462306a36Sopenharmony_ci * on-demand when needed. Since updating the SID value is an SMP-sensitive
234562306a36Sopenharmony_ci * operation, this helper must be used to do that safely.
234662306a36Sopenharmony_ci *
234762306a36Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller
234862306a36Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer!
234962306a36Sopenharmony_ci */
235062306a36Sopenharmony_cistatic int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
235162306a36Sopenharmony_ci			   size_t index, u32 *out_sid)
235262306a36Sopenharmony_ci{
235362306a36Sopenharmony_ci	int rc;
235462306a36Sopenharmony_ci	u32 sid;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	/* Ensure the associated sidtab entry is visible to this thread. */
235762306a36Sopenharmony_ci	sid = smp_load_acquire(&c->sid[index]);
235862306a36Sopenharmony_ci	if (!sid) {
235962306a36Sopenharmony_ci		rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
236062306a36Sopenharmony_ci		if (rc)
236162306a36Sopenharmony_ci			return rc;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci		/*
236462306a36Sopenharmony_ci		 * Ensure the new sidtab entry is visible to other threads
236562306a36Sopenharmony_ci		 * when they see the SID.
236662306a36Sopenharmony_ci		 */
236762306a36Sopenharmony_ci		smp_store_release(&c->sid[index], sid);
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci	*out_sid = sid;
237062306a36Sopenharmony_ci	return 0;
237162306a36Sopenharmony_ci}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci/**
237462306a36Sopenharmony_ci * security_port_sid - Obtain the SID for a port.
237562306a36Sopenharmony_ci * @protocol: protocol number
237662306a36Sopenharmony_ci * @port: port number
237762306a36Sopenharmony_ci * @out_sid: security identifier
237862306a36Sopenharmony_ci */
237962306a36Sopenharmony_ciint security_port_sid(u8 protocol, u16 port, u32 *out_sid)
238062306a36Sopenharmony_ci{
238162306a36Sopenharmony_ci	struct selinux_policy *policy;
238262306a36Sopenharmony_ci	struct policydb *policydb;
238362306a36Sopenharmony_ci	struct sidtab *sidtab;
238462306a36Sopenharmony_ci	struct ocontext *c;
238562306a36Sopenharmony_ci	int rc;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	if (!selinux_initialized()) {
238862306a36Sopenharmony_ci		*out_sid = SECINITSID_PORT;
238962306a36Sopenharmony_ci		return 0;
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ciretry:
239362306a36Sopenharmony_ci	rc = 0;
239462306a36Sopenharmony_ci	rcu_read_lock();
239562306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
239662306a36Sopenharmony_ci	policydb = &policy->policydb;
239762306a36Sopenharmony_ci	sidtab = policy->sidtab;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	c = policydb->ocontexts[OCON_PORT];
240062306a36Sopenharmony_ci	while (c) {
240162306a36Sopenharmony_ci		if (c->u.port.protocol == protocol &&
240262306a36Sopenharmony_ci		    c->u.port.low_port <= port &&
240362306a36Sopenharmony_ci		    c->u.port.high_port >= port)
240462306a36Sopenharmony_ci			break;
240562306a36Sopenharmony_ci		c = c->next;
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	if (c) {
240962306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
241062306a36Sopenharmony_ci		if (rc == -ESTALE) {
241162306a36Sopenharmony_ci			rcu_read_unlock();
241262306a36Sopenharmony_ci			goto retry;
241362306a36Sopenharmony_ci		}
241462306a36Sopenharmony_ci		if (rc)
241562306a36Sopenharmony_ci			goto out;
241662306a36Sopenharmony_ci	} else {
241762306a36Sopenharmony_ci		*out_sid = SECINITSID_PORT;
241862306a36Sopenharmony_ci	}
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ciout:
242162306a36Sopenharmony_ci	rcu_read_unlock();
242262306a36Sopenharmony_ci	return rc;
242362306a36Sopenharmony_ci}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci/**
242662306a36Sopenharmony_ci * security_ib_pkey_sid - Obtain the SID for a pkey.
242762306a36Sopenharmony_ci * @subnet_prefix: Subnet Prefix
242862306a36Sopenharmony_ci * @pkey_num: pkey number
242962306a36Sopenharmony_ci * @out_sid: security identifier
243062306a36Sopenharmony_ci */
243162306a36Sopenharmony_ciint security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
243262306a36Sopenharmony_ci{
243362306a36Sopenharmony_ci	struct selinux_policy *policy;
243462306a36Sopenharmony_ci	struct policydb *policydb;
243562306a36Sopenharmony_ci	struct sidtab *sidtab;
243662306a36Sopenharmony_ci	struct ocontext *c;
243762306a36Sopenharmony_ci	int rc;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	if (!selinux_initialized()) {
244062306a36Sopenharmony_ci		*out_sid = SECINITSID_UNLABELED;
244162306a36Sopenharmony_ci		return 0;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ciretry:
244562306a36Sopenharmony_ci	rc = 0;
244662306a36Sopenharmony_ci	rcu_read_lock();
244762306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
244862306a36Sopenharmony_ci	policydb = &policy->policydb;
244962306a36Sopenharmony_ci	sidtab = policy->sidtab;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	c = policydb->ocontexts[OCON_IBPKEY];
245262306a36Sopenharmony_ci	while (c) {
245362306a36Sopenharmony_ci		if (c->u.ibpkey.low_pkey <= pkey_num &&
245462306a36Sopenharmony_ci		    c->u.ibpkey.high_pkey >= pkey_num &&
245562306a36Sopenharmony_ci		    c->u.ibpkey.subnet_prefix == subnet_prefix)
245662306a36Sopenharmony_ci			break;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci		c = c->next;
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	if (c) {
246262306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
246362306a36Sopenharmony_ci		if (rc == -ESTALE) {
246462306a36Sopenharmony_ci			rcu_read_unlock();
246562306a36Sopenharmony_ci			goto retry;
246662306a36Sopenharmony_ci		}
246762306a36Sopenharmony_ci		if (rc)
246862306a36Sopenharmony_ci			goto out;
246962306a36Sopenharmony_ci	} else
247062306a36Sopenharmony_ci		*out_sid = SECINITSID_UNLABELED;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ciout:
247362306a36Sopenharmony_ci	rcu_read_unlock();
247462306a36Sopenharmony_ci	return rc;
247562306a36Sopenharmony_ci}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci/**
247862306a36Sopenharmony_ci * security_ib_endport_sid - Obtain the SID for a subnet management interface.
247962306a36Sopenharmony_ci * @dev_name: device name
248062306a36Sopenharmony_ci * @port_num: port number
248162306a36Sopenharmony_ci * @out_sid: security identifier
248262306a36Sopenharmony_ci */
248362306a36Sopenharmony_ciint security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
248462306a36Sopenharmony_ci{
248562306a36Sopenharmony_ci	struct selinux_policy *policy;
248662306a36Sopenharmony_ci	struct policydb *policydb;
248762306a36Sopenharmony_ci	struct sidtab *sidtab;
248862306a36Sopenharmony_ci	struct ocontext *c;
248962306a36Sopenharmony_ci	int rc;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	if (!selinux_initialized()) {
249262306a36Sopenharmony_ci		*out_sid = SECINITSID_UNLABELED;
249362306a36Sopenharmony_ci		return 0;
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ciretry:
249762306a36Sopenharmony_ci	rc = 0;
249862306a36Sopenharmony_ci	rcu_read_lock();
249962306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
250062306a36Sopenharmony_ci	policydb = &policy->policydb;
250162306a36Sopenharmony_ci	sidtab = policy->sidtab;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	c = policydb->ocontexts[OCON_IBENDPORT];
250462306a36Sopenharmony_ci	while (c) {
250562306a36Sopenharmony_ci		if (c->u.ibendport.port == port_num &&
250662306a36Sopenharmony_ci		    !strncmp(c->u.ibendport.dev_name,
250762306a36Sopenharmony_ci			     dev_name,
250862306a36Sopenharmony_ci			     IB_DEVICE_NAME_MAX))
250962306a36Sopenharmony_ci			break;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci		c = c->next;
251262306a36Sopenharmony_ci	}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	if (c) {
251562306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
251662306a36Sopenharmony_ci		if (rc == -ESTALE) {
251762306a36Sopenharmony_ci			rcu_read_unlock();
251862306a36Sopenharmony_ci			goto retry;
251962306a36Sopenharmony_ci		}
252062306a36Sopenharmony_ci		if (rc)
252162306a36Sopenharmony_ci			goto out;
252262306a36Sopenharmony_ci	} else
252362306a36Sopenharmony_ci		*out_sid = SECINITSID_UNLABELED;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ciout:
252662306a36Sopenharmony_ci	rcu_read_unlock();
252762306a36Sopenharmony_ci	return rc;
252862306a36Sopenharmony_ci}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci/**
253162306a36Sopenharmony_ci * security_netif_sid - Obtain the SID for a network interface.
253262306a36Sopenharmony_ci * @name: interface name
253362306a36Sopenharmony_ci * @if_sid: interface SID
253462306a36Sopenharmony_ci */
253562306a36Sopenharmony_ciint security_netif_sid(char *name, u32 *if_sid)
253662306a36Sopenharmony_ci{
253762306a36Sopenharmony_ci	struct selinux_policy *policy;
253862306a36Sopenharmony_ci	struct policydb *policydb;
253962306a36Sopenharmony_ci	struct sidtab *sidtab;
254062306a36Sopenharmony_ci	int rc;
254162306a36Sopenharmony_ci	struct ocontext *c;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	if (!selinux_initialized()) {
254462306a36Sopenharmony_ci		*if_sid = SECINITSID_NETIF;
254562306a36Sopenharmony_ci		return 0;
254662306a36Sopenharmony_ci	}
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ciretry:
254962306a36Sopenharmony_ci	rc = 0;
255062306a36Sopenharmony_ci	rcu_read_lock();
255162306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
255262306a36Sopenharmony_ci	policydb = &policy->policydb;
255362306a36Sopenharmony_ci	sidtab = policy->sidtab;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	c = policydb->ocontexts[OCON_NETIF];
255662306a36Sopenharmony_ci	while (c) {
255762306a36Sopenharmony_ci		if (strcmp(name, c->u.name) == 0)
255862306a36Sopenharmony_ci			break;
255962306a36Sopenharmony_ci		c = c->next;
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	if (c) {
256362306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, if_sid);
256462306a36Sopenharmony_ci		if (rc == -ESTALE) {
256562306a36Sopenharmony_ci			rcu_read_unlock();
256662306a36Sopenharmony_ci			goto retry;
256762306a36Sopenharmony_ci		}
256862306a36Sopenharmony_ci		if (rc)
256962306a36Sopenharmony_ci			goto out;
257062306a36Sopenharmony_ci	} else
257162306a36Sopenharmony_ci		*if_sid = SECINITSID_NETIF;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ciout:
257462306a36Sopenharmony_ci	rcu_read_unlock();
257562306a36Sopenharmony_ci	return rc;
257662306a36Sopenharmony_ci}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_cistatic int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
257962306a36Sopenharmony_ci{
258062306a36Sopenharmony_ci	int i, fail = 0;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
258362306a36Sopenharmony_ci		if (addr[i] != (input[i] & mask[i])) {
258462306a36Sopenharmony_ci			fail = 1;
258562306a36Sopenharmony_ci			break;
258662306a36Sopenharmony_ci		}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	return !fail;
258962306a36Sopenharmony_ci}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci/**
259262306a36Sopenharmony_ci * security_node_sid - Obtain the SID for a node (host).
259362306a36Sopenharmony_ci * @domain: communication domain aka address family
259462306a36Sopenharmony_ci * @addrp: address
259562306a36Sopenharmony_ci * @addrlen: address length in bytes
259662306a36Sopenharmony_ci * @out_sid: security identifier
259762306a36Sopenharmony_ci */
259862306a36Sopenharmony_ciint security_node_sid(u16 domain,
259962306a36Sopenharmony_ci		      void *addrp,
260062306a36Sopenharmony_ci		      u32 addrlen,
260162306a36Sopenharmony_ci		      u32 *out_sid)
260262306a36Sopenharmony_ci{
260362306a36Sopenharmony_ci	struct selinux_policy *policy;
260462306a36Sopenharmony_ci	struct policydb *policydb;
260562306a36Sopenharmony_ci	struct sidtab *sidtab;
260662306a36Sopenharmony_ci	int rc;
260762306a36Sopenharmony_ci	struct ocontext *c;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (!selinux_initialized()) {
261062306a36Sopenharmony_ci		*out_sid = SECINITSID_NODE;
261162306a36Sopenharmony_ci		return 0;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ciretry:
261562306a36Sopenharmony_ci	rcu_read_lock();
261662306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
261762306a36Sopenharmony_ci	policydb = &policy->policydb;
261862306a36Sopenharmony_ci	sidtab = policy->sidtab;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	switch (domain) {
262162306a36Sopenharmony_ci	case AF_INET: {
262262306a36Sopenharmony_ci		u32 addr;
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci		rc = -EINVAL;
262562306a36Sopenharmony_ci		if (addrlen != sizeof(u32))
262662306a36Sopenharmony_ci			goto out;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci		addr = *((u32 *)addrp);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci		c = policydb->ocontexts[OCON_NODE];
263162306a36Sopenharmony_ci		while (c) {
263262306a36Sopenharmony_ci			if (c->u.node.addr == (addr & c->u.node.mask))
263362306a36Sopenharmony_ci				break;
263462306a36Sopenharmony_ci			c = c->next;
263562306a36Sopenharmony_ci		}
263662306a36Sopenharmony_ci		break;
263762306a36Sopenharmony_ci	}
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci	case AF_INET6:
264062306a36Sopenharmony_ci		rc = -EINVAL;
264162306a36Sopenharmony_ci		if (addrlen != sizeof(u64) * 2)
264262306a36Sopenharmony_ci			goto out;
264362306a36Sopenharmony_ci		c = policydb->ocontexts[OCON_NODE6];
264462306a36Sopenharmony_ci		while (c) {
264562306a36Sopenharmony_ci			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
264662306a36Sopenharmony_ci						c->u.node6.mask))
264762306a36Sopenharmony_ci				break;
264862306a36Sopenharmony_ci			c = c->next;
264962306a36Sopenharmony_ci		}
265062306a36Sopenharmony_ci		break;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	default:
265362306a36Sopenharmony_ci		rc = 0;
265462306a36Sopenharmony_ci		*out_sid = SECINITSID_NODE;
265562306a36Sopenharmony_ci		goto out;
265662306a36Sopenharmony_ci	}
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	if (c) {
265962306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
266062306a36Sopenharmony_ci		if (rc == -ESTALE) {
266162306a36Sopenharmony_ci			rcu_read_unlock();
266262306a36Sopenharmony_ci			goto retry;
266362306a36Sopenharmony_ci		}
266462306a36Sopenharmony_ci		if (rc)
266562306a36Sopenharmony_ci			goto out;
266662306a36Sopenharmony_ci	} else {
266762306a36Sopenharmony_ci		*out_sid = SECINITSID_NODE;
266862306a36Sopenharmony_ci	}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	rc = 0;
267162306a36Sopenharmony_ciout:
267262306a36Sopenharmony_ci	rcu_read_unlock();
267362306a36Sopenharmony_ci	return rc;
267462306a36Sopenharmony_ci}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci#define SIDS_NEL 25
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci/**
267962306a36Sopenharmony_ci * security_get_user_sids - Obtain reachable SIDs for a user.
268062306a36Sopenharmony_ci * @fromsid: starting SID
268162306a36Sopenharmony_ci * @username: username
268262306a36Sopenharmony_ci * @sids: array of reachable SIDs for user
268362306a36Sopenharmony_ci * @nel: number of elements in @sids
268462306a36Sopenharmony_ci *
268562306a36Sopenharmony_ci * Generate the set of SIDs for legal security contexts
268662306a36Sopenharmony_ci * for a given user that can be reached by @fromsid.
268762306a36Sopenharmony_ci * Set *@sids to point to a dynamically allocated
268862306a36Sopenharmony_ci * array containing the set of SIDs.  Set *@nel to the
268962306a36Sopenharmony_ci * number of elements in the array.
269062306a36Sopenharmony_ci */
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ciint security_get_user_sids(u32 fromsid,
269362306a36Sopenharmony_ci			   char *username,
269462306a36Sopenharmony_ci			   u32 **sids,
269562306a36Sopenharmony_ci			   u32 *nel)
269662306a36Sopenharmony_ci{
269762306a36Sopenharmony_ci	struct selinux_policy *policy;
269862306a36Sopenharmony_ci	struct policydb *policydb;
269962306a36Sopenharmony_ci	struct sidtab *sidtab;
270062306a36Sopenharmony_ci	struct context *fromcon, usercon;
270162306a36Sopenharmony_ci	u32 *mysids = NULL, *mysids2, sid;
270262306a36Sopenharmony_ci	u32 i, j, mynel, maxnel = SIDS_NEL;
270362306a36Sopenharmony_ci	struct user_datum *user;
270462306a36Sopenharmony_ci	struct role_datum *role;
270562306a36Sopenharmony_ci	struct ebitmap_node *rnode, *tnode;
270662306a36Sopenharmony_ci	int rc;
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	*sids = NULL;
270962306a36Sopenharmony_ci	*nel = 0;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	if (!selinux_initialized())
271262306a36Sopenharmony_ci		return 0;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
271562306a36Sopenharmony_ci	if (!mysids)
271662306a36Sopenharmony_ci		return -ENOMEM;
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ciretry:
271962306a36Sopenharmony_ci	mynel = 0;
272062306a36Sopenharmony_ci	rcu_read_lock();
272162306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
272262306a36Sopenharmony_ci	policydb = &policy->policydb;
272362306a36Sopenharmony_ci	sidtab = policy->sidtab;
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	context_init(&usercon);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	rc = -EINVAL;
272862306a36Sopenharmony_ci	fromcon = sidtab_search(sidtab, fromsid);
272962306a36Sopenharmony_ci	if (!fromcon)
273062306a36Sopenharmony_ci		goto out_unlock;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	rc = -EINVAL;
273362306a36Sopenharmony_ci	user = symtab_search(&policydb->p_users, username);
273462306a36Sopenharmony_ci	if (!user)
273562306a36Sopenharmony_ci		goto out_unlock;
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	usercon.user = user->value;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
274062306a36Sopenharmony_ci		role = policydb->role_val_to_struct[i];
274162306a36Sopenharmony_ci		usercon.role = i + 1;
274262306a36Sopenharmony_ci		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
274362306a36Sopenharmony_ci			usercon.type = j + 1;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci			if (mls_setup_user_range(policydb, fromcon, user,
274662306a36Sopenharmony_ci						 &usercon))
274762306a36Sopenharmony_ci				continue;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
275062306a36Sopenharmony_ci			if (rc == -ESTALE) {
275162306a36Sopenharmony_ci				rcu_read_unlock();
275262306a36Sopenharmony_ci				goto retry;
275362306a36Sopenharmony_ci			}
275462306a36Sopenharmony_ci			if (rc)
275562306a36Sopenharmony_ci				goto out_unlock;
275662306a36Sopenharmony_ci			if (mynel < maxnel) {
275762306a36Sopenharmony_ci				mysids[mynel++] = sid;
275862306a36Sopenharmony_ci			} else {
275962306a36Sopenharmony_ci				rc = -ENOMEM;
276062306a36Sopenharmony_ci				maxnel += SIDS_NEL;
276162306a36Sopenharmony_ci				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
276262306a36Sopenharmony_ci				if (!mysids2)
276362306a36Sopenharmony_ci					goto out_unlock;
276462306a36Sopenharmony_ci				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
276562306a36Sopenharmony_ci				kfree(mysids);
276662306a36Sopenharmony_ci				mysids = mysids2;
276762306a36Sopenharmony_ci				mysids[mynel++] = sid;
276862306a36Sopenharmony_ci			}
276962306a36Sopenharmony_ci		}
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci	rc = 0;
277262306a36Sopenharmony_ciout_unlock:
277362306a36Sopenharmony_ci	rcu_read_unlock();
277462306a36Sopenharmony_ci	if (rc || !mynel) {
277562306a36Sopenharmony_ci		kfree(mysids);
277662306a36Sopenharmony_ci		return rc;
277762306a36Sopenharmony_ci	}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	rc = -ENOMEM;
278062306a36Sopenharmony_ci	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
278162306a36Sopenharmony_ci	if (!mysids2) {
278262306a36Sopenharmony_ci		kfree(mysids);
278362306a36Sopenharmony_ci		return rc;
278462306a36Sopenharmony_ci	}
278562306a36Sopenharmony_ci	for (i = 0, j = 0; i < mynel; i++) {
278662306a36Sopenharmony_ci		struct av_decision dummy_avd;
278762306a36Sopenharmony_ci		rc = avc_has_perm_noaudit(fromsid, mysids[i],
278862306a36Sopenharmony_ci					  SECCLASS_PROCESS, /* kernel value */
278962306a36Sopenharmony_ci					  PROCESS__TRANSITION, AVC_STRICT,
279062306a36Sopenharmony_ci					  &dummy_avd);
279162306a36Sopenharmony_ci		if (!rc)
279262306a36Sopenharmony_ci			mysids2[j++] = mysids[i];
279362306a36Sopenharmony_ci		cond_resched();
279462306a36Sopenharmony_ci	}
279562306a36Sopenharmony_ci	kfree(mysids);
279662306a36Sopenharmony_ci	*sids = mysids2;
279762306a36Sopenharmony_ci	*nel = j;
279862306a36Sopenharmony_ci	return 0;
279962306a36Sopenharmony_ci}
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci/**
280262306a36Sopenharmony_ci * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
280362306a36Sopenharmony_ci * @policy: policy
280462306a36Sopenharmony_ci * @fstype: filesystem type
280562306a36Sopenharmony_ci * @path: path from root of mount
280662306a36Sopenharmony_ci * @orig_sclass: file security class
280762306a36Sopenharmony_ci * @sid: SID for path
280862306a36Sopenharmony_ci *
280962306a36Sopenharmony_ci * Obtain a SID to use for a file in a filesystem that
281062306a36Sopenharmony_ci * cannot support xattr or use a fixed labeling behavior like
281162306a36Sopenharmony_ci * transition SIDs or task SIDs.
281262306a36Sopenharmony_ci *
281362306a36Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller
281462306a36Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer!
281562306a36Sopenharmony_ci */
281662306a36Sopenharmony_cistatic inline int __security_genfs_sid(struct selinux_policy *policy,
281762306a36Sopenharmony_ci				       const char *fstype,
281862306a36Sopenharmony_ci				       const char *path,
281962306a36Sopenharmony_ci				       u16 orig_sclass,
282062306a36Sopenharmony_ci				       u32 *sid)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	struct policydb *policydb = &policy->policydb;
282362306a36Sopenharmony_ci	struct sidtab *sidtab = policy->sidtab;
282462306a36Sopenharmony_ci	u16 sclass;
282562306a36Sopenharmony_ci	struct genfs *genfs;
282662306a36Sopenharmony_ci	struct ocontext *c;
282762306a36Sopenharmony_ci	int cmp = 0;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	while (path[0] == '/' && path[1] == '/')
283062306a36Sopenharmony_ci		path++;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	sclass = unmap_class(&policy->map, orig_sclass);
283362306a36Sopenharmony_ci	*sid = SECINITSID_UNLABELED;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
283662306a36Sopenharmony_ci		cmp = strcmp(fstype, genfs->fstype);
283762306a36Sopenharmony_ci		if (cmp <= 0)
283862306a36Sopenharmony_ci			break;
283962306a36Sopenharmony_ci	}
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	if (!genfs || cmp)
284262306a36Sopenharmony_ci		return -ENOENT;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	for (c = genfs->head; c; c = c->next) {
284562306a36Sopenharmony_ci		size_t len = strlen(c->u.name);
284662306a36Sopenharmony_ci		if ((!c->v.sclass || sclass == c->v.sclass) &&
284762306a36Sopenharmony_ci		    (strncmp(c->u.name, path, len) == 0))
284862306a36Sopenharmony_ci			break;
284962306a36Sopenharmony_ci	}
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	if (!c)
285262306a36Sopenharmony_ci		return -ENOENT;
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	return ocontext_to_sid(sidtab, c, 0, sid);
285562306a36Sopenharmony_ci}
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci/**
285862306a36Sopenharmony_ci * security_genfs_sid - Obtain a SID for a file in a filesystem
285962306a36Sopenharmony_ci * @fstype: filesystem type
286062306a36Sopenharmony_ci * @path: path from root of mount
286162306a36Sopenharmony_ci * @orig_sclass: file security class
286262306a36Sopenharmony_ci * @sid: SID for path
286362306a36Sopenharmony_ci *
286462306a36Sopenharmony_ci * Acquire policy_rwlock before calling __security_genfs_sid() and release
286562306a36Sopenharmony_ci * it afterward.
286662306a36Sopenharmony_ci */
286762306a36Sopenharmony_ciint security_genfs_sid(const char *fstype,
286862306a36Sopenharmony_ci		       const char *path,
286962306a36Sopenharmony_ci		       u16 orig_sclass,
287062306a36Sopenharmony_ci		       u32 *sid)
287162306a36Sopenharmony_ci{
287262306a36Sopenharmony_ci	struct selinux_policy *policy;
287362306a36Sopenharmony_ci	int retval;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (!selinux_initialized()) {
287662306a36Sopenharmony_ci		*sid = SECINITSID_UNLABELED;
287762306a36Sopenharmony_ci		return 0;
287862306a36Sopenharmony_ci	}
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	do {
288162306a36Sopenharmony_ci		rcu_read_lock();
288262306a36Sopenharmony_ci		policy = rcu_dereference(selinux_state.policy);
288362306a36Sopenharmony_ci		retval = __security_genfs_sid(policy, fstype, path,
288462306a36Sopenharmony_ci					      orig_sclass, sid);
288562306a36Sopenharmony_ci		rcu_read_unlock();
288662306a36Sopenharmony_ci	} while (retval == -ESTALE);
288762306a36Sopenharmony_ci	return retval;
288862306a36Sopenharmony_ci}
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ciint selinux_policy_genfs_sid(struct selinux_policy *policy,
289162306a36Sopenharmony_ci			const char *fstype,
289262306a36Sopenharmony_ci			const char *path,
289362306a36Sopenharmony_ci			u16 orig_sclass,
289462306a36Sopenharmony_ci			u32 *sid)
289562306a36Sopenharmony_ci{
289662306a36Sopenharmony_ci	/* no lock required, policy is not yet accessible by other threads */
289762306a36Sopenharmony_ci	return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci/**
290162306a36Sopenharmony_ci * security_fs_use - Determine how to handle labeling for a filesystem.
290262306a36Sopenharmony_ci * @sb: superblock in question
290362306a36Sopenharmony_ci */
290462306a36Sopenharmony_ciint security_fs_use(struct super_block *sb)
290562306a36Sopenharmony_ci{
290662306a36Sopenharmony_ci	struct selinux_policy *policy;
290762306a36Sopenharmony_ci	struct policydb *policydb;
290862306a36Sopenharmony_ci	struct sidtab *sidtab;
290962306a36Sopenharmony_ci	int rc;
291062306a36Sopenharmony_ci	struct ocontext *c;
291162306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
291262306a36Sopenharmony_ci	const char *fstype = sb->s_type->name;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	if (!selinux_initialized()) {
291562306a36Sopenharmony_ci		sbsec->behavior = SECURITY_FS_USE_NONE;
291662306a36Sopenharmony_ci		sbsec->sid = SECINITSID_UNLABELED;
291762306a36Sopenharmony_ci		return 0;
291862306a36Sopenharmony_ci	}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ciretry:
292162306a36Sopenharmony_ci	rcu_read_lock();
292262306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
292362306a36Sopenharmony_ci	policydb = &policy->policydb;
292462306a36Sopenharmony_ci	sidtab = policy->sidtab;
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	c = policydb->ocontexts[OCON_FSUSE];
292762306a36Sopenharmony_ci	while (c) {
292862306a36Sopenharmony_ci		if (strcmp(fstype, c->u.name) == 0)
292962306a36Sopenharmony_ci			break;
293062306a36Sopenharmony_ci		c = c->next;
293162306a36Sopenharmony_ci	}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	if (c) {
293462306a36Sopenharmony_ci		sbsec->behavior = c->v.behavior;
293562306a36Sopenharmony_ci		rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
293662306a36Sopenharmony_ci		if (rc == -ESTALE) {
293762306a36Sopenharmony_ci			rcu_read_unlock();
293862306a36Sopenharmony_ci			goto retry;
293962306a36Sopenharmony_ci		}
294062306a36Sopenharmony_ci		if (rc)
294162306a36Sopenharmony_ci			goto out;
294262306a36Sopenharmony_ci	} else {
294362306a36Sopenharmony_ci		rc = __security_genfs_sid(policy, fstype, "/",
294462306a36Sopenharmony_ci					SECCLASS_DIR, &sbsec->sid);
294562306a36Sopenharmony_ci		if (rc == -ESTALE) {
294662306a36Sopenharmony_ci			rcu_read_unlock();
294762306a36Sopenharmony_ci			goto retry;
294862306a36Sopenharmony_ci		}
294962306a36Sopenharmony_ci		if (rc) {
295062306a36Sopenharmony_ci			sbsec->behavior = SECURITY_FS_USE_NONE;
295162306a36Sopenharmony_ci			rc = 0;
295262306a36Sopenharmony_ci		} else {
295362306a36Sopenharmony_ci			sbsec->behavior = SECURITY_FS_USE_GENFS;
295462306a36Sopenharmony_ci		}
295562306a36Sopenharmony_ci	}
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ciout:
295862306a36Sopenharmony_ci	rcu_read_unlock();
295962306a36Sopenharmony_ci	return rc;
296062306a36Sopenharmony_ci}
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ciint security_get_bools(struct selinux_policy *policy,
296362306a36Sopenharmony_ci		       u32 *len, char ***names, int **values)
296462306a36Sopenharmony_ci{
296562306a36Sopenharmony_ci	struct policydb *policydb;
296662306a36Sopenharmony_ci	u32 i;
296762306a36Sopenharmony_ci	int rc;
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	policydb = &policy->policydb;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	*names = NULL;
297262306a36Sopenharmony_ci	*values = NULL;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	rc = 0;
297562306a36Sopenharmony_ci	*len = policydb->p_bools.nprim;
297662306a36Sopenharmony_ci	if (!*len)
297762306a36Sopenharmony_ci		goto out;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci	rc = -ENOMEM;
298062306a36Sopenharmony_ci	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
298162306a36Sopenharmony_ci	if (!*names)
298262306a36Sopenharmony_ci		goto err;
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	rc = -ENOMEM;
298562306a36Sopenharmony_ci	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
298662306a36Sopenharmony_ci	if (!*values)
298762306a36Sopenharmony_ci		goto err;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	for (i = 0; i < *len; i++) {
299062306a36Sopenharmony_ci		(*values)[i] = policydb->bool_val_to_struct[i]->state;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci		rc = -ENOMEM;
299362306a36Sopenharmony_ci		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
299462306a36Sopenharmony_ci				      GFP_ATOMIC);
299562306a36Sopenharmony_ci		if (!(*names)[i])
299662306a36Sopenharmony_ci			goto err;
299762306a36Sopenharmony_ci	}
299862306a36Sopenharmony_ci	rc = 0;
299962306a36Sopenharmony_ciout:
300062306a36Sopenharmony_ci	return rc;
300162306a36Sopenharmony_cierr:
300262306a36Sopenharmony_ci	if (*names) {
300362306a36Sopenharmony_ci		for (i = 0; i < *len; i++)
300462306a36Sopenharmony_ci			kfree((*names)[i]);
300562306a36Sopenharmony_ci		kfree(*names);
300662306a36Sopenharmony_ci	}
300762306a36Sopenharmony_ci	kfree(*values);
300862306a36Sopenharmony_ci	*len = 0;
300962306a36Sopenharmony_ci	*names = NULL;
301062306a36Sopenharmony_ci	*values = NULL;
301162306a36Sopenharmony_ci	goto out;
301262306a36Sopenharmony_ci}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ciint security_set_bools(u32 len, int *values)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
301862306a36Sopenharmony_ci	struct selinux_policy *newpolicy, *oldpolicy;
301962306a36Sopenharmony_ci	int rc;
302062306a36Sopenharmony_ci	u32 i, seqno = 0;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (!selinux_initialized())
302362306a36Sopenharmony_ci		return -EINVAL;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	oldpolicy = rcu_dereference_protected(state->policy,
302662306a36Sopenharmony_ci					lockdep_is_held(&state->policy_mutex));
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	/* Consistency check on number of booleans, should never fail */
302962306a36Sopenharmony_ci	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
303062306a36Sopenharmony_ci		return -EINVAL;
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci	newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
303362306a36Sopenharmony_ci	if (!newpolicy)
303462306a36Sopenharmony_ci		return -ENOMEM;
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	/*
303762306a36Sopenharmony_ci	 * Deep copy only the parts of the policydb that might be
303862306a36Sopenharmony_ci	 * modified as a result of changing booleans.
303962306a36Sopenharmony_ci	 */
304062306a36Sopenharmony_ci	rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
304162306a36Sopenharmony_ci	if (rc) {
304262306a36Sopenharmony_ci		kfree(newpolicy);
304362306a36Sopenharmony_ci		return -ENOMEM;
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	/* Update the boolean states in the copy */
304762306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
304862306a36Sopenharmony_ci		int new_state = !!values[i];
304962306a36Sopenharmony_ci		int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci		if (new_state != old_state) {
305262306a36Sopenharmony_ci			audit_log(audit_context(), GFP_ATOMIC,
305362306a36Sopenharmony_ci				AUDIT_MAC_CONFIG_CHANGE,
305462306a36Sopenharmony_ci				"bool=%s val=%d old_val=%d auid=%u ses=%u",
305562306a36Sopenharmony_ci				sym_name(&newpolicy->policydb, SYM_BOOLS, i),
305662306a36Sopenharmony_ci				new_state,
305762306a36Sopenharmony_ci				old_state,
305862306a36Sopenharmony_ci				from_kuid(&init_user_ns, audit_get_loginuid(current)),
305962306a36Sopenharmony_ci				audit_get_sessionid(current));
306062306a36Sopenharmony_ci			newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
306162306a36Sopenharmony_ci		}
306262306a36Sopenharmony_ci	}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	/* Re-evaluate the conditional rules in the copy */
306562306a36Sopenharmony_ci	evaluate_cond_nodes(&newpolicy->policydb);
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	/* Set latest granting seqno for new policy */
306862306a36Sopenharmony_ci	newpolicy->latest_granting = oldpolicy->latest_granting + 1;
306962306a36Sopenharmony_ci	seqno = newpolicy->latest_granting;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* Install the new policy */
307262306a36Sopenharmony_ci	rcu_assign_pointer(state->policy, newpolicy);
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	/*
307562306a36Sopenharmony_ci	 * Free the conditional portions of the old policydb
307662306a36Sopenharmony_ci	 * that were copied for the new policy, and the oldpolicy
307762306a36Sopenharmony_ci	 * structure itself but not what it references.
307862306a36Sopenharmony_ci	 */
307962306a36Sopenharmony_ci	synchronize_rcu();
308062306a36Sopenharmony_ci	selinux_policy_cond_free(oldpolicy);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	/* Notify others of the policy change */
308362306a36Sopenharmony_ci	selinux_notify_policy_change(seqno);
308462306a36Sopenharmony_ci	return 0;
308562306a36Sopenharmony_ci}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ciint security_get_bool_value(u32 index)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	struct selinux_policy *policy;
309062306a36Sopenharmony_ci	struct policydb *policydb;
309162306a36Sopenharmony_ci	int rc;
309262306a36Sopenharmony_ci	u32 len;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	if (!selinux_initialized())
309562306a36Sopenharmony_ci		return 0;
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	rcu_read_lock();
309862306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
309962306a36Sopenharmony_ci	policydb = &policy->policydb;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	rc = -EFAULT;
310262306a36Sopenharmony_ci	len = policydb->p_bools.nprim;
310362306a36Sopenharmony_ci	if (index >= len)
310462306a36Sopenharmony_ci		goto out;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	rc = policydb->bool_val_to_struct[index]->state;
310762306a36Sopenharmony_ciout:
310862306a36Sopenharmony_ci	rcu_read_unlock();
310962306a36Sopenharmony_ci	return rc;
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy,
311362306a36Sopenharmony_ci				struct selinux_policy *newpolicy)
311462306a36Sopenharmony_ci{
311562306a36Sopenharmony_ci	int rc, *bvalues = NULL;
311662306a36Sopenharmony_ci	char **bnames = NULL;
311762306a36Sopenharmony_ci	struct cond_bool_datum *booldatum;
311862306a36Sopenharmony_ci	u32 i, nbools = 0;
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci	rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
312162306a36Sopenharmony_ci	if (rc)
312262306a36Sopenharmony_ci		goto out;
312362306a36Sopenharmony_ci	for (i = 0; i < nbools; i++) {
312462306a36Sopenharmony_ci		booldatum = symtab_search(&newpolicy->policydb.p_bools,
312562306a36Sopenharmony_ci					bnames[i]);
312662306a36Sopenharmony_ci		if (booldatum)
312762306a36Sopenharmony_ci			booldatum->state = bvalues[i];
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci	evaluate_cond_nodes(&newpolicy->policydb);
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ciout:
313262306a36Sopenharmony_ci	if (bnames) {
313362306a36Sopenharmony_ci		for (i = 0; i < nbools; i++)
313462306a36Sopenharmony_ci			kfree(bnames[i]);
313562306a36Sopenharmony_ci	}
313662306a36Sopenharmony_ci	kfree(bnames);
313762306a36Sopenharmony_ci	kfree(bvalues);
313862306a36Sopenharmony_ci	return rc;
313962306a36Sopenharmony_ci}
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci/*
314262306a36Sopenharmony_ci * security_sid_mls_copy() - computes a new sid based on the given
314362306a36Sopenharmony_ci * sid and the mls portion of mls_sid.
314462306a36Sopenharmony_ci */
314562306a36Sopenharmony_ciint security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
314662306a36Sopenharmony_ci{
314762306a36Sopenharmony_ci	struct selinux_policy *policy;
314862306a36Sopenharmony_ci	struct policydb *policydb;
314962306a36Sopenharmony_ci	struct sidtab *sidtab;
315062306a36Sopenharmony_ci	struct context *context1;
315162306a36Sopenharmony_ci	struct context *context2;
315262306a36Sopenharmony_ci	struct context newcon;
315362306a36Sopenharmony_ci	char *s;
315462306a36Sopenharmony_ci	u32 len;
315562306a36Sopenharmony_ci	int rc;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	if (!selinux_initialized()) {
315862306a36Sopenharmony_ci		*new_sid = sid;
315962306a36Sopenharmony_ci		return 0;
316062306a36Sopenharmony_ci	}
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ciretry:
316362306a36Sopenharmony_ci	rc = 0;
316462306a36Sopenharmony_ci	context_init(&newcon);
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	rcu_read_lock();
316762306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
316862306a36Sopenharmony_ci	policydb = &policy->policydb;
316962306a36Sopenharmony_ci	sidtab = policy->sidtab;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	if (!policydb->mls_enabled) {
317262306a36Sopenharmony_ci		*new_sid = sid;
317362306a36Sopenharmony_ci		goto out_unlock;
317462306a36Sopenharmony_ci	}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	rc = -EINVAL;
317762306a36Sopenharmony_ci	context1 = sidtab_search(sidtab, sid);
317862306a36Sopenharmony_ci	if (!context1) {
317962306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
318062306a36Sopenharmony_ci			__func__, sid);
318162306a36Sopenharmony_ci		goto out_unlock;
318262306a36Sopenharmony_ci	}
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	rc = -EINVAL;
318562306a36Sopenharmony_ci	context2 = sidtab_search(sidtab, mls_sid);
318662306a36Sopenharmony_ci	if (!context2) {
318762306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
318862306a36Sopenharmony_ci			__func__, mls_sid);
318962306a36Sopenharmony_ci		goto out_unlock;
319062306a36Sopenharmony_ci	}
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	newcon.user = context1->user;
319362306a36Sopenharmony_ci	newcon.role = context1->role;
319462306a36Sopenharmony_ci	newcon.type = context1->type;
319562306a36Sopenharmony_ci	rc = mls_context_cpy(&newcon, context2);
319662306a36Sopenharmony_ci	if (rc)
319762306a36Sopenharmony_ci		goto out_unlock;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	/* Check the validity of the new context. */
320062306a36Sopenharmony_ci	if (!policydb_context_isvalid(policydb, &newcon)) {
320162306a36Sopenharmony_ci		rc = convert_context_handle_invalid_context(policydb,
320262306a36Sopenharmony_ci							&newcon);
320362306a36Sopenharmony_ci		if (rc) {
320462306a36Sopenharmony_ci			if (!context_struct_to_string(policydb, &newcon, &s,
320562306a36Sopenharmony_ci						      &len)) {
320662306a36Sopenharmony_ci				struct audit_buffer *ab;
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci				ab = audit_log_start(audit_context(),
320962306a36Sopenharmony_ci						     GFP_ATOMIC,
321062306a36Sopenharmony_ci						     AUDIT_SELINUX_ERR);
321162306a36Sopenharmony_ci				audit_log_format(ab,
321262306a36Sopenharmony_ci						 "op=security_sid_mls_copy invalid_context=");
321362306a36Sopenharmony_ci				/* don't record NUL with untrusted strings */
321462306a36Sopenharmony_ci				audit_log_n_untrustedstring(ab, s, len - 1);
321562306a36Sopenharmony_ci				audit_log_end(ab);
321662306a36Sopenharmony_ci				kfree(s);
321762306a36Sopenharmony_ci			}
321862306a36Sopenharmony_ci			goto out_unlock;
321962306a36Sopenharmony_ci		}
322062306a36Sopenharmony_ci	}
322162306a36Sopenharmony_ci	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
322262306a36Sopenharmony_ci	if (rc == -ESTALE) {
322362306a36Sopenharmony_ci		rcu_read_unlock();
322462306a36Sopenharmony_ci		context_destroy(&newcon);
322562306a36Sopenharmony_ci		goto retry;
322662306a36Sopenharmony_ci	}
322762306a36Sopenharmony_ciout_unlock:
322862306a36Sopenharmony_ci	rcu_read_unlock();
322962306a36Sopenharmony_ci	context_destroy(&newcon);
323062306a36Sopenharmony_ci	return rc;
323162306a36Sopenharmony_ci}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci/**
323462306a36Sopenharmony_ci * security_net_peersid_resolve - Compare and resolve two network peer SIDs
323562306a36Sopenharmony_ci * @nlbl_sid: NetLabel SID
323662306a36Sopenharmony_ci * @nlbl_type: NetLabel labeling protocol type
323762306a36Sopenharmony_ci * @xfrm_sid: XFRM SID
323862306a36Sopenharmony_ci * @peer_sid: network peer sid
323962306a36Sopenharmony_ci *
324062306a36Sopenharmony_ci * Description:
324162306a36Sopenharmony_ci * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
324262306a36Sopenharmony_ci * resolved into a single SID it is returned via @peer_sid and the function
324362306a36Sopenharmony_ci * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
324462306a36Sopenharmony_ci * returns a negative value.  A table summarizing the behavior is below:
324562306a36Sopenharmony_ci *
324662306a36Sopenharmony_ci *                                 | function return |      @sid
324762306a36Sopenharmony_ci *   ------------------------------+-----------------+-----------------
324862306a36Sopenharmony_ci *   no peer labels                |        0        |    SECSID_NULL
324962306a36Sopenharmony_ci *   single peer label             |        0        |    <peer_label>
325062306a36Sopenharmony_ci *   multiple, consistent labels   |        0        |    <peer_label>
325162306a36Sopenharmony_ci *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
325262306a36Sopenharmony_ci *
325362306a36Sopenharmony_ci */
325462306a36Sopenharmony_ciint security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
325562306a36Sopenharmony_ci				 u32 xfrm_sid,
325662306a36Sopenharmony_ci				 u32 *peer_sid)
325762306a36Sopenharmony_ci{
325862306a36Sopenharmony_ci	struct selinux_policy *policy;
325962306a36Sopenharmony_ci	struct policydb *policydb;
326062306a36Sopenharmony_ci	struct sidtab *sidtab;
326162306a36Sopenharmony_ci	int rc;
326262306a36Sopenharmony_ci	struct context *nlbl_ctx;
326362306a36Sopenharmony_ci	struct context *xfrm_ctx;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	*peer_sid = SECSID_NULL;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	/* handle the common (which also happens to be the set of easy) cases
326862306a36Sopenharmony_ci	 * right away, these two if statements catch everything involving a
326962306a36Sopenharmony_ci	 * single or absent peer SID/label */
327062306a36Sopenharmony_ci	if (xfrm_sid == SECSID_NULL) {
327162306a36Sopenharmony_ci		*peer_sid = nlbl_sid;
327262306a36Sopenharmony_ci		return 0;
327362306a36Sopenharmony_ci	}
327462306a36Sopenharmony_ci	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
327562306a36Sopenharmony_ci	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
327662306a36Sopenharmony_ci	 * is present */
327762306a36Sopenharmony_ci	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
327862306a36Sopenharmony_ci		*peer_sid = xfrm_sid;
327962306a36Sopenharmony_ci		return 0;
328062306a36Sopenharmony_ci	}
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	if (!selinux_initialized())
328362306a36Sopenharmony_ci		return 0;
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	rcu_read_lock();
328662306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
328762306a36Sopenharmony_ci	policydb = &policy->policydb;
328862306a36Sopenharmony_ci	sidtab = policy->sidtab;
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	/*
329162306a36Sopenharmony_ci	 * We don't need to check initialized here since the only way both
329262306a36Sopenharmony_ci	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
329362306a36Sopenharmony_ci	 * security server was initialized and state->initialized was true.
329462306a36Sopenharmony_ci	 */
329562306a36Sopenharmony_ci	if (!policydb->mls_enabled) {
329662306a36Sopenharmony_ci		rc = 0;
329762306a36Sopenharmony_ci		goto out;
329862306a36Sopenharmony_ci	}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	rc = -EINVAL;
330162306a36Sopenharmony_ci	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
330262306a36Sopenharmony_ci	if (!nlbl_ctx) {
330362306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
330462306a36Sopenharmony_ci		       __func__, nlbl_sid);
330562306a36Sopenharmony_ci		goto out;
330662306a36Sopenharmony_ci	}
330762306a36Sopenharmony_ci	rc = -EINVAL;
330862306a36Sopenharmony_ci	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
330962306a36Sopenharmony_ci	if (!xfrm_ctx) {
331062306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized SID %d\n",
331162306a36Sopenharmony_ci		       __func__, xfrm_sid);
331262306a36Sopenharmony_ci		goto out;
331362306a36Sopenharmony_ci	}
331462306a36Sopenharmony_ci	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
331562306a36Sopenharmony_ci	if (rc)
331662306a36Sopenharmony_ci		goto out;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	/* at present NetLabel SIDs/labels really only carry MLS
331962306a36Sopenharmony_ci	 * information so if the MLS portion of the NetLabel SID
332062306a36Sopenharmony_ci	 * matches the MLS portion of the labeled XFRM SID/label
332162306a36Sopenharmony_ci	 * then pass along the XFRM SID as it is the most
332262306a36Sopenharmony_ci	 * expressive */
332362306a36Sopenharmony_ci	*peer_sid = xfrm_sid;
332462306a36Sopenharmony_ciout:
332562306a36Sopenharmony_ci	rcu_read_unlock();
332662306a36Sopenharmony_ci	return rc;
332762306a36Sopenharmony_ci}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_cistatic int get_classes_callback(void *k, void *d, void *args)
333062306a36Sopenharmony_ci{
333162306a36Sopenharmony_ci	struct class_datum *datum = d;
333262306a36Sopenharmony_ci	char *name = k, **classes = args;
333362306a36Sopenharmony_ci	u32 value = datum->value - 1;
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	classes[value] = kstrdup(name, GFP_ATOMIC);
333662306a36Sopenharmony_ci	if (!classes[value])
333762306a36Sopenharmony_ci		return -ENOMEM;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	return 0;
334062306a36Sopenharmony_ci}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ciint security_get_classes(struct selinux_policy *policy,
334362306a36Sopenharmony_ci			 char ***classes, u32 *nclasses)
334462306a36Sopenharmony_ci{
334562306a36Sopenharmony_ci	struct policydb *policydb;
334662306a36Sopenharmony_ci	int rc;
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	policydb = &policy->policydb;
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	rc = -ENOMEM;
335162306a36Sopenharmony_ci	*nclasses = policydb->p_classes.nprim;
335262306a36Sopenharmony_ci	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
335362306a36Sopenharmony_ci	if (!*classes)
335462306a36Sopenharmony_ci		goto out;
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci	rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
335762306a36Sopenharmony_ci			 *classes);
335862306a36Sopenharmony_ci	if (rc) {
335962306a36Sopenharmony_ci		u32 i;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci		for (i = 0; i < *nclasses; i++)
336262306a36Sopenharmony_ci			kfree((*classes)[i]);
336362306a36Sopenharmony_ci		kfree(*classes);
336462306a36Sopenharmony_ci	}
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ciout:
336762306a36Sopenharmony_ci	return rc;
336862306a36Sopenharmony_ci}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_cistatic int get_permissions_callback(void *k, void *d, void *args)
337162306a36Sopenharmony_ci{
337262306a36Sopenharmony_ci	struct perm_datum *datum = d;
337362306a36Sopenharmony_ci	char *name = k, **perms = args;
337462306a36Sopenharmony_ci	u32 value = datum->value - 1;
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	perms[value] = kstrdup(name, GFP_ATOMIC);
337762306a36Sopenharmony_ci	if (!perms[value])
337862306a36Sopenharmony_ci		return -ENOMEM;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	return 0;
338162306a36Sopenharmony_ci}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ciint security_get_permissions(struct selinux_policy *policy,
338462306a36Sopenharmony_ci			     const char *class, char ***perms, u32 *nperms)
338562306a36Sopenharmony_ci{
338662306a36Sopenharmony_ci	struct policydb *policydb;
338762306a36Sopenharmony_ci	u32 i;
338862306a36Sopenharmony_ci	int rc;
338962306a36Sopenharmony_ci	struct class_datum *match;
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	policydb = &policy->policydb;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	rc = -EINVAL;
339462306a36Sopenharmony_ci	match = symtab_search(&policydb->p_classes, class);
339562306a36Sopenharmony_ci	if (!match) {
339662306a36Sopenharmony_ci		pr_err("SELinux: %s:  unrecognized class %s\n",
339762306a36Sopenharmony_ci			__func__, class);
339862306a36Sopenharmony_ci		goto out;
339962306a36Sopenharmony_ci	}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	rc = -ENOMEM;
340262306a36Sopenharmony_ci	*nperms = match->permissions.nprim;
340362306a36Sopenharmony_ci	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
340462306a36Sopenharmony_ci	if (!*perms)
340562306a36Sopenharmony_ci		goto out;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	if (match->comdatum) {
340862306a36Sopenharmony_ci		rc = hashtab_map(&match->comdatum->permissions.table,
340962306a36Sopenharmony_ci				 get_permissions_callback, *perms);
341062306a36Sopenharmony_ci		if (rc)
341162306a36Sopenharmony_ci			goto err;
341262306a36Sopenharmony_ci	}
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	rc = hashtab_map(&match->permissions.table, get_permissions_callback,
341562306a36Sopenharmony_ci			 *perms);
341662306a36Sopenharmony_ci	if (rc)
341762306a36Sopenharmony_ci		goto err;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ciout:
342062306a36Sopenharmony_ci	return rc;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_cierr:
342362306a36Sopenharmony_ci	for (i = 0; i < *nperms; i++)
342462306a36Sopenharmony_ci		kfree((*perms)[i]);
342562306a36Sopenharmony_ci	kfree(*perms);
342662306a36Sopenharmony_ci	return rc;
342762306a36Sopenharmony_ci}
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ciint security_get_reject_unknown(void)
343062306a36Sopenharmony_ci{
343162306a36Sopenharmony_ci	struct selinux_policy *policy;
343262306a36Sopenharmony_ci	int value;
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci	if (!selinux_initialized())
343562306a36Sopenharmony_ci		return 0;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	rcu_read_lock();
343862306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
343962306a36Sopenharmony_ci	value = policy->policydb.reject_unknown;
344062306a36Sopenharmony_ci	rcu_read_unlock();
344162306a36Sopenharmony_ci	return value;
344262306a36Sopenharmony_ci}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ciint security_get_allow_unknown(void)
344562306a36Sopenharmony_ci{
344662306a36Sopenharmony_ci	struct selinux_policy *policy;
344762306a36Sopenharmony_ci	int value;
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	if (!selinux_initialized())
345062306a36Sopenharmony_ci		return 0;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	rcu_read_lock();
345362306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
345462306a36Sopenharmony_ci	value = policy->policydb.allow_unknown;
345562306a36Sopenharmony_ci	rcu_read_unlock();
345662306a36Sopenharmony_ci	return value;
345762306a36Sopenharmony_ci}
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci/**
346062306a36Sopenharmony_ci * security_policycap_supported - Check for a specific policy capability
346162306a36Sopenharmony_ci * @req_cap: capability
346262306a36Sopenharmony_ci *
346362306a36Sopenharmony_ci * Description:
346462306a36Sopenharmony_ci * This function queries the currently loaded policy to see if it supports the
346562306a36Sopenharmony_ci * capability specified by @req_cap.  Returns true (1) if the capability is
346662306a36Sopenharmony_ci * supported, false (0) if it isn't supported.
346762306a36Sopenharmony_ci *
346862306a36Sopenharmony_ci */
346962306a36Sopenharmony_ciint security_policycap_supported(unsigned int req_cap)
347062306a36Sopenharmony_ci{
347162306a36Sopenharmony_ci	struct selinux_policy *policy;
347262306a36Sopenharmony_ci	int rc;
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	if (!selinux_initialized())
347562306a36Sopenharmony_ci		return 0;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	rcu_read_lock();
347862306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
347962306a36Sopenharmony_ci	rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
348062306a36Sopenharmony_ci	rcu_read_unlock();
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	return rc;
348362306a36Sopenharmony_ci}
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_cistruct selinux_audit_rule {
348662306a36Sopenharmony_ci	u32 au_seqno;
348762306a36Sopenharmony_ci	struct context au_ctxt;
348862306a36Sopenharmony_ci};
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_civoid selinux_audit_rule_free(void *vrule)
349162306a36Sopenharmony_ci{
349262306a36Sopenharmony_ci	struct selinux_audit_rule *rule = vrule;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	if (rule) {
349562306a36Sopenharmony_ci		context_destroy(&rule->au_ctxt);
349662306a36Sopenharmony_ci		kfree(rule);
349762306a36Sopenharmony_ci	}
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ciint selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
350162306a36Sopenharmony_ci{
350262306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
350362306a36Sopenharmony_ci	struct selinux_policy *policy;
350462306a36Sopenharmony_ci	struct policydb *policydb;
350562306a36Sopenharmony_ci	struct selinux_audit_rule *tmprule;
350662306a36Sopenharmony_ci	struct role_datum *roledatum;
350762306a36Sopenharmony_ci	struct type_datum *typedatum;
350862306a36Sopenharmony_ci	struct user_datum *userdatum;
350962306a36Sopenharmony_ci	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
351062306a36Sopenharmony_ci	int rc = 0;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	*rule = NULL;
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	if (!selinux_initialized())
351562306a36Sopenharmony_ci		return -EOPNOTSUPP;
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci	switch (field) {
351862306a36Sopenharmony_ci	case AUDIT_SUBJ_USER:
351962306a36Sopenharmony_ci	case AUDIT_SUBJ_ROLE:
352062306a36Sopenharmony_ci	case AUDIT_SUBJ_TYPE:
352162306a36Sopenharmony_ci	case AUDIT_OBJ_USER:
352262306a36Sopenharmony_ci	case AUDIT_OBJ_ROLE:
352362306a36Sopenharmony_ci	case AUDIT_OBJ_TYPE:
352462306a36Sopenharmony_ci		/* only 'equals' and 'not equals' fit user, role, and type */
352562306a36Sopenharmony_ci		if (op != Audit_equal && op != Audit_not_equal)
352662306a36Sopenharmony_ci			return -EINVAL;
352762306a36Sopenharmony_ci		break;
352862306a36Sopenharmony_ci	case AUDIT_SUBJ_SEN:
352962306a36Sopenharmony_ci	case AUDIT_SUBJ_CLR:
353062306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_LOW:
353162306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_HIGH:
353262306a36Sopenharmony_ci		/* we do not allow a range, indicated by the presence of '-' */
353362306a36Sopenharmony_ci		if (strchr(rulestr, '-'))
353462306a36Sopenharmony_ci			return -EINVAL;
353562306a36Sopenharmony_ci		break;
353662306a36Sopenharmony_ci	default:
353762306a36Sopenharmony_ci		/* only the above fields are valid */
353862306a36Sopenharmony_ci		return -EINVAL;
353962306a36Sopenharmony_ci	}
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
354262306a36Sopenharmony_ci	if (!tmprule)
354362306a36Sopenharmony_ci		return -ENOMEM;
354462306a36Sopenharmony_ci	context_init(&tmprule->au_ctxt);
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	rcu_read_lock();
354762306a36Sopenharmony_ci	policy = rcu_dereference(state->policy);
354862306a36Sopenharmony_ci	policydb = &policy->policydb;
354962306a36Sopenharmony_ci	tmprule->au_seqno = policy->latest_granting;
355062306a36Sopenharmony_ci	switch (field) {
355162306a36Sopenharmony_ci	case AUDIT_SUBJ_USER:
355262306a36Sopenharmony_ci	case AUDIT_OBJ_USER:
355362306a36Sopenharmony_ci		userdatum = symtab_search(&policydb->p_users, rulestr);
355462306a36Sopenharmony_ci		if (!userdatum) {
355562306a36Sopenharmony_ci			rc = -EINVAL;
355662306a36Sopenharmony_ci			goto err;
355762306a36Sopenharmony_ci		}
355862306a36Sopenharmony_ci		tmprule->au_ctxt.user = userdatum->value;
355962306a36Sopenharmony_ci		break;
356062306a36Sopenharmony_ci	case AUDIT_SUBJ_ROLE:
356162306a36Sopenharmony_ci	case AUDIT_OBJ_ROLE:
356262306a36Sopenharmony_ci		roledatum = symtab_search(&policydb->p_roles, rulestr);
356362306a36Sopenharmony_ci		if (!roledatum) {
356462306a36Sopenharmony_ci			rc = -EINVAL;
356562306a36Sopenharmony_ci			goto err;
356662306a36Sopenharmony_ci		}
356762306a36Sopenharmony_ci		tmprule->au_ctxt.role = roledatum->value;
356862306a36Sopenharmony_ci		break;
356962306a36Sopenharmony_ci	case AUDIT_SUBJ_TYPE:
357062306a36Sopenharmony_ci	case AUDIT_OBJ_TYPE:
357162306a36Sopenharmony_ci		typedatum = symtab_search(&policydb->p_types, rulestr);
357262306a36Sopenharmony_ci		if (!typedatum) {
357362306a36Sopenharmony_ci			rc = -EINVAL;
357462306a36Sopenharmony_ci			goto err;
357562306a36Sopenharmony_ci		}
357662306a36Sopenharmony_ci		tmprule->au_ctxt.type = typedatum->value;
357762306a36Sopenharmony_ci		break;
357862306a36Sopenharmony_ci	case AUDIT_SUBJ_SEN:
357962306a36Sopenharmony_ci	case AUDIT_SUBJ_CLR:
358062306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_LOW:
358162306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_HIGH:
358262306a36Sopenharmony_ci		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
358362306a36Sopenharmony_ci				     GFP_ATOMIC);
358462306a36Sopenharmony_ci		if (rc)
358562306a36Sopenharmony_ci			goto err;
358662306a36Sopenharmony_ci		break;
358762306a36Sopenharmony_ci	}
358862306a36Sopenharmony_ci	rcu_read_unlock();
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	*rule = tmprule;
359162306a36Sopenharmony_ci	return 0;
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_cierr:
359462306a36Sopenharmony_ci	rcu_read_unlock();
359562306a36Sopenharmony_ci	selinux_audit_rule_free(tmprule);
359662306a36Sopenharmony_ci	*rule = NULL;
359762306a36Sopenharmony_ci	return rc;
359862306a36Sopenharmony_ci}
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci/* Check to see if the rule contains any selinux fields */
360162306a36Sopenharmony_ciint selinux_audit_rule_known(struct audit_krule *rule)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	u32 i;
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	for (i = 0; i < rule->field_count; i++) {
360662306a36Sopenharmony_ci		struct audit_field *f = &rule->fields[i];
360762306a36Sopenharmony_ci		switch (f->type) {
360862306a36Sopenharmony_ci		case AUDIT_SUBJ_USER:
360962306a36Sopenharmony_ci		case AUDIT_SUBJ_ROLE:
361062306a36Sopenharmony_ci		case AUDIT_SUBJ_TYPE:
361162306a36Sopenharmony_ci		case AUDIT_SUBJ_SEN:
361262306a36Sopenharmony_ci		case AUDIT_SUBJ_CLR:
361362306a36Sopenharmony_ci		case AUDIT_OBJ_USER:
361462306a36Sopenharmony_ci		case AUDIT_OBJ_ROLE:
361562306a36Sopenharmony_ci		case AUDIT_OBJ_TYPE:
361662306a36Sopenharmony_ci		case AUDIT_OBJ_LEV_LOW:
361762306a36Sopenharmony_ci		case AUDIT_OBJ_LEV_HIGH:
361862306a36Sopenharmony_ci			return 1;
361962306a36Sopenharmony_ci		}
362062306a36Sopenharmony_ci	}
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	return 0;
362362306a36Sopenharmony_ci}
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ciint selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
362662306a36Sopenharmony_ci{
362762306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
362862306a36Sopenharmony_ci	struct selinux_policy *policy;
362962306a36Sopenharmony_ci	struct context *ctxt;
363062306a36Sopenharmony_ci	struct mls_level *level;
363162306a36Sopenharmony_ci	struct selinux_audit_rule *rule = vrule;
363262306a36Sopenharmony_ci	int match = 0;
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	if (unlikely(!rule)) {
363562306a36Sopenharmony_ci		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
363662306a36Sopenharmony_ci		return -ENOENT;
363762306a36Sopenharmony_ci	}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	if (!selinux_initialized())
364062306a36Sopenharmony_ci		return 0;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	rcu_read_lock();
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	policy = rcu_dereference(state->policy);
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	if (rule->au_seqno < policy->latest_granting) {
364762306a36Sopenharmony_ci		match = -ESTALE;
364862306a36Sopenharmony_ci		goto out;
364962306a36Sopenharmony_ci	}
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	ctxt = sidtab_search(policy->sidtab, sid);
365262306a36Sopenharmony_ci	if (unlikely(!ctxt)) {
365362306a36Sopenharmony_ci		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
365462306a36Sopenharmony_ci			  sid);
365562306a36Sopenharmony_ci		match = -ENOENT;
365662306a36Sopenharmony_ci		goto out;
365762306a36Sopenharmony_ci	}
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	/* a field/op pair that is not caught here will simply fall through
366062306a36Sopenharmony_ci	   without a match */
366162306a36Sopenharmony_ci	switch (field) {
366262306a36Sopenharmony_ci	case AUDIT_SUBJ_USER:
366362306a36Sopenharmony_ci	case AUDIT_OBJ_USER:
366462306a36Sopenharmony_ci		switch (op) {
366562306a36Sopenharmony_ci		case Audit_equal:
366662306a36Sopenharmony_ci			match = (ctxt->user == rule->au_ctxt.user);
366762306a36Sopenharmony_ci			break;
366862306a36Sopenharmony_ci		case Audit_not_equal:
366962306a36Sopenharmony_ci			match = (ctxt->user != rule->au_ctxt.user);
367062306a36Sopenharmony_ci			break;
367162306a36Sopenharmony_ci		}
367262306a36Sopenharmony_ci		break;
367362306a36Sopenharmony_ci	case AUDIT_SUBJ_ROLE:
367462306a36Sopenharmony_ci	case AUDIT_OBJ_ROLE:
367562306a36Sopenharmony_ci		switch (op) {
367662306a36Sopenharmony_ci		case Audit_equal:
367762306a36Sopenharmony_ci			match = (ctxt->role == rule->au_ctxt.role);
367862306a36Sopenharmony_ci			break;
367962306a36Sopenharmony_ci		case Audit_not_equal:
368062306a36Sopenharmony_ci			match = (ctxt->role != rule->au_ctxt.role);
368162306a36Sopenharmony_ci			break;
368262306a36Sopenharmony_ci		}
368362306a36Sopenharmony_ci		break;
368462306a36Sopenharmony_ci	case AUDIT_SUBJ_TYPE:
368562306a36Sopenharmony_ci	case AUDIT_OBJ_TYPE:
368662306a36Sopenharmony_ci		switch (op) {
368762306a36Sopenharmony_ci		case Audit_equal:
368862306a36Sopenharmony_ci			match = (ctxt->type == rule->au_ctxt.type);
368962306a36Sopenharmony_ci			break;
369062306a36Sopenharmony_ci		case Audit_not_equal:
369162306a36Sopenharmony_ci			match = (ctxt->type != rule->au_ctxt.type);
369262306a36Sopenharmony_ci			break;
369362306a36Sopenharmony_ci		}
369462306a36Sopenharmony_ci		break;
369562306a36Sopenharmony_ci	case AUDIT_SUBJ_SEN:
369662306a36Sopenharmony_ci	case AUDIT_SUBJ_CLR:
369762306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_LOW:
369862306a36Sopenharmony_ci	case AUDIT_OBJ_LEV_HIGH:
369962306a36Sopenharmony_ci		level = ((field == AUDIT_SUBJ_SEN ||
370062306a36Sopenharmony_ci			  field == AUDIT_OBJ_LEV_LOW) ?
370162306a36Sopenharmony_ci			 &ctxt->range.level[0] : &ctxt->range.level[1]);
370262306a36Sopenharmony_ci		switch (op) {
370362306a36Sopenharmony_ci		case Audit_equal:
370462306a36Sopenharmony_ci			match = mls_level_eq(&rule->au_ctxt.range.level[0],
370562306a36Sopenharmony_ci					     level);
370662306a36Sopenharmony_ci			break;
370762306a36Sopenharmony_ci		case Audit_not_equal:
370862306a36Sopenharmony_ci			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
370962306a36Sopenharmony_ci					      level);
371062306a36Sopenharmony_ci			break;
371162306a36Sopenharmony_ci		case Audit_lt:
371262306a36Sopenharmony_ci			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
371362306a36Sopenharmony_ci					       level) &&
371462306a36Sopenharmony_ci				 !mls_level_eq(&rule->au_ctxt.range.level[0],
371562306a36Sopenharmony_ci					       level));
371662306a36Sopenharmony_ci			break;
371762306a36Sopenharmony_ci		case Audit_le:
371862306a36Sopenharmony_ci			match = mls_level_dom(&rule->au_ctxt.range.level[0],
371962306a36Sopenharmony_ci					      level);
372062306a36Sopenharmony_ci			break;
372162306a36Sopenharmony_ci		case Audit_gt:
372262306a36Sopenharmony_ci			match = (mls_level_dom(level,
372362306a36Sopenharmony_ci					      &rule->au_ctxt.range.level[0]) &&
372462306a36Sopenharmony_ci				 !mls_level_eq(level,
372562306a36Sopenharmony_ci					       &rule->au_ctxt.range.level[0]));
372662306a36Sopenharmony_ci			break;
372762306a36Sopenharmony_ci		case Audit_ge:
372862306a36Sopenharmony_ci			match = mls_level_dom(level,
372962306a36Sopenharmony_ci					      &rule->au_ctxt.range.level[0]);
373062306a36Sopenharmony_ci			break;
373162306a36Sopenharmony_ci		}
373262306a36Sopenharmony_ci	}
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ciout:
373562306a36Sopenharmony_ci	rcu_read_unlock();
373662306a36Sopenharmony_ci	return match;
373762306a36Sopenharmony_ci}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_cistatic int aurule_avc_callback(u32 event)
374062306a36Sopenharmony_ci{
374162306a36Sopenharmony_ci	if (event == AVC_CALLBACK_RESET)
374262306a36Sopenharmony_ci		return audit_update_lsm_rules();
374362306a36Sopenharmony_ci	return 0;
374462306a36Sopenharmony_ci}
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_cistatic int __init aurule_init(void)
374762306a36Sopenharmony_ci{
374862306a36Sopenharmony_ci	int err;
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
375162306a36Sopenharmony_ci	if (err)
375262306a36Sopenharmony_ci		panic("avc_add_callback() failed, error %d\n", err);
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	return err;
375562306a36Sopenharmony_ci}
375662306a36Sopenharmony_ci__initcall(aurule_init);
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci#ifdef CONFIG_NETLABEL
375962306a36Sopenharmony_ci/**
376062306a36Sopenharmony_ci * security_netlbl_cache_add - Add an entry to the NetLabel cache
376162306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes
376262306a36Sopenharmony_ci * @sid: the SELinux SID
376362306a36Sopenharmony_ci *
376462306a36Sopenharmony_ci * Description:
376562306a36Sopenharmony_ci * Attempt to cache the context in @ctx, which was derived from the packet in
376662306a36Sopenharmony_ci * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
376762306a36Sopenharmony_ci * already been initialized.
376862306a36Sopenharmony_ci *
376962306a36Sopenharmony_ci */
377062306a36Sopenharmony_cistatic void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
377162306a36Sopenharmony_ci				      u32 sid)
377262306a36Sopenharmony_ci{
377362306a36Sopenharmony_ci	u32 *sid_cache;
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_ci	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
377662306a36Sopenharmony_ci	if (sid_cache == NULL)
377762306a36Sopenharmony_ci		return;
377862306a36Sopenharmony_ci	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
377962306a36Sopenharmony_ci	if (secattr->cache == NULL) {
378062306a36Sopenharmony_ci		kfree(sid_cache);
378162306a36Sopenharmony_ci		return;
378262306a36Sopenharmony_ci	}
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci	*sid_cache = sid;
378562306a36Sopenharmony_ci	secattr->cache->free = kfree;
378662306a36Sopenharmony_ci	secattr->cache->data = sid_cache;
378762306a36Sopenharmony_ci	secattr->flags |= NETLBL_SECATTR_CACHE;
378862306a36Sopenharmony_ci}
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci/**
379162306a36Sopenharmony_ci * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
379262306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes
379362306a36Sopenharmony_ci * @sid: the SELinux SID
379462306a36Sopenharmony_ci *
379562306a36Sopenharmony_ci * Description:
379662306a36Sopenharmony_ci * Convert the given NetLabel security attributes in @secattr into a
379762306a36Sopenharmony_ci * SELinux SID.  If the @secattr field does not contain a full SELinux
379862306a36Sopenharmony_ci * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
379962306a36Sopenharmony_ci * 'cache' field of @secattr is set and the CACHE flag is set; this is to
380062306a36Sopenharmony_ci * allow the @secattr to be used by NetLabel to cache the secattr to SID
380162306a36Sopenharmony_ci * conversion for future lookups.  Returns zero on success, negative values on
380262306a36Sopenharmony_ci * failure.
380362306a36Sopenharmony_ci *
380462306a36Sopenharmony_ci */
380562306a36Sopenharmony_ciint security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
380662306a36Sopenharmony_ci				   u32 *sid)
380762306a36Sopenharmony_ci{
380862306a36Sopenharmony_ci	struct selinux_policy *policy;
380962306a36Sopenharmony_ci	struct policydb *policydb;
381062306a36Sopenharmony_ci	struct sidtab *sidtab;
381162306a36Sopenharmony_ci	int rc;
381262306a36Sopenharmony_ci	struct context *ctx;
381362306a36Sopenharmony_ci	struct context ctx_new;
381462306a36Sopenharmony_ci
381562306a36Sopenharmony_ci	if (!selinux_initialized()) {
381662306a36Sopenharmony_ci		*sid = SECSID_NULL;
381762306a36Sopenharmony_ci		return 0;
381862306a36Sopenharmony_ci	}
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ciretry:
382162306a36Sopenharmony_ci	rc = 0;
382262306a36Sopenharmony_ci	rcu_read_lock();
382362306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
382462306a36Sopenharmony_ci	policydb = &policy->policydb;
382562306a36Sopenharmony_ci	sidtab = policy->sidtab;
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	if (secattr->flags & NETLBL_SECATTR_CACHE)
382862306a36Sopenharmony_ci		*sid = *(u32 *)secattr->cache->data;
382962306a36Sopenharmony_ci	else if (secattr->flags & NETLBL_SECATTR_SECID)
383062306a36Sopenharmony_ci		*sid = secattr->attr.secid;
383162306a36Sopenharmony_ci	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
383262306a36Sopenharmony_ci		rc = -EIDRM;
383362306a36Sopenharmony_ci		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
383462306a36Sopenharmony_ci		if (ctx == NULL)
383562306a36Sopenharmony_ci			goto out;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci		context_init(&ctx_new);
383862306a36Sopenharmony_ci		ctx_new.user = ctx->user;
383962306a36Sopenharmony_ci		ctx_new.role = ctx->role;
384062306a36Sopenharmony_ci		ctx_new.type = ctx->type;
384162306a36Sopenharmony_ci		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
384262306a36Sopenharmony_ci		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
384362306a36Sopenharmony_ci			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
384462306a36Sopenharmony_ci			if (rc)
384562306a36Sopenharmony_ci				goto out;
384662306a36Sopenharmony_ci		}
384762306a36Sopenharmony_ci		rc = -EIDRM;
384862306a36Sopenharmony_ci		if (!mls_context_isvalid(policydb, &ctx_new)) {
384962306a36Sopenharmony_ci			ebitmap_destroy(&ctx_new.range.level[0].cat);
385062306a36Sopenharmony_ci			goto out;
385162306a36Sopenharmony_ci		}
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
385462306a36Sopenharmony_ci		ebitmap_destroy(&ctx_new.range.level[0].cat);
385562306a36Sopenharmony_ci		if (rc == -ESTALE) {
385662306a36Sopenharmony_ci			rcu_read_unlock();
385762306a36Sopenharmony_ci			goto retry;
385862306a36Sopenharmony_ci		}
385962306a36Sopenharmony_ci		if (rc)
386062306a36Sopenharmony_ci			goto out;
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci		security_netlbl_cache_add(secattr, *sid);
386362306a36Sopenharmony_ci	} else
386462306a36Sopenharmony_ci		*sid = SECSID_NULL;
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ciout:
386762306a36Sopenharmony_ci	rcu_read_unlock();
386862306a36Sopenharmony_ci	return rc;
386962306a36Sopenharmony_ci}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci/**
387262306a36Sopenharmony_ci * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
387362306a36Sopenharmony_ci * @sid: the SELinux SID
387462306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes
387562306a36Sopenharmony_ci *
387662306a36Sopenharmony_ci * Description:
387762306a36Sopenharmony_ci * Convert the given SELinux SID in @sid into a NetLabel security attribute.
387862306a36Sopenharmony_ci * Returns zero on success, negative values on failure.
387962306a36Sopenharmony_ci *
388062306a36Sopenharmony_ci */
388162306a36Sopenharmony_ciint security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
388262306a36Sopenharmony_ci{
388362306a36Sopenharmony_ci	struct selinux_policy *policy;
388462306a36Sopenharmony_ci	struct policydb *policydb;
388562306a36Sopenharmony_ci	int rc;
388662306a36Sopenharmony_ci	struct context *ctx;
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ci	if (!selinux_initialized())
388962306a36Sopenharmony_ci		return 0;
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci	rcu_read_lock();
389262306a36Sopenharmony_ci	policy = rcu_dereference(selinux_state.policy);
389362306a36Sopenharmony_ci	policydb = &policy->policydb;
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	rc = -ENOENT;
389662306a36Sopenharmony_ci	ctx = sidtab_search(policy->sidtab, sid);
389762306a36Sopenharmony_ci	if (ctx == NULL)
389862306a36Sopenharmony_ci		goto out;
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	rc = -ENOMEM;
390162306a36Sopenharmony_ci	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
390262306a36Sopenharmony_ci				  GFP_ATOMIC);
390362306a36Sopenharmony_ci	if (secattr->domain == NULL)
390462306a36Sopenharmony_ci		goto out;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	secattr->attr.secid = sid;
390762306a36Sopenharmony_ci	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
390862306a36Sopenharmony_ci	mls_export_netlbl_lvl(policydb, ctx, secattr);
390962306a36Sopenharmony_ci	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
391062306a36Sopenharmony_ciout:
391162306a36Sopenharmony_ci	rcu_read_unlock();
391262306a36Sopenharmony_ci	return rc;
391362306a36Sopenharmony_ci}
391462306a36Sopenharmony_ci#endif /* CONFIG_NETLABEL */
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_ci/**
391762306a36Sopenharmony_ci * __security_read_policy - read the policy.
391862306a36Sopenharmony_ci * @policy: SELinux policy
391962306a36Sopenharmony_ci * @data: binary policy data
392062306a36Sopenharmony_ci * @len: length of data in bytes
392162306a36Sopenharmony_ci *
392262306a36Sopenharmony_ci */
392362306a36Sopenharmony_cistatic int __security_read_policy(struct selinux_policy *policy,
392462306a36Sopenharmony_ci				  void *data, size_t *len)
392562306a36Sopenharmony_ci{
392662306a36Sopenharmony_ci	int rc;
392762306a36Sopenharmony_ci	struct policy_file fp;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	fp.data = data;
393062306a36Sopenharmony_ci	fp.len = *len;
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci	rc = policydb_write(&policy->policydb, &fp);
393362306a36Sopenharmony_ci	if (rc)
393462306a36Sopenharmony_ci		return rc;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	*len = (unsigned long)fp.data - (unsigned long)data;
393762306a36Sopenharmony_ci	return 0;
393862306a36Sopenharmony_ci}
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci/**
394162306a36Sopenharmony_ci * security_read_policy - read the policy.
394262306a36Sopenharmony_ci * @data: binary policy data
394362306a36Sopenharmony_ci * @len: length of data in bytes
394462306a36Sopenharmony_ci *
394562306a36Sopenharmony_ci */
394662306a36Sopenharmony_ciint security_read_policy(void **data, size_t *len)
394762306a36Sopenharmony_ci{
394862306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
394962306a36Sopenharmony_ci	struct selinux_policy *policy;
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	policy = rcu_dereference_protected(
395262306a36Sopenharmony_ci			state->policy, lockdep_is_held(&state->policy_mutex));
395362306a36Sopenharmony_ci	if (!policy)
395462306a36Sopenharmony_ci		return -EINVAL;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	*len = policy->policydb.len;
395762306a36Sopenharmony_ci	*data = vmalloc_user(*len);
395862306a36Sopenharmony_ci	if (!*data)
395962306a36Sopenharmony_ci		return -ENOMEM;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	return __security_read_policy(policy, *data, len);
396262306a36Sopenharmony_ci}
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci/**
396562306a36Sopenharmony_ci * security_read_state_kernel - read the policy.
396662306a36Sopenharmony_ci * @data: binary policy data
396762306a36Sopenharmony_ci * @len: length of data in bytes
396862306a36Sopenharmony_ci *
396962306a36Sopenharmony_ci * Allocates kernel memory for reading SELinux policy.
397062306a36Sopenharmony_ci * This function is for internal use only and should not
397162306a36Sopenharmony_ci * be used for returning data to user space.
397262306a36Sopenharmony_ci *
397362306a36Sopenharmony_ci * This function must be called with policy_mutex held.
397462306a36Sopenharmony_ci */
397562306a36Sopenharmony_ciint security_read_state_kernel(void **data, size_t *len)
397662306a36Sopenharmony_ci{
397762306a36Sopenharmony_ci	int err;
397862306a36Sopenharmony_ci	struct selinux_state *state = &selinux_state;
397962306a36Sopenharmony_ci	struct selinux_policy *policy;
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	policy = rcu_dereference_protected(
398262306a36Sopenharmony_ci			state->policy, lockdep_is_held(&state->policy_mutex));
398362306a36Sopenharmony_ci	if (!policy)
398462306a36Sopenharmony_ci		return -EINVAL;
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	*len = policy->policydb.len;
398762306a36Sopenharmony_ci	*data = vmalloc(*len);
398862306a36Sopenharmony_ci	if (!*data)
398962306a36Sopenharmony_ci		return -ENOMEM;
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci	err = __security_read_policy(policy, *data, len);
399262306a36Sopenharmony_ci	if (err) {
399362306a36Sopenharmony_ci		vfree(*data);
399462306a36Sopenharmony_ci		*data = NULL;
399562306a36Sopenharmony_ci		*len = 0;
399662306a36Sopenharmony_ci	}
399762306a36Sopenharmony_ci	return err;
399862306a36Sopenharmony_ci}
3999