xref: /openbmc/linux/security/selinux/ss/services.c (revision f07ea1d4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Implementation of the security services.
31da177e4SLinus Torvalds  *
47efbb60bSStephen Smalley  * Authors : Stephen Smalley, <sds@tycho.nsa.gov>
51da177e4SLinus Torvalds  *	     James Morris <jmorris@redhat.com>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Support for enhanced MLS infrastructure.
10376bd9cbSDarrel Goeddel  *	Support for context based audit filters.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *	Added conditional policy language extensions
151da177e4SLinus Torvalds  *
1682c21bfaSPaul Moore  * Updated: Hewlett-Packard <paul@paul-moore.com>
177420ed23SVenkat Yekkirala  *
187420ed23SVenkat Yekkirala  *      Added support for NetLabel
193bb56b25SPaul Moore  *      Added support for the policy capability bitmap
207420ed23SVenkat Yekkirala  *
21b94c7e67SChad Sellers  * Updated: Chad Sellers <csellers@tresys.com>
22b94c7e67SChad Sellers  *
23b94c7e67SChad Sellers  *  Added validation of kernel classes and permissions
24b94c7e67SChad Sellers  *
2544c2d9bdSKaiGai Kohei  * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
2644c2d9bdSKaiGai Kohei  *
2744c2d9bdSKaiGai Kohei  *  Added support for bounds domain and audit messaged on masked permissions
2844c2d9bdSKaiGai Kohei  *
290719aaf5SGuido Trentalancia  * Updated: Guido Trentalancia <guido@trentalancia.com>
300719aaf5SGuido Trentalancia  *
310719aaf5SGuido Trentalancia  *  Added support for runtime switching of the policy type
320719aaf5SGuido Trentalancia  *
3344c2d9bdSKaiGai Kohei  * Copyright (C) 2008, 2009 NEC Corporation
343bb56b25SPaul Moore  * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
35376bd9cbSDarrel Goeddel  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
36b94c7e67SChad Sellers  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
371da177e4SLinus Torvalds  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
381da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or modify
391da177e4SLinus Torvalds  *	it under the terms of the GNU General Public License as published by
401da177e4SLinus Torvalds  *	the Free Software Foundation, version 2.
411da177e4SLinus Torvalds  */
421da177e4SLinus Torvalds #include <linux/kernel.h>
431da177e4SLinus Torvalds #include <linux/slab.h>
441da177e4SLinus Torvalds #include <linux/string.h>
451da177e4SLinus Torvalds #include <linux/spinlock.h>
469f2ad665SPaul Moore #include <linux/rcupdate.h>
471da177e4SLinus Torvalds #include <linux/errno.h>
481da177e4SLinus Torvalds #include <linux/in.h>
491da177e4SLinus Torvalds #include <linux/sched.h>
501da177e4SLinus Torvalds #include <linux/audit.h>
51bb003079SIngo Molnar #include <linux/mutex.h>
52f0d3d989SStephen Rothwell #include <linux/vmalloc.h>
537420ed23SVenkat Yekkirala #include <net/netlabel.h>
54bb003079SIngo Molnar 
551da177e4SLinus Torvalds #include "flask.h"
561da177e4SLinus Torvalds #include "avc.h"
571da177e4SLinus Torvalds #include "avc_ss.h"
581da177e4SLinus Torvalds #include "security.h"
591da177e4SLinus Torvalds #include "context.h"
601da177e4SLinus Torvalds #include "policydb.h"
611da177e4SLinus Torvalds #include "sidtab.h"
621da177e4SLinus Torvalds #include "services.h"
631da177e4SLinus Torvalds #include "conditional.h"
641da177e4SLinus Torvalds #include "mls.h"
657420ed23SVenkat Yekkirala #include "objsec.h"
66c60475bfSPaul Moore #include "netlabel.h"
673de4bab5SPaul Moore #include "xfrm.h"
6802752760SPaul Moore #include "ebitmap.h"
699d57a7f9SAhmed S. Darwish #include "audit.h"
701da177e4SLinus Torvalds 
714dc2fce3SStephen Smalley /* Policy capability names */
7289f5bebcSAlexey Dobriyan const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
734dc2fce3SStephen Smalley 	"network_peer_controls",
744dc2fce3SStephen Smalley 	"open_perms",
754dc2fce3SStephen Smalley 	"extended_socket_class",
764dc2fce3SStephen Smalley 	"always_check_network",
77af63f419SStephen Smalley 	"cgroup_seclabel",
78af63f419SStephen Smalley 	"nnp_nosuid_transition"
794dc2fce3SStephen Smalley };
804dc2fce3SStephen Smalley 
81aa8e712cSStephen Smalley static struct selinux_ss selinux_ss;
823bb56b25SPaul Moore 
83aa8e712cSStephen Smalley void selinux_ss_init(struct selinux_ss **ss)
84aa8e712cSStephen Smalley {
85aa8e712cSStephen Smalley 	rwlock_init(&selinux_ss.policy_rwlock);
86aa8e712cSStephen Smalley 	mutex_init(&selinux_ss.status_lock);
87aa8e712cSStephen Smalley 	*ss = &selinux_ss;
88aa8e712cSStephen Smalley }
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds /* Forward declaration. */
91aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *policydb,
92aa8e712cSStephen Smalley 				    struct context *context,
93aa8e712cSStephen Smalley 				    char **scontext,
941da177e4SLinus Torvalds 				    u32 *scontext_len);
951da177e4SLinus Torvalds 
96aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
97aa8e712cSStephen Smalley 				      struct context *scontext,
98d9250deaSKaiGai Kohei 				      struct context *tcontext,
99d9250deaSKaiGai Kohei 				      u16 tclass,
100fa1aa143SJeff Vander Stoep 				      struct av_decision *avd,
101fa1aa143SJeff Vander Stoep 				      struct extended_perms *xperms);
102c6d3aaa4SStephen Smalley 
103c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol,
104c6d3aaa4SStephen Smalley 			       struct security_class_mapping *map,
105aa8e712cSStephen Smalley 			       struct selinux_map *out_map)
106c6d3aaa4SStephen Smalley {
107c6d3aaa4SStephen Smalley 	u16 i, j;
108c6d3aaa4SStephen Smalley 	unsigned k;
109c6d3aaa4SStephen Smalley 	bool print_unknown_handle = false;
110c6d3aaa4SStephen Smalley 
111c6d3aaa4SStephen Smalley 	/* Find number of classes in the input mapping */
112c6d3aaa4SStephen Smalley 	if (!map)
113c6d3aaa4SStephen Smalley 		return -EINVAL;
114c6d3aaa4SStephen Smalley 	i = 0;
115c6d3aaa4SStephen Smalley 	while (map[i].name)
116c6d3aaa4SStephen Smalley 		i++;
117c6d3aaa4SStephen Smalley 
118c6d3aaa4SStephen Smalley 	/* Allocate space for the class records, plus one for class zero */
119aa8e712cSStephen Smalley 	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
120aa8e712cSStephen Smalley 	if (!out_map->mapping)
121c6d3aaa4SStephen Smalley 		return -ENOMEM;
122c6d3aaa4SStephen Smalley 
123c6d3aaa4SStephen Smalley 	/* Store the raw class and permission values */
124c6d3aaa4SStephen Smalley 	j = 0;
125c6d3aaa4SStephen Smalley 	while (map[j].name) {
126c6d3aaa4SStephen Smalley 		struct security_class_mapping *p_in = map + (j++);
127aa8e712cSStephen Smalley 		struct selinux_mapping *p_out = out_map->mapping + j;
128c6d3aaa4SStephen Smalley 
129c6d3aaa4SStephen Smalley 		/* An empty class string skips ahead */
130c6d3aaa4SStephen Smalley 		if (!strcmp(p_in->name, "")) {
131c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
132c6d3aaa4SStephen Smalley 			continue;
133c6d3aaa4SStephen Smalley 		}
134c6d3aaa4SStephen Smalley 
135c6d3aaa4SStephen Smalley 		p_out->value = string_to_security_class(pol, p_in->name);
136c6d3aaa4SStephen Smalley 		if (!p_out->value) {
137b54c85c1Speter enderborg 			pr_info("SELinux:  Class %s not defined in policy.\n",
138c6d3aaa4SStephen Smalley 			       p_in->name);
139c6d3aaa4SStephen Smalley 			if (pol->reject_unknown)
140c6d3aaa4SStephen Smalley 				goto err;
141c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
142c6d3aaa4SStephen Smalley 			print_unknown_handle = true;
143c6d3aaa4SStephen Smalley 			continue;
144c6d3aaa4SStephen Smalley 		}
145c6d3aaa4SStephen Smalley 
146c6d3aaa4SStephen Smalley 		k = 0;
147342e9157SMatthias Kaehlcke 		while (p_in->perms[k]) {
148c6d3aaa4SStephen Smalley 			/* An empty permission string skips ahead */
149c6d3aaa4SStephen Smalley 			if (!*p_in->perms[k]) {
150c6d3aaa4SStephen Smalley 				k++;
151c6d3aaa4SStephen Smalley 				continue;
152c6d3aaa4SStephen Smalley 			}
153c6d3aaa4SStephen Smalley 			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
154c6d3aaa4SStephen Smalley 							    p_in->perms[k]);
155c6d3aaa4SStephen Smalley 			if (!p_out->perms[k]) {
156b54c85c1Speter enderborg 				pr_info("SELinux:  Permission %s in class %s not defined in policy.\n",
157c6d3aaa4SStephen Smalley 				       p_in->perms[k], p_in->name);
158c6d3aaa4SStephen Smalley 				if (pol->reject_unknown)
159c6d3aaa4SStephen Smalley 					goto err;
160c6d3aaa4SStephen Smalley 				print_unknown_handle = true;
161c6d3aaa4SStephen Smalley 			}
162c6d3aaa4SStephen Smalley 
163c6d3aaa4SStephen Smalley 			k++;
164c6d3aaa4SStephen Smalley 		}
165c6d3aaa4SStephen Smalley 		p_out->num_perms = k;
166c6d3aaa4SStephen Smalley 	}
167c6d3aaa4SStephen Smalley 
168c6d3aaa4SStephen Smalley 	if (print_unknown_handle)
169b54c85c1Speter enderborg 		pr_info("SELinux: the above unknown classes and permissions will be %s\n",
170c6d3aaa4SStephen Smalley 		       pol->allow_unknown ? "allowed" : "denied");
171c6d3aaa4SStephen Smalley 
172aa8e712cSStephen Smalley 	out_map->size = i;
173c6d3aaa4SStephen Smalley 	return 0;
174c6d3aaa4SStephen Smalley err:
175aa8e712cSStephen Smalley 	kfree(out_map->mapping);
176aa8e712cSStephen Smalley 	out_map->mapping = NULL;
177c6d3aaa4SStephen Smalley 	return -EINVAL;
178c6d3aaa4SStephen Smalley }
179c6d3aaa4SStephen Smalley 
180c6d3aaa4SStephen Smalley /*
181c6d3aaa4SStephen Smalley  * Get real, policy values from mapped values
182c6d3aaa4SStephen Smalley  */
183c6d3aaa4SStephen Smalley 
184aa8e712cSStephen Smalley static u16 unmap_class(struct selinux_map *map, u16 tclass)
185c6d3aaa4SStephen Smalley {
186aa8e712cSStephen Smalley 	if (tclass < map->size)
187aa8e712cSStephen Smalley 		return map->mapping[tclass].value;
188c6d3aaa4SStephen Smalley 
189c6d3aaa4SStephen Smalley 	return tclass;
190c6d3aaa4SStephen Smalley }
191c6d3aaa4SStephen Smalley 
1926f5317e7SHarry Ciao /*
1936f5317e7SHarry Ciao  * Get kernel value for class from its policy value
1946f5317e7SHarry Ciao  */
195aa8e712cSStephen Smalley static u16 map_class(struct selinux_map *map, u16 pol_value)
1966f5317e7SHarry Ciao {
1976f5317e7SHarry Ciao 	u16 i;
1986f5317e7SHarry Ciao 
199aa8e712cSStephen Smalley 	for (i = 1; i < map->size; i++) {
200aa8e712cSStephen Smalley 		if (map->mapping[i].value == pol_value)
2016f5317e7SHarry Ciao 			return i;
2026f5317e7SHarry Ciao 	}
2036f5317e7SHarry Ciao 
20485cd6da5SStephen Smalley 	return SECCLASS_NULL;
2056f5317e7SHarry Ciao }
2066f5317e7SHarry Ciao 
207aa8e712cSStephen Smalley static void map_decision(struct selinux_map *map,
208aa8e712cSStephen Smalley 			 u16 tclass, struct av_decision *avd,
209c6d3aaa4SStephen Smalley 			 int allow_unknown)
210c6d3aaa4SStephen Smalley {
211aa8e712cSStephen Smalley 	if (tclass < map->size) {
212aa8e712cSStephen Smalley 		struct selinux_mapping *mapping = &map->mapping[tclass];
213aa8e712cSStephen Smalley 		unsigned int i, n = mapping->num_perms;
214c6d3aaa4SStephen Smalley 		u32 result;
215c6d3aaa4SStephen Smalley 
216c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
217aa8e712cSStephen Smalley 			if (avd->allowed & mapping->perms[i])
218c6d3aaa4SStephen Smalley 				result |= 1<<i;
219aa8e712cSStephen Smalley 			if (allow_unknown && !mapping->perms[i])
220c6d3aaa4SStephen Smalley 				result |= 1<<i;
221c6d3aaa4SStephen Smalley 		}
222c6d3aaa4SStephen Smalley 		avd->allowed = result;
223c6d3aaa4SStephen Smalley 
224c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++)
225aa8e712cSStephen Smalley 			if (avd->auditallow & mapping->perms[i])
226c6d3aaa4SStephen Smalley 				result |= 1<<i;
227c6d3aaa4SStephen Smalley 		avd->auditallow = result;
228c6d3aaa4SStephen Smalley 
229c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
230aa8e712cSStephen Smalley 			if (avd->auditdeny & mapping->perms[i])
231c6d3aaa4SStephen Smalley 				result |= 1<<i;
232aa8e712cSStephen Smalley 			if (!allow_unknown && !mapping->perms[i])
233c6d3aaa4SStephen Smalley 				result |= 1<<i;
234c6d3aaa4SStephen Smalley 		}
2350bce9527SEric Paris 		/*
2360bce9527SEric Paris 		 * In case the kernel has a bug and requests a permission
2370bce9527SEric Paris 		 * between num_perms and the maximum permission number, we
2380bce9527SEric Paris 		 * should audit that denial
2390bce9527SEric Paris 		 */
2400bce9527SEric Paris 		for (; i < (sizeof(u32)*8); i++)
2410bce9527SEric Paris 			result |= 1<<i;
242c6d3aaa4SStephen Smalley 		avd->auditdeny = result;
243c6d3aaa4SStephen Smalley 	}
244c6d3aaa4SStephen Smalley }
245c6d3aaa4SStephen Smalley 
246aa8e712cSStephen Smalley int security_mls_enabled(struct selinux_state *state)
2470719aaf5SGuido Trentalancia {
248aa8e712cSStephen Smalley 	struct policydb *p = &state->ss->policydb;
249aa8e712cSStephen Smalley 
250aa8e712cSStephen Smalley 	return p->mls_enabled;
2510719aaf5SGuido Trentalancia }
252c6d3aaa4SStephen Smalley 
2531da177e4SLinus Torvalds /*
2541da177e4SLinus Torvalds  * Return the boolean value of a constraint expression
2551da177e4SLinus Torvalds  * when it is applied to the specified source and target
2561da177e4SLinus Torvalds  * security contexts.
2571da177e4SLinus Torvalds  *
2581da177e4SLinus Torvalds  * xcontext is a special beast...  It is used by the validatetrans rules
2591da177e4SLinus Torvalds  * only.  For these rules, scontext is the context before the transition,
2601da177e4SLinus Torvalds  * tcontext is the context after the transition, and xcontext is the context
2611da177e4SLinus Torvalds  * of the process performing the transition.  All other callers of
2621da177e4SLinus Torvalds  * constraint_expr_eval should pass in NULL for xcontext.
2631da177e4SLinus Torvalds  */
264aa8e712cSStephen Smalley static int constraint_expr_eval(struct policydb *policydb,
265aa8e712cSStephen Smalley 				struct context *scontext,
2661da177e4SLinus Torvalds 				struct context *tcontext,
2671da177e4SLinus Torvalds 				struct context *xcontext,
2681da177e4SLinus Torvalds 				struct constraint_expr *cexpr)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds 	u32 val1, val2;
2711da177e4SLinus Torvalds 	struct context *c;
2721da177e4SLinus Torvalds 	struct role_datum *r1, *r2;
2731da177e4SLinus Torvalds 	struct mls_level *l1, *l2;
2741da177e4SLinus Torvalds 	struct constraint_expr *e;
2751da177e4SLinus Torvalds 	int s[CEXPR_MAXDEPTH];
2761da177e4SLinus Torvalds 	int sp = -1;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	for (e = cexpr; e; e = e->next) {
2791da177e4SLinus Torvalds 		switch (e->expr_type) {
2801da177e4SLinus Torvalds 		case CEXPR_NOT:
2811da177e4SLinus Torvalds 			BUG_ON(sp < 0);
2821da177e4SLinus Torvalds 			s[sp] = !s[sp];
2831da177e4SLinus Torvalds 			break;
2841da177e4SLinus Torvalds 		case CEXPR_AND:
2851da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2861da177e4SLinus Torvalds 			sp--;
2871da177e4SLinus Torvalds 			s[sp] &= s[sp + 1];
2881da177e4SLinus Torvalds 			break;
2891da177e4SLinus Torvalds 		case CEXPR_OR:
2901da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2911da177e4SLinus Torvalds 			sp--;
2921da177e4SLinus Torvalds 			s[sp] |= s[sp + 1];
2931da177e4SLinus Torvalds 			break;
2941da177e4SLinus Torvalds 		case CEXPR_ATTR:
2951da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH - 1))
2961da177e4SLinus Torvalds 				return 0;
2971da177e4SLinus Torvalds 			switch (e->attr) {
2981da177e4SLinus Torvalds 			case CEXPR_USER:
2991da177e4SLinus Torvalds 				val1 = scontext->user;
3001da177e4SLinus Torvalds 				val2 = tcontext->user;
3011da177e4SLinus Torvalds 				break;
3021da177e4SLinus Torvalds 			case CEXPR_TYPE:
3031da177e4SLinus Torvalds 				val1 = scontext->type;
3041da177e4SLinus Torvalds 				val2 = tcontext->type;
3051da177e4SLinus Torvalds 				break;
3061da177e4SLinus Torvalds 			case CEXPR_ROLE:
3071da177e4SLinus Torvalds 				val1 = scontext->role;
3081da177e4SLinus Torvalds 				val2 = tcontext->role;
309aa8e712cSStephen Smalley 				r1 = policydb->role_val_to_struct[val1 - 1];
310aa8e712cSStephen Smalley 				r2 = policydb->role_val_to_struct[val2 - 1];
3111da177e4SLinus Torvalds 				switch (e->op) {
3121da177e4SLinus Torvalds 				case CEXPR_DOM:
3131da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r1->dominates,
3141da177e4SLinus Torvalds 								  val2 - 1);
3151da177e4SLinus Torvalds 					continue;
3161da177e4SLinus Torvalds 				case CEXPR_DOMBY:
3171da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r2->dominates,
3181da177e4SLinus Torvalds 								  val1 - 1);
3191da177e4SLinus Torvalds 					continue;
3201da177e4SLinus Torvalds 				case CEXPR_INCOMP:
3211da177e4SLinus Torvalds 					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
3221da177e4SLinus Torvalds 								    val2 - 1) &&
3231da177e4SLinus Torvalds 						   !ebitmap_get_bit(&r2->dominates,
3241da177e4SLinus Torvalds 								    val1 - 1));
3251da177e4SLinus Torvalds 					continue;
3261da177e4SLinus Torvalds 				default:
3271da177e4SLinus Torvalds 					break;
3281da177e4SLinus Torvalds 				}
3291da177e4SLinus Torvalds 				break;
3301da177e4SLinus Torvalds 			case CEXPR_L1L2:
3311da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3321da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3331da177e4SLinus Torvalds 				goto mls_ops;
3341da177e4SLinus Torvalds 			case CEXPR_L1H2:
3351da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3361da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3371da177e4SLinus Torvalds 				goto mls_ops;
3381da177e4SLinus Torvalds 			case CEXPR_H1L2:
3391da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3401da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3411da177e4SLinus Torvalds 				goto mls_ops;
3421da177e4SLinus Torvalds 			case CEXPR_H1H2:
3431da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3441da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3451da177e4SLinus Torvalds 				goto mls_ops;
3461da177e4SLinus Torvalds 			case CEXPR_L1H1:
3471da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3481da177e4SLinus Torvalds 				l2 = &(scontext->range.level[1]);
3491da177e4SLinus Torvalds 				goto mls_ops;
3501da177e4SLinus Torvalds 			case CEXPR_L2H2:
3511da177e4SLinus Torvalds 				l1 = &(tcontext->range.level[0]);
3521da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3531da177e4SLinus Torvalds 				goto mls_ops;
3541da177e4SLinus Torvalds mls_ops:
3551da177e4SLinus Torvalds 			switch (e->op) {
3561da177e4SLinus Torvalds 			case CEXPR_EQ:
3571da177e4SLinus Torvalds 				s[++sp] = mls_level_eq(l1, l2);
3581da177e4SLinus Torvalds 				continue;
3591da177e4SLinus Torvalds 			case CEXPR_NEQ:
3601da177e4SLinus Torvalds 				s[++sp] = !mls_level_eq(l1, l2);
3611da177e4SLinus Torvalds 				continue;
3621da177e4SLinus Torvalds 			case CEXPR_DOM:
3631da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l1, l2);
3641da177e4SLinus Torvalds 				continue;
3651da177e4SLinus Torvalds 			case CEXPR_DOMBY:
3661da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l2, l1);
3671da177e4SLinus Torvalds 				continue;
3681da177e4SLinus Torvalds 			case CEXPR_INCOMP:
3691da177e4SLinus Torvalds 				s[++sp] = mls_level_incomp(l2, l1);
3701da177e4SLinus Torvalds 				continue;
3711da177e4SLinus Torvalds 			default:
3721da177e4SLinus Torvalds 				BUG();
3731da177e4SLinus Torvalds 				return 0;
3741da177e4SLinus Torvalds 			}
3751da177e4SLinus Torvalds 			break;
3761da177e4SLinus Torvalds 			default:
3771da177e4SLinus Torvalds 				BUG();
3781da177e4SLinus Torvalds 				return 0;
3791da177e4SLinus Torvalds 			}
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 			switch (e->op) {
3821da177e4SLinus Torvalds 			case CEXPR_EQ:
3831da177e4SLinus Torvalds 				s[++sp] = (val1 == val2);
3841da177e4SLinus Torvalds 				break;
3851da177e4SLinus Torvalds 			case CEXPR_NEQ:
3861da177e4SLinus Torvalds 				s[++sp] = (val1 != val2);
3871da177e4SLinus Torvalds 				break;
3881da177e4SLinus Torvalds 			default:
3891da177e4SLinus Torvalds 				BUG();
3901da177e4SLinus Torvalds 				return 0;
3911da177e4SLinus Torvalds 			}
3921da177e4SLinus Torvalds 			break;
3931da177e4SLinus Torvalds 		case CEXPR_NAMES:
3941da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH-1))
3951da177e4SLinus Torvalds 				return 0;
3961da177e4SLinus Torvalds 			c = scontext;
3971da177e4SLinus Torvalds 			if (e->attr & CEXPR_TARGET)
3981da177e4SLinus Torvalds 				c = tcontext;
3991da177e4SLinus Torvalds 			else if (e->attr & CEXPR_XTARGET) {
4001da177e4SLinus Torvalds 				c = xcontext;
4011da177e4SLinus Torvalds 				if (!c) {
4021da177e4SLinus Torvalds 					BUG();
4031da177e4SLinus Torvalds 					return 0;
4041da177e4SLinus Torvalds 				}
4051da177e4SLinus Torvalds 			}
4061da177e4SLinus Torvalds 			if (e->attr & CEXPR_USER)
4071da177e4SLinus Torvalds 				val1 = c->user;
4081da177e4SLinus Torvalds 			else if (e->attr & CEXPR_ROLE)
4091da177e4SLinus Torvalds 				val1 = c->role;
4101da177e4SLinus Torvalds 			else if (e->attr & CEXPR_TYPE)
4111da177e4SLinus Torvalds 				val1 = c->type;
4121da177e4SLinus Torvalds 			else {
4131da177e4SLinus Torvalds 				BUG();
4141da177e4SLinus Torvalds 				return 0;
4151da177e4SLinus Torvalds 			}
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 			switch (e->op) {
4181da177e4SLinus Torvalds 			case CEXPR_EQ:
4191da177e4SLinus Torvalds 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
4201da177e4SLinus Torvalds 				break;
4211da177e4SLinus Torvalds 			case CEXPR_NEQ:
4221da177e4SLinus Torvalds 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
4231da177e4SLinus Torvalds 				break;
4241da177e4SLinus Torvalds 			default:
4251da177e4SLinus Torvalds 				BUG();
4261da177e4SLinus Torvalds 				return 0;
4271da177e4SLinus Torvalds 			}
4281da177e4SLinus Torvalds 			break;
4291da177e4SLinus Torvalds 		default:
4301da177e4SLinus Torvalds 			BUG();
4311da177e4SLinus Torvalds 			return 0;
4321da177e4SLinus Torvalds 		}
4331da177e4SLinus Torvalds 	}
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	BUG_ON(sp != 0);
4361da177e4SLinus Torvalds 	return s[0];
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds /*
44044c2d9bdSKaiGai Kohei  * security_dump_masked_av - dumps masked permissions during
44144c2d9bdSKaiGai Kohei  * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
44244c2d9bdSKaiGai Kohei  */
44344c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args)
44444c2d9bdSKaiGai Kohei {
44544c2d9bdSKaiGai Kohei 	struct perm_datum *pdatum = d;
44644c2d9bdSKaiGai Kohei 	char **permission_names = args;
44744c2d9bdSKaiGai Kohei 
44844c2d9bdSKaiGai Kohei 	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
44944c2d9bdSKaiGai Kohei 
45044c2d9bdSKaiGai Kohei 	permission_names[pdatum->value - 1] = (char *)k;
45144c2d9bdSKaiGai Kohei 
45244c2d9bdSKaiGai Kohei 	return 0;
45344c2d9bdSKaiGai Kohei }
45444c2d9bdSKaiGai Kohei 
455aa8e712cSStephen Smalley static void security_dump_masked_av(struct policydb *policydb,
456aa8e712cSStephen Smalley 				    struct context *scontext,
45744c2d9bdSKaiGai Kohei 				    struct context *tcontext,
45844c2d9bdSKaiGai Kohei 				    u16 tclass,
45944c2d9bdSKaiGai Kohei 				    u32 permissions,
46044c2d9bdSKaiGai Kohei 				    const char *reason)
46144c2d9bdSKaiGai Kohei {
46244c2d9bdSKaiGai Kohei 	struct common_datum *common_dat;
46344c2d9bdSKaiGai Kohei 	struct class_datum *tclass_dat;
46444c2d9bdSKaiGai Kohei 	struct audit_buffer *ab;
46544c2d9bdSKaiGai Kohei 	char *tclass_name;
46644c2d9bdSKaiGai Kohei 	char *scontext_name = NULL;
46744c2d9bdSKaiGai Kohei 	char *tcontext_name = NULL;
46844c2d9bdSKaiGai Kohei 	char *permission_names[32];
4692da5d31bSJames Morris 	int index;
4702da5d31bSJames Morris 	u32 length;
47144c2d9bdSKaiGai Kohei 	bool need_comma = false;
47244c2d9bdSKaiGai Kohei 
47344c2d9bdSKaiGai Kohei 	if (!permissions)
47444c2d9bdSKaiGai Kohei 		return;
47544c2d9bdSKaiGai Kohei 
476aa8e712cSStephen Smalley 	tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
477aa8e712cSStephen Smalley 	tclass_dat = policydb->class_val_to_struct[tclass - 1];
47844c2d9bdSKaiGai Kohei 	common_dat = tclass_dat->comdatum;
47944c2d9bdSKaiGai Kohei 
48044c2d9bdSKaiGai Kohei 	/* init permission_names */
48144c2d9bdSKaiGai Kohei 	if (common_dat &&
48244c2d9bdSKaiGai Kohei 	    hashtab_map(common_dat->permissions.table,
48344c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
48444c2d9bdSKaiGai Kohei 		goto out;
48544c2d9bdSKaiGai Kohei 
48644c2d9bdSKaiGai Kohei 	if (hashtab_map(tclass_dat->permissions.table,
48744c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
48844c2d9bdSKaiGai Kohei 		goto out;
48944c2d9bdSKaiGai Kohei 
49044c2d9bdSKaiGai Kohei 	/* get scontext/tcontext in text form */
491aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, scontext,
49244c2d9bdSKaiGai Kohei 				     &scontext_name, &length) < 0)
49344c2d9bdSKaiGai Kohei 		goto out;
49444c2d9bdSKaiGai Kohei 
495aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, tcontext,
49644c2d9bdSKaiGai Kohei 				     &tcontext_name, &length) < 0)
49744c2d9bdSKaiGai Kohei 		goto out;
49844c2d9bdSKaiGai Kohei 
49944c2d9bdSKaiGai Kohei 	/* audit a message */
500cdfb6b34SRichard Guy Briggs 	ab = audit_log_start(audit_context(),
50144c2d9bdSKaiGai Kohei 			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
50244c2d9bdSKaiGai Kohei 	if (!ab)
50344c2d9bdSKaiGai Kohei 		goto out;
50444c2d9bdSKaiGai Kohei 
50544c2d9bdSKaiGai Kohei 	audit_log_format(ab, "op=security_compute_av reason=%s "
50644c2d9bdSKaiGai Kohei 			 "scontext=%s tcontext=%s tclass=%s perms=",
50744c2d9bdSKaiGai Kohei 			 reason, scontext_name, tcontext_name, tclass_name);
50844c2d9bdSKaiGai Kohei 
50944c2d9bdSKaiGai Kohei 	for (index = 0; index < 32; index++) {
51044c2d9bdSKaiGai Kohei 		u32 mask = (1 << index);
51144c2d9bdSKaiGai Kohei 
51244c2d9bdSKaiGai Kohei 		if ((mask & permissions) == 0)
51344c2d9bdSKaiGai Kohei 			continue;
51444c2d9bdSKaiGai Kohei 
51544c2d9bdSKaiGai Kohei 		audit_log_format(ab, "%s%s",
51644c2d9bdSKaiGai Kohei 				 need_comma ? "," : "",
51744c2d9bdSKaiGai Kohei 				 permission_names[index]
51844c2d9bdSKaiGai Kohei 				 ? permission_names[index] : "????");
51944c2d9bdSKaiGai Kohei 		need_comma = true;
52044c2d9bdSKaiGai Kohei 	}
52144c2d9bdSKaiGai Kohei 	audit_log_end(ab);
52244c2d9bdSKaiGai Kohei out:
52344c2d9bdSKaiGai Kohei 	/* release scontext/tcontext */
52444c2d9bdSKaiGai Kohei 	kfree(tcontext_name);
52544c2d9bdSKaiGai Kohei 	kfree(scontext_name);
52644c2d9bdSKaiGai Kohei 
52744c2d9bdSKaiGai Kohei 	return;
52844c2d9bdSKaiGai Kohei }
52944c2d9bdSKaiGai Kohei 
53044c2d9bdSKaiGai Kohei /*
531d9250deaSKaiGai Kohei  * security_boundary_permission - drops violated permissions
532d9250deaSKaiGai Kohei  * on boundary constraint.
533d9250deaSKaiGai Kohei  */
534aa8e712cSStephen Smalley static void type_attribute_bounds_av(struct policydb *policydb,
535aa8e712cSStephen Smalley 				     struct context *scontext,
536d9250deaSKaiGai Kohei 				     struct context *tcontext,
537d9250deaSKaiGai Kohei 				     u16 tclass,
538d9250deaSKaiGai Kohei 				     struct av_decision *avd)
539d9250deaSKaiGai Kohei {
5402ae3ba39SKaiGai Kohei 	struct context lo_scontext;
5417ea59202SStephen Smalley 	struct context lo_tcontext, *tcontextp = tcontext;
5422ae3ba39SKaiGai Kohei 	struct av_decision lo_avd;
54323bdecb0SEric Paris 	struct type_datum *source;
54423bdecb0SEric Paris 	struct type_datum *target;
5452ae3ba39SKaiGai Kohei 	u32 masked = 0;
546d9250deaSKaiGai Kohei 
547f07ea1d4SOndrej Mosnacek 	source = policydb->type_val_to_struct[scontext->type - 1];
54823bdecb0SEric Paris 	BUG_ON(!source);
54923bdecb0SEric Paris 
5507ea59202SStephen Smalley 	if (!source->bounds)
5517ea59202SStephen Smalley 		return;
5527ea59202SStephen Smalley 
553f07ea1d4SOndrej Mosnacek 	target = policydb->type_val_to_struct[tcontext->type - 1];
55423bdecb0SEric Paris 	BUG_ON(!target);
55523bdecb0SEric Paris 
556d9250deaSKaiGai Kohei 	memset(&lo_avd, 0, sizeof(lo_avd));
557d9250deaSKaiGai Kohei 
558d9250deaSKaiGai Kohei 	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
559d9250deaSKaiGai Kohei 	lo_scontext.type = source->bounds;
560d9250deaSKaiGai Kohei 
5612ae3ba39SKaiGai Kohei 	if (target->bounds) {
5622ae3ba39SKaiGai Kohei 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5632ae3ba39SKaiGai Kohei 		lo_tcontext.type = target->bounds;
5647ea59202SStephen Smalley 		tcontextp = &lo_tcontext;
5652ae3ba39SKaiGai Kohei 	}
5662ae3ba39SKaiGai Kohei 
567aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, &lo_scontext,
5687ea59202SStephen Smalley 				  tcontextp,
5692ae3ba39SKaiGai Kohei 				  tclass,
570fa1aa143SJeff Vander Stoep 				  &lo_avd,
571fa1aa143SJeff Vander Stoep 				  NULL);
5722ae3ba39SKaiGai Kohei 
5737ea59202SStephen Smalley 	masked = ~lo_avd.allowed & avd->allowed;
5747ea59202SStephen Smalley 
5757ea59202SStephen Smalley 	if (likely(!masked))
5767ea59202SStephen Smalley 		return;		/* no masked permission */
5777ea59202SStephen Smalley 
578d9250deaSKaiGai Kohei 	/* mask violated permissions */
579d9250deaSKaiGai Kohei 	avd->allowed &= ~masked;
580d9250deaSKaiGai Kohei 
58144c2d9bdSKaiGai Kohei 	/* audit masked permissions */
582aa8e712cSStephen Smalley 	security_dump_masked_av(policydb, scontext, tcontext,
58344c2d9bdSKaiGai Kohei 				tclass, masked, "bounds");
584d9250deaSKaiGai Kohei }
585d9250deaSKaiGai Kohei 
586d9250deaSKaiGai Kohei /*
587fa1aa143SJeff Vander Stoep  * flag which drivers have permissions
588fa1aa143SJeff Vander Stoep  * only looking for ioctl based extended permssions
589fa1aa143SJeff Vander Stoep  */
590fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers(
591fa1aa143SJeff Vander Stoep 		struct extended_perms *xperms,
592fa1aa143SJeff Vander Stoep 		struct avtab_node *node)
593fa1aa143SJeff Vander Stoep {
594fa1aa143SJeff Vander Stoep 	unsigned int i;
595fa1aa143SJeff Vander Stoep 
596fa1aa143SJeff Vander Stoep 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
597fa1aa143SJeff Vander Stoep 		/* if one or more driver has all permissions allowed */
598fa1aa143SJeff Vander Stoep 		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
599fa1aa143SJeff Vander Stoep 			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
600fa1aa143SJeff Vander Stoep 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
601fa1aa143SJeff Vander Stoep 		/* if allowing permissions within a driver */
602fa1aa143SJeff Vander Stoep 		security_xperm_set(xperms->drivers.p,
603fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->driver);
604fa1aa143SJeff Vander Stoep 	}
605fa1aa143SJeff Vander Stoep 
606fa1aa143SJeff Vander Stoep 	/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
607fa1aa143SJeff Vander Stoep 	if (node->key.specified & AVTAB_XPERMS_ALLOWED)
608fa1aa143SJeff Vander Stoep 		xperms->len = 1;
609fa1aa143SJeff Vander Stoep }
610fa1aa143SJeff Vander Stoep 
611fa1aa143SJeff Vander Stoep /*
612fa1aa143SJeff Vander Stoep  * Compute access vectors and extended permissions based on a context
613fa1aa143SJeff Vander Stoep  * structure pair for the permissions in a particular class.
6141da177e4SLinus Torvalds  */
615aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
616aa8e712cSStephen Smalley 				      struct context *scontext,
6171da177e4SLinus Torvalds 				      struct context *tcontext,
6181da177e4SLinus Torvalds 				      u16 tclass,
619fa1aa143SJeff Vander Stoep 				      struct av_decision *avd,
620fa1aa143SJeff Vander Stoep 				      struct extended_perms *xperms)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds 	struct constraint_node *constraint;
6231da177e4SLinus Torvalds 	struct role_allow *ra;
6241da177e4SLinus Torvalds 	struct avtab_key avkey;
625782ebb99SStephen Smalley 	struct avtab_node *node;
6261da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
627782ebb99SStephen Smalley 	struct ebitmap *sattr, *tattr;
628782ebb99SStephen Smalley 	struct ebitmap_node *snode, *tnode;
629782ebb99SStephen Smalley 	unsigned int i, j;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	avd->allowed = 0;
6321da177e4SLinus Torvalds 	avd->auditallow = 0;
6331da177e4SLinus Torvalds 	avd->auditdeny = 0xffffffff;
634fa1aa143SJeff Vander Stoep 	if (xperms) {
635fa1aa143SJeff Vander Stoep 		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
636fa1aa143SJeff Vander Stoep 		xperms->len = 0;
637fa1aa143SJeff Vander Stoep 	}
6381da177e4SLinus Torvalds 
639aa8e712cSStephen Smalley 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
640c6d3aaa4SStephen Smalley 		if (printk_ratelimit())
641b54c85c1Speter enderborg 			pr_warn("SELinux:  Invalid class %hu\n", tclass);
64219439d05SStephen Smalley 		return;
643c6d3aaa4SStephen Smalley 	}
6443f12070eSEric Paris 
645aa8e712cSStephen Smalley 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
6463f12070eSEric Paris 
6473f12070eSEric Paris 	/*
6481da177e4SLinus Torvalds 	 * If a specific type enforcement rule was defined for
6491da177e4SLinus Torvalds 	 * this permission check, then use it.
6501da177e4SLinus Torvalds 	 */
6511da177e4SLinus Torvalds 	avkey.target_class = tclass;
652fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
653acdf52d9SKent Overstreet 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
654acdf52d9SKent Overstreet 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
6559fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(sattr, snode, i) {
6569fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
657782ebb99SStephen Smalley 			avkey.source_type = i + 1;
658782ebb99SStephen Smalley 			avkey.target_type = j + 1;
659aa8e712cSStephen Smalley 			for (node = avtab_search_node(&policydb->te_avtab,
660aa8e712cSStephen Smalley 						      &avkey);
661dbc74c65SVesa-Matti Kari 			     node;
662782ebb99SStephen Smalley 			     node = avtab_search_node_next(node, avkey.specified)) {
663782ebb99SStephen Smalley 				if (node->key.specified == AVTAB_ALLOWED)
664fa1aa143SJeff Vander Stoep 					avd->allowed |= node->datum.u.data;
665782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITALLOW)
666fa1aa143SJeff Vander Stoep 					avd->auditallow |= node->datum.u.data;
667782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITDENY)
668fa1aa143SJeff Vander Stoep 					avd->auditdeny &= node->datum.u.data;
669fa1aa143SJeff Vander Stoep 				else if (xperms && (node->key.specified & AVTAB_XPERMS))
670fa1aa143SJeff Vander Stoep 					services_compute_xperms_drivers(xperms, node);
6711da177e4SLinus Torvalds 			}
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds 			/* Check conditional av table for additional permissions */
674aa8e712cSStephen Smalley 			cond_compute_av(&policydb->te_cond_avtab, &avkey,
675fa1aa143SJeff Vander Stoep 					avd, xperms);
6761da177e4SLinus Torvalds 
677782ebb99SStephen Smalley 		}
678782ebb99SStephen Smalley 	}
679782ebb99SStephen Smalley 
6801da177e4SLinus Torvalds 	/*
6811da177e4SLinus Torvalds 	 * Remove any permissions prohibited by a constraint (this includes
6821da177e4SLinus Torvalds 	 * the MLS policy).
6831da177e4SLinus Torvalds 	 */
6841da177e4SLinus Torvalds 	constraint = tclass_datum->constraints;
6851da177e4SLinus Torvalds 	while (constraint) {
6861da177e4SLinus Torvalds 		if ((constraint->permissions & (avd->allowed)) &&
687aa8e712cSStephen Smalley 		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
6881da177e4SLinus Torvalds 					  constraint->expr)) {
689caabbdc0SKaiGai Kohei 			avd->allowed &= ~(constraint->permissions);
6901da177e4SLinus Torvalds 		}
6911da177e4SLinus Torvalds 		constraint = constraint->next;
6921da177e4SLinus Torvalds 	}
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	/*
6951da177e4SLinus Torvalds 	 * If checking process transition permission and the
6961da177e4SLinus Torvalds 	 * role is changing, then check the (current_role, new_role)
6971da177e4SLinus Torvalds 	 * pair.
6981da177e4SLinus Torvalds 	 */
699aa8e712cSStephen Smalley 	if (tclass == policydb->process_class &&
700aa8e712cSStephen Smalley 	    (avd->allowed & policydb->process_trans_perms) &&
7011da177e4SLinus Torvalds 	    scontext->role != tcontext->role) {
702aa8e712cSStephen Smalley 		for (ra = policydb->role_allow; ra; ra = ra->next) {
7031da177e4SLinus Torvalds 			if (scontext->role == ra->role &&
7041da177e4SLinus Torvalds 			    tcontext->role == ra->new_role)
7051da177e4SLinus Torvalds 				break;
7061da177e4SLinus Torvalds 		}
7071da177e4SLinus Torvalds 		if (!ra)
708aa8e712cSStephen Smalley 			avd->allowed &= ~policydb->process_trans_perms;
7091da177e4SLinus Torvalds 	}
7101da177e4SLinus Torvalds 
711d9250deaSKaiGai Kohei 	/*
712d9250deaSKaiGai Kohei 	 * If the given source and target types have boundary
713d9250deaSKaiGai Kohei 	 * constraint, lazy checks have to mask any violated
714d9250deaSKaiGai Kohei 	 * permission and notice it to userspace via audit.
715d9250deaSKaiGai Kohei 	 */
716aa8e712cSStephen Smalley 	type_attribute_bounds_av(policydb, scontext, tcontext,
71719439d05SStephen Smalley 				 tclass, avd);
71822df4adbSStephen Smalley }
71922df4adbSStephen Smalley 
720aa8e712cSStephen Smalley static int security_validtrans_handle_fail(struct selinux_state *state,
721aa8e712cSStephen Smalley 					   struct context *ocontext,
7221da177e4SLinus Torvalds 					   struct context *ncontext,
7231da177e4SLinus Torvalds 					   struct context *tcontext,
7241da177e4SLinus Torvalds 					   u16 tclass)
7251da177e4SLinus Torvalds {
726aa8e712cSStephen Smalley 	struct policydb *p = &state->ss->policydb;
7271da177e4SLinus Torvalds 	char *o = NULL, *n = NULL, *t = NULL;
7281da177e4SLinus Torvalds 	u32 olen, nlen, tlen;
7291da177e4SLinus Torvalds 
730aa8e712cSStephen Smalley 	if (context_struct_to_string(p, ocontext, &o, &olen))
7311da177e4SLinus Torvalds 		goto out;
732aa8e712cSStephen Smalley 	if (context_struct_to_string(p, ncontext, &n, &nlen))
7331da177e4SLinus Torvalds 		goto out;
734aa8e712cSStephen Smalley 	if (context_struct_to_string(p, tcontext, &t, &tlen))
7351da177e4SLinus Torvalds 		goto out;
736cdfb6b34SRichard Guy Briggs 	audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
7374093a844SRichard Guy Briggs 		  "op=security_validate_transition seresult=denied"
7381da177e4SLinus Torvalds 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
739aa8e712cSStephen Smalley 		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
7401da177e4SLinus Torvalds out:
7411da177e4SLinus Torvalds 	kfree(o);
7421da177e4SLinus Torvalds 	kfree(n);
7431da177e4SLinus Torvalds 	kfree(t);
7441da177e4SLinus Torvalds 
745e5a5ca96SPaul Moore 	if (!enforcing_enabled(state))
7461da177e4SLinus Torvalds 		return 0;
7471da177e4SLinus Torvalds 	return -EPERM;
7481da177e4SLinus Torvalds }
7491da177e4SLinus Torvalds 
750aa8e712cSStephen Smalley static int security_compute_validatetrans(struct selinux_state *state,
751aa8e712cSStephen Smalley 					  u32 oldsid, u32 newsid, u32 tasksid,
752f9df6458SAndrew Perepechko 					  u16 orig_tclass, bool user)
7531da177e4SLinus Torvalds {
754aa8e712cSStephen Smalley 	struct policydb *policydb;
755aa8e712cSStephen Smalley 	struct sidtab *sidtab;
7561da177e4SLinus Torvalds 	struct context *ocontext;
7571da177e4SLinus Torvalds 	struct context *ncontext;
7581da177e4SLinus Torvalds 	struct context *tcontext;
7591da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
7601da177e4SLinus Torvalds 	struct constraint_node *constraint;
761c6d3aaa4SStephen Smalley 	u16 tclass;
7621da177e4SLinus Torvalds 	int rc = 0;
7631da177e4SLinus Torvalds 
764aa8e712cSStephen Smalley 
765aa8e712cSStephen Smalley 	if (!state->initialized)
7661da177e4SLinus Torvalds 		return 0;
7671da177e4SLinus Torvalds 
768aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
769aa8e712cSStephen Smalley 
770aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
77124ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
7721da177e4SLinus Torvalds 
773f9df6458SAndrew Perepechko 	if (!user)
774aa8e712cSStephen Smalley 		tclass = unmap_class(&state->ss->map, orig_tclass);
775f9df6458SAndrew Perepechko 	else
776f9df6458SAndrew Perepechko 		tclass = orig_tclass;
777c6d3aaa4SStephen Smalley 
778aa8e712cSStephen Smalley 	if (!tclass || tclass > policydb->p_classes.nprim) {
7791da177e4SLinus Torvalds 		rc = -EINVAL;
7801da177e4SLinus Torvalds 		goto out;
7811da177e4SLinus Torvalds 	}
782aa8e712cSStephen Smalley 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
7831da177e4SLinus Torvalds 
784aa8e712cSStephen Smalley 	ocontext = sidtab_search(sidtab, oldsid);
7851da177e4SLinus Torvalds 	if (!ocontext) {
786b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
787744ba35eSEric Paris 			__func__, oldsid);
7881da177e4SLinus Torvalds 		rc = -EINVAL;
7891da177e4SLinus Torvalds 		goto out;
7901da177e4SLinus Torvalds 	}
7911da177e4SLinus Torvalds 
792aa8e712cSStephen Smalley 	ncontext = sidtab_search(sidtab, newsid);
7931da177e4SLinus Torvalds 	if (!ncontext) {
794b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
795744ba35eSEric Paris 			__func__, newsid);
7961da177e4SLinus Torvalds 		rc = -EINVAL;
7971da177e4SLinus Torvalds 		goto out;
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 
800aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tasksid);
8011da177e4SLinus Torvalds 	if (!tcontext) {
802b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
803744ba35eSEric Paris 			__func__, tasksid);
8041da177e4SLinus Torvalds 		rc = -EINVAL;
8051da177e4SLinus Torvalds 		goto out;
8061da177e4SLinus Torvalds 	}
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	constraint = tclass_datum->validatetrans;
8091da177e4SLinus Torvalds 	while (constraint) {
810aa8e712cSStephen Smalley 		if (!constraint_expr_eval(policydb, ocontext, ncontext,
811aa8e712cSStephen Smalley 					  tcontext, constraint->expr)) {
812f9df6458SAndrew Perepechko 			if (user)
813f9df6458SAndrew Perepechko 				rc = -EPERM;
814f9df6458SAndrew Perepechko 			else
815aa8e712cSStephen Smalley 				rc = security_validtrans_handle_fail(state,
816aa8e712cSStephen Smalley 								     ocontext,
817f9df6458SAndrew Perepechko 								     ncontext,
818f9df6458SAndrew Perepechko 								     tcontext,
819f9df6458SAndrew Perepechko 								     tclass);
8201da177e4SLinus Torvalds 			goto out;
8211da177e4SLinus Torvalds 		}
8221da177e4SLinus Torvalds 		constraint = constraint->next;
8231da177e4SLinus Torvalds 	}
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds out:
826aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
8271da177e4SLinus Torvalds 	return rc;
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds 
830aa8e712cSStephen Smalley int security_validate_transition_user(struct selinux_state *state,
831aa8e712cSStephen Smalley 				      u32 oldsid, u32 newsid, u32 tasksid,
832f9df6458SAndrew Perepechko 				      u16 tclass)
833f9df6458SAndrew Perepechko {
834aa8e712cSStephen Smalley 	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
835f9df6458SAndrew Perepechko 					      tclass, true);
836f9df6458SAndrew Perepechko }
837f9df6458SAndrew Perepechko 
838aa8e712cSStephen Smalley int security_validate_transition(struct selinux_state *state,
839aa8e712cSStephen Smalley 				 u32 oldsid, u32 newsid, u32 tasksid,
840f9df6458SAndrew Perepechko 				 u16 orig_tclass)
841f9df6458SAndrew Perepechko {
842aa8e712cSStephen Smalley 	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
843f9df6458SAndrew Perepechko 					      orig_tclass, false);
844f9df6458SAndrew Perepechko }
845f9df6458SAndrew Perepechko 
846d9250deaSKaiGai Kohei /*
847d9250deaSKaiGai Kohei  * security_bounded_transition - check whether the given
848d9250deaSKaiGai Kohei  * transition is directed to bounded, or not.
849d9250deaSKaiGai Kohei  * It returns 0, if @newsid is bounded by @oldsid.
850d9250deaSKaiGai Kohei  * Otherwise, it returns error code.
851d9250deaSKaiGai Kohei  *
852d9250deaSKaiGai Kohei  * @oldsid : current security identifier
853d9250deaSKaiGai Kohei  * @newsid : destinated security identifier
854d9250deaSKaiGai Kohei  */
855aa8e712cSStephen Smalley int security_bounded_transition(struct selinux_state *state,
856aa8e712cSStephen Smalley 				u32 old_sid, u32 new_sid)
857d9250deaSKaiGai Kohei {
858aa8e712cSStephen Smalley 	struct policydb *policydb;
859aa8e712cSStephen Smalley 	struct sidtab *sidtab;
860d9250deaSKaiGai Kohei 	struct context *old_context, *new_context;
861d9250deaSKaiGai Kohei 	struct type_datum *type;
862d9250deaSKaiGai Kohei 	int index;
8634b02b524SEric Paris 	int rc;
864d9250deaSKaiGai Kohei 
865aa8e712cSStephen Smalley 	if (!state->initialized)
8664b14752eSPaul Moore 		return 0;
8674b14752eSPaul Moore 
868aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
869aa8e712cSStephen Smalley 
870aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
87124ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
872d9250deaSKaiGai Kohei 
8734b02b524SEric Paris 	rc = -EINVAL;
874aa8e712cSStephen Smalley 	old_context = sidtab_search(sidtab, old_sid);
875d9250deaSKaiGai Kohei 	if (!old_context) {
876b54c85c1Speter enderborg 		pr_err("SELinux: %s: unrecognized SID %u\n",
877d9250deaSKaiGai Kohei 		       __func__, old_sid);
878d9250deaSKaiGai Kohei 		goto out;
879d9250deaSKaiGai Kohei 	}
880d9250deaSKaiGai Kohei 
8814b02b524SEric Paris 	rc = -EINVAL;
882aa8e712cSStephen Smalley 	new_context = sidtab_search(sidtab, new_sid);
883d9250deaSKaiGai Kohei 	if (!new_context) {
884b54c85c1Speter enderborg 		pr_err("SELinux: %s: unrecognized SID %u\n",
885d9250deaSKaiGai Kohei 		       __func__, new_sid);
886d9250deaSKaiGai Kohei 		goto out;
887d9250deaSKaiGai Kohei 	}
888d9250deaSKaiGai Kohei 
889d9250deaSKaiGai Kohei 	rc = 0;
8904b02b524SEric Paris 	/* type/domain unchanged */
8914b02b524SEric Paris 	if (old_context->type == new_context->type)
892d9250deaSKaiGai Kohei 		goto out;
893d9250deaSKaiGai Kohei 
894d9250deaSKaiGai Kohei 	index = new_context->type;
895d9250deaSKaiGai Kohei 	while (true) {
896f07ea1d4SOndrej Mosnacek 		type = policydb->type_val_to_struct[index - 1];
897d9250deaSKaiGai Kohei 		BUG_ON(!type);
898d9250deaSKaiGai Kohei 
899d9250deaSKaiGai Kohei 		/* not bounded anymore */
900d9250deaSKaiGai Kohei 		rc = -EPERM;
9014b02b524SEric Paris 		if (!type->bounds)
902d9250deaSKaiGai Kohei 			break;
903d9250deaSKaiGai Kohei 
904d9250deaSKaiGai Kohei 		/* @newsid is bounded by @oldsid */
905d9250deaSKaiGai Kohei 		rc = 0;
9064b02b524SEric Paris 		if (type->bounds == old_context->type)
907d9250deaSKaiGai Kohei 			break;
9084b02b524SEric Paris 
909d9250deaSKaiGai Kohei 		index = type->bounds;
910d9250deaSKaiGai Kohei 	}
91144c2d9bdSKaiGai Kohei 
91244c2d9bdSKaiGai Kohei 	if (rc) {
91344c2d9bdSKaiGai Kohei 		char *old_name = NULL;
91444c2d9bdSKaiGai Kohei 		char *new_name = NULL;
9152da5d31bSJames Morris 		u32 length;
91644c2d9bdSKaiGai Kohei 
917aa8e712cSStephen Smalley 		if (!context_struct_to_string(policydb, old_context,
91844c2d9bdSKaiGai Kohei 					      &old_name, &length) &&
919aa8e712cSStephen Smalley 		    !context_struct_to_string(policydb, new_context,
92044c2d9bdSKaiGai Kohei 					      &new_name, &length)) {
921cdfb6b34SRichard Guy Briggs 			audit_log(audit_context(),
92244c2d9bdSKaiGai Kohei 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
92344c2d9bdSKaiGai Kohei 				  "op=security_bounded_transition "
9244093a844SRichard Guy Briggs 				  "seresult=denied "
92544c2d9bdSKaiGai Kohei 				  "oldcontext=%s newcontext=%s",
92644c2d9bdSKaiGai Kohei 				  old_name, new_name);
92744c2d9bdSKaiGai Kohei 		}
92844c2d9bdSKaiGai Kohei 		kfree(new_name);
92944c2d9bdSKaiGai Kohei 		kfree(old_name);
93044c2d9bdSKaiGai Kohei 	}
931d9250deaSKaiGai Kohei out:
932aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
933d9250deaSKaiGai Kohei 
934d9250deaSKaiGai Kohei 	return rc;
935d9250deaSKaiGai Kohei }
936d9250deaSKaiGai Kohei 
937aa8e712cSStephen Smalley static void avd_init(struct selinux_state *state, struct av_decision *avd)
938c6d3aaa4SStephen Smalley {
93919439d05SStephen Smalley 	avd->allowed = 0;
94019439d05SStephen Smalley 	avd->auditallow = 0;
94119439d05SStephen Smalley 	avd->auditdeny = 0xffffffff;
942aa8e712cSStephen Smalley 	avd->seqno = state->ss->latest_granting;
94319439d05SStephen Smalley 	avd->flags = 0;
944c6d3aaa4SStephen Smalley }
945c6d3aaa4SStephen Smalley 
946fa1aa143SJeff Vander Stoep void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
947fa1aa143SJeff Vander Stoep 					struct avtab_node *node)
948fa1aa143SJeff Vander Stoep {
949fa1aa143SJeff Vander Stoep 	unsigned int i;
950fa1aa143SJeff Vander Stoep 
951fa1aa143SJeff Vander Stoep 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
952fa1aa143SJeff Vander Stoep 		if (xpermd->driver != node->datum.u.xperms->driver)
953fa1aa143SJeff Vander Stoep 			return;
954fa1aa143SJeff Vander Stoep 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
955fa1aa143SJeff Vander Stoep 		if (!security_xperm_test(node->datum.u.xperms->perms.p,
956fa1aa143SJeff Vander Stoep 					xpermd->driver))
957fa1aa143SJeff Vander Stoep 			return;
958fa1aa143SJeff Vander Stoep 	} else {
959fa1aa143SJeff Vander Stoep 		BUG();
960fa1aa143SJeff Vander Stoep 	}
961fa1aa143SJeff Vander Stoep 
962fa1aa143SJeff Vander Stoep 	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
963fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_ALLOWED;
964fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
965fa1aa143SJeff Vander Stoep 			memset(xpermd->allowed->p, 0xff,
966fa1aa143SJeff Vander Stoep 					sizeof(xpermd->allowed->p));
967fa1aa143SJeff Vander Stoep 		}
968fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
969fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
970fa1aa143SJeff Vander Stoep 				xpermd->allowed->p[i] |=
971fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
972fa1aa143SJeff Vander Stoep 		}
973fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
974fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_AUDITALLOW;
975fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
976fa1aa143SJeff Vander Stoep 			memset(xpermd->auditallow->p, 0xff,
977fa1aa143SJeff Vander Stoep 					sizeof(xpermd->auditallow->p));
978fa1aa143SJeff Vander Stoep 		}
979fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
980fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
981fa1aa143SJeff Vander Stoep 				xpermd->auditallow->p[i] |=
982fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
983fa1aa143SJeff Vander Stoep 		}
984fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
985fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_DONTAUDIT;
986fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
987fa1aa143SJeff Vander Stoep 			memset(xpermd->dontaudit->p, 0xff,
988fa1aa143SJeff Vander Stoep 					sizeof(xpermd->dontaudit->p));
989fa1aa143SJeff Vander Stoep 		}
990fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
991fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
992fa1aa143SJeff Vander Stoep 				xpermd->dontaudit->p[i] |=
993fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
994fa1aa143SJeff Vander Stoep 		}
995fa1aa143SJeff Vander Stoep 	} else {
996fa1aa143SJeff Vander Stoep 		BUG();
997fa1aa143SJeff Vander Stoep 	}
998fa1aa143SJeff Vander Stoep }
999fa1aa143SJeff Vander Stoep 
1000aa8e712cSStephen Smalley void security_compute_xperms_decision(struct selinux_state *state,
1001aa8e712cSStephen Smalley 				      u32 ssid,
1002fa1aa143SJeff Vander Stoep 				      u32 tsid,
1003fa1aa143SJeff Vander Stoep 				      u16 orig_tclass,
1004fa1aa143SJeff Vander Stoep 				      u8 driver,
1005fa1aa143SJeff Vander Stoep 				      struct extended_perms_decision *xpermd)
1006fa1aa143SJeff Vander Stoep {
1007aa8e712cSStephen Smalley 	struct policydb *policydb;
1008aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1009fa1aa143SJeff Vander Stoep 	u16 tclass;
1010fa1aa143SJeff Vander Stoep 	struct context *scontext, *tcontext;
1011fa1aa143SJeff Vander Stoep 	struct avtab_key avkey;
1012fa1aa143SJeff Vander Stoep 	struct avtab_node *node;
1013fa1aa143SJeff Vander Stoep 	struct ebitmap *sattr, *tattr;
1014fa1aa143SJeff Vander Stoep 	struct ebitmap_node *snode, *tnode;
1015fa1aa143SJeff Vander Stoep 	unsigned int i, j;
1016fa1aa143SJeff Vander Stoep 
1017fa1aa143SJeff Vander Stoep 	xpermd->driver = driver;
1018fa1aa143SJeff Vander Stoep 	xpermd->used = 0;
1019fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1020fa1aa143SJeff Vander Stoep 	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1021fa1aa143SJeff Vander Stoep 	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1022fa1aa143SJeff Vander Stoep 
1023aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
1024aa8e712cSStephen Smalley 	if (!state->initialized)
1025fa1aa143SJeff Vander Stoep 		goto allow;
1026fa1aa143SJeff Vander Stoep 
1027aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
102824ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
1029aa8e712cSStephen Smalley 
1030aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
1031fa1aa143SJeff Vander Stoep 	if (!scontext) {
1032b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1033fa1aa143SJeff Vander Stoep 		       __func__, ssid);
1034fa1aa143SJeff Vander Stoep 		goto out;
1035fa1aa143SJeff Vander Stoep 	}
1036fa1aa143SJeff Vander Stoep 
1037aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
1038fa1aa143SJeff Vander Stoep 	if (!tcontext) {
1039b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1040fa1aa143SJeff Vander Stoep 		       __func__, tsid);
1041fa1aa143SJeff Vander Stoep 		goto out;
1042fa1aa143SJeff Vander Stoep 	}
1043fa1aa143SJeff Vander Stoep 
1044aa8e712cSStephen Smalley 	tclass = unmap_class(&state->ss->map, orig_tclass);
1045fa1aa143SJeff Vander Stoep 	if (unlikely(orig_tclass && !tclass)) {
1046aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1047fa1aa143SJeff Vander Stoep 			goto allow;
1048fa1aa143SJeff Vander Stoep 		goto out;
1049fa1aa143SJeff Vander Stoep 	}
1050fa1aa143SJeff Vander Stoep 
1051fa1aa143SJeff Vander Stoep 
1052aa8e712cSStephen Smalley 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1053fa1aa143SJeff Vander Stoep 		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
1054fa1aa143SJeff Vander Stoep 		goto out;
1055fa1aa143SJeff Vander Stoep 	}
1056fa1aa143SJeff Vander Stoep 
1057fa1aa143SJeff Vander Stoep 	avkey.target_class = tclass;
1058fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_XPERMS;
1059acdf52d9SKent Overstreet 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
1060acdf52d9SKent Overstreet 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1061fa1aa143SJeff Vander Stoep 	ebitmap_for_each_positive_bit(sattr, snode, i) {
1062fa1aa143SJeff Vander Stoep 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1063fa1aa143SJeff Vander Stoep 			avkey.source_type = i + 1;
1064fa1aa143SJeff Vander Stoep 			avkey.target_type = j + 1;
1065aa8e712cSStephen Smalley 			for (node = avtab_search_node(&policydb->te_avtab,
1066aa8e712cSStephen Smalley 						      &avkey);
1067fa1aa143SJeff Vander Stoep 			     node;
1068fa1aa143SJeff Vander Stoep 			     node = avtab_search_node_next(node, avkey.specified))
1069fa1aa143SJeff Vander Stoep 				services_compute_xperms_decision(xpermd, node);
1070fa1aa143SJeff Vander Stoep 
1071aa8e712cSStephen Smalley 			cond_compute_xperms(&policydb->te_cond_avtab,
1072fa1aa143SJeff Vander Stoep 						&avkey, xpermd);
1073fa1aa143SJeff Vander Stoep 		}
1074fa1aa143SJeff Vander Stoep 	}
1075fa1aa143SJeff Vander Stoep out:
1076aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
1077fa1aa143SJeff Vander Stoep 	return;
1078fa1aa143SJeff Vander Stoep allow:
1079fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1080fa1aa143SJeff Vander Stoep 	goto out;
1081fa1aa143SJeff Vander Stoep }
1082c6d3aaa4SStephen Smalley 
10831da177e4SLinus Torvalds /**
10841da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
10851da177e4SLinus Torvalds  * @ssid: source security identifier
10861da177e4SLinus Torvalds  * @tsid: target security identifier
10871da177e4SLinus Torvalds  * @tclass: target security class
10881da177e4SLinus Torvalds  * @avd: access vector decisions
1089fa1aa143SJeff Vander Stoep  * @xperms: extended permissions
10901da177e4SLinus Torvalds  *
10911da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
10921da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
10931da177e4SLinus Torvalds  */
1094aa8e712cSStephen Smalley void security_compute_av(struct selinux_state *state,
1095aa8e712cSStephen Smalley 			 u32 ssid,
10961da177e4SLinus Torvalds 			 u32 tsid,
1097c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
1098fa1aa143SJeff Vander Stoep 			 struct av_decision *avd,
1099fa1aa143SJeff Vander Stoep 			 struct extended_perms *xperms)
1100c6d3aaa4SStephen Smalley {
1101aa8e712cSStephen Smalley 	struct policydb *policydb;
1102aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1103c6d3aaa4SStephen Smalley 	u16 tclass;
110419439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
1105c6d3aaa4SStephen Smalley 
1106aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
1107aa8e712cSStephen Smalley 	avd_init(state, avd);
1108fa1aa143SJeff Vander Stoep 	xperms->len = 0;
1109aa8e712cSStephen Smalley 	if (!state->initialized)
1110c6d3aaa4SStephen Smalley 		goto allow;
1111c6d3aaa4SStephen Smalley 
1112aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
111324ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
1114aa8e712cSStephen Smalley 
1115aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
111619439d05SStephen Smalley 	if (!scontext) {
1117b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
111819439d05SStephen Smalley 		       __func__, ssid);
111919439d05SStephen Smalley 		goto out;
112019439d05SStephen Smalley 	}
112119439d05SStephen Smalley 
112219439d05SStephen Smalley 	/* permissive domain? */
1123aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
112419439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
112519439d05SStephen Smalley 
1126aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
112719439d05SStephen Smalley 	if (!tcontext) {
1128b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
112919439d05SStephen Smalley 		       __func__, tsid);
113019439d05SStephen Smalley 		goto out;
113119439d05SStephen Smalley 	}
113219439d05SStephen Smalley 
1133aa8e712cSStephen Smalley 	tclass = unmap_class(&state->ss->map, orig_tclass);
1134c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
1135aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1136c6d3aaa4SStephen Smalley 			goto allow;
1137b7f3008aSStephen Smalley 		goto out;
1138c6d3aaa4SStephen Smalley 	}
1139aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1140aa8e712cSStephen Smalley 				  xperms);
1141aa8e712cSStephen Smalley 	map_decision(&state->ss->map, orig_tclass, avd,
1142aa8e712cSStephen Smalley 		     policydb->allow_unknown);
1143b7f3008aSStephen Smalley out:
1144aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
114519439d05SStephen Smalley 	return;
1146c6d3aaa4SStephen Smalley allow:
1147c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
1148b7f3008aSStephen Smalley 	goto out;
1149c6d3aaa4SStephen Smalley }
1150c6d3aaa4SStephen Smalley 
1151aa8e712cSStephen Smalley void security_compute_av_user(struct selinux_state *state,
1152aa8e712cSStephen Smalley 			      u32 ssid,
1153c6d3aaa4SStephen Smalley 			      u32 tsid,
11541da177e4SLinus Torvalds 			      u16 tclass,
11551da177e4SLinus Torvalds 			      struct av_decision *avd)
11561da177e4SLinus Torvalds {
1157aa8e712cSStephen Smalley 	struct policydb *policydb;
1158aa8e712cSStephen Smalley 	struct sidtab *sidtab;
115919439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
11601da177e4SLinus Torvalds 
1161aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
1162aa8e712cSStephen Smalley 	avd_init(state, avd);
1163aa8e712cSStephen Smalley 	if (!state->initialized)
116419439d05SStephen Smalley 		goto allow;
116519439d05SStephen Smalley 
1166aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
116724ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
1168aa8e712cSStephen Smalley 
1169aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
117019439d05SStephen Smalley 	if (!scontext) {
1171b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
117219439d05SStephen Smalley 		       __func__, ssid);
117319439d05SStephen Smalley 		goto out;
117419439d05SStephen Smalley 	}
117519439d05SStephen Smalley 
117619439d05SStephen Smalley 	/* permissive domain? */
1177aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
117819439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
117919439d05SStephen Smalley 
1180aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
118119439d05SStephen Smalley 	if (!tcontext) {
1182b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
118319439d05SStephen Smalley 		       __func__, tsid);
118419439d05SStephen Smalley 		goto out;
118519439d05SStephen Smalley 	}
118619439d05SStephen Smalley 
118719439d05SStephen Smalley 	if (unlikely(!tclass)) {
1188aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
118919439d05SStephen Smalley 			goto allow;
119019439d05SStephen Smalley 		goto out;
119119439d05SStephen Smalley 	}
119219439d05SStephen Smalley 
1193aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1194aa8e712cSStephen Smalley 				  NULL);
119519439d05SStephen Smalley  out:
1196aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
119719439d05SStephen Smalley 	return;
119819439d05SStephen Smalley allow:
119919439d05SStephen Smalley 	avd->allowed = 0xffffffff;
120019439d05SStephen Smalley 	goto out;
12011da177e4SLinus Torvalds }
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds /*
12041da177e4SLinus Torvalds  * Write the security context string representation of
12051da177e4SLinus Torvalds  * the context structure `context' into a dynamically
12061da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
12071da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
12081da177e4SLinus Torvalds  * the length of the string.
12091da177e4SLinus Torvalds  */
1210aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p,
1211aa8e712cSStephen Smalley 				    struct context *context,
1212aa8e712cSStephen Smalley 				    char **scontext, u32 *scontext_len)
12131da177e4SLinus Torvalds {
12141da177e4SLinus Torvalds 	char *scontextp;
12151da177e4SLinus Torvalds 
1216d5630b9dSEric Paris 	if (scontext)
12171da177e4SLinus Torvalds 		*scontext = NULL;
12181da177e4SLinus Torvalds 	*scontext_len = 0;
12191da177e4SLinus Torvalds 
122012b29f34SStephen Smalley 	if (context->len) {
122112b29f34SStephen Smalley 		*scontext_len = context->len;
1222bb7081abSEric Paris 		if (scontext) {
122312b29f34SStephen Smalley 			*scontext = kstrdup(context->str, GFP_ATOMIC);
122412b29f34SStephen Smalley 			if (!(*scontext))
122512b29f34SStephen Smalley 				return -ENOMEM;
1226bb7081abSEric Paris 		}
122712b29f34SStephen Smalley 		return 0;
122812b29f34SStephen Smalley 	}
122912b29f34SStephen Smalley 
12301da177e4SLinus Torvalds 	/* Compute the size of the context. */
1231aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1232aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1233aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1234aa8e712cSStephen Smalley 	*scontext_len += mls_compute_context_len(p, context);
12351da177e4SLinus Torvalds 
1236d5630b9dSEric Paris 	if (!scontext)
1237d5630b9dSEric Paris 		return 0;
1238d5630b9dSEric Paris 
12391da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
12401da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12415d55a345SEric Paris 	if (!scontextp)
12421da177e4SLinus Torvalds 		return -ENOMEM;
12431da177e4SLinus Torvalds 	*scontext = scontextp;
12441da177e4SLinus Torvalds 
12451da177e4SLinus Torvalds 	/*
12461da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
12471da177e4SLinus Torvalds 	 */
12489529c788SRasmus Villemoes 	scontextp += sprintf(scontextp, "%s:%s:%s",
1249aa8e712cSStephen Smalley 		sym_name(p, SYM_USERS, context->user - 1),
1250aa8e712cSStephen Smalley 		sym_name(p, SYM_ROLES, context->role - 1),
1251aa8e712cSStephen Smalley 		sym_name(p, SYM_TYPES, context->type - 1));
12521da177e4SLinus Torvalds 
1253aa8e712cSStephen Smalley 	mls_sid_to_context(p, context, &scontextp);
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 	*scontextp = 0;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	return 0;
12581da177e4SLinus Torvalds }
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12611da177e4SLinus Torvalds 
1262f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1263f0ee2e46SJames Carter {
1264f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1265f0ee2e46SJames Carter 		return NULL;
1266f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1267f0ee2e46SJames Carter }
1268f0ee2e46SJames Carter 
1269aa8e712cSStephen Smalley static int security_sid_to_context_core(struct selinux_state *state,
1270aa8e712cSStephen Smalley 					u32 sid, char **scontext,
1271fede1483SOndrej Mosnacek 					u32 *scontext_len, int force,
1272fede1483SOndrej Mosnacek 					int only_invalid)
12731da177e4SLinus Torvalds {
1274aa8e712cSStephen Smalley 	struct policydb *policydb;
1275aa8e712cSStephen Smalley 	struct sidtab *sidtab;
12761da177e4SLinus Torvalds 	struct context *context;
12771da177e4SLinus Torvalds 	int rc = 0;
12781da177e4SLinus Torvalds 
1279d5630b9dSEric Paris 	if (scontext)
12804f4acf3aSStephen Smalley 		*scontext = NULL;
12814f4acf3aSStephen Smalley 	*scontext_len  = 0;
12824f4acf3aSStephen Smalley 
1283aa8e712cSStephen Smalley 	if (!state->initialized) {
12841da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
12851da177e4SLinus Torvalds 			char *scontextp;
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
1288d5630b9dSEric Paris 			if (!scontext)
1289d5630b9dSEric Paris 				goto out;
1290aa736c36SRasmus Villemoes 			scontextp = kmemdup(initial_sid_to_string[sid],
1291aa736c36SRasmus Villemoes 					    *scontext_len, GFP_ATOMIC);
12920cccca06SSerge E. Hallyn 			if (!scontextp) {
12930cccca06SSerge E. Hallyn 				rc = -ENOMEM;
12940cccca06SSerge E. Hallyn 				goto out;
12950cccca06SSerge E. Hallyn 			}
12961da177e4SLinus Torvalds 			*scontext = scontextp;
12971da177e4SLinus Torvalds 			goto out;
12981da177e4SLinus Torvalds 		}
1299b54c85c1Speter enderborg 		pr_err("SELinux: %s:  called before initial "
1300744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
13011da177e4SLinus Torvalds 		rc = -EINVAL;
13021da177e4SLinus Torvalds 		goto out;
13031da177e4SLinus Torvalds 	}
1304aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
1305aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
130624ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
130712b29f34SStephen Smalley 	if (force)
1308aa8e712cSStephen Smalley 		context = sidtab_search_force(sidtab, sid);
130912b29f34SStephen Smalley 	else
1310aa8e712cSStephen Smalley 		context = sidtab_search(sidtab, sid);
13111da177e4SLinus Torvalds 	if (!context) {
1312b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1313744ba35eSEric Paris 			__func__, sid);
13141da177e4SLinus Torvalds 		rc = -EINVAL;
13151da177e4SLinus Torvalds 		goto out_unlock;
13161da177e4SLinus Torvalds 	}
13179e0cfe28SOndrej Mosnacek 	if (only_invalid && !context->len)
1318fede1483SOndrej Mosnacek 		rc = 0;
13199e0cfe28SOndrej Mosnacek 	else
1320aa8e712cSStephen Smalley 		rc = context_struct_to_string(policydb, context, scontext,
1321aa8e712cSStephen Smalley 					      scontext_len);
13221da177e4SLinus Torvalds out_unlock:
1323aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
13241da177e4SLinus Torvalds out:
13251da177e4SLinus Torvalds 	return rc;
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds }
13281da177e4SLinus Torvalds 
132912b29f34SStephen Smalley /**
133012b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
133112b29f34SStephen Smalley  * @sid: security identifier, SID
133212b29f34SStephen Smalley  * @scontext: security context
133312b29f34SStephen Smalley  * @scontext_len: length in bytes
133412b29f34SStephen Smalley  *
133512b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
133612b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
133712b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
133812b29f34SStephen Smalley  */
1339aa8e712cSStephen Smalley int security_sid_to_context(struct selinux_state *state,
1340aa8e712cSStephen Smalley 			    u32 sid, char **scontext, u32 *scontext_len)
13411da177e4SLinus Torvalds {
1342aa8e712cSStephen Smalley 	return security_sid_to_context_core(state, sid, scontext,
1343fede1483SOndrej Mosnacek 					    scontext_len, 0, 0);
134412b29f34SStephen Smalley }
134512b29f34SStephen Smalley 
1346aa8e712cSStephen Smalley int security_sid_to_context_force(struct selinux_state *state, u32 sid,
1347aa8e712cSStephen Smalley 				  char **scontext, u32 *scontext_len)
134812b29f34SStephen Smalley {
1349aa8e712cSStephen Smalley 	return security_sid_to_context_core(state, sid, scontext,
1350fede1483SOndrej Mosnacek 					    scontext_len, 1, 0);
1351fede1483SOndrej Mosnacek }
1352fede1483SOndrej Mosnacek 
1353fede1483SOndrej Mosnacek /**
1354fede1483SOndrej Mosnacek  * security_sid_to_context_inval - Obtain a context for a given SID if it
1355fede1483SOndrej Mosnacek  *                                 is invalid.
1356fede1483SOndrej Mosnacek  * @sid: security identifier, SID
1357fede1483SOndrej Mosnacek  * @scontext: security context
1358fede1483SOndrej Mosnacek  * @scontext_len: length in bytes
1359fede1483SOndrej Mosnacek  *
1360fede1483SOndrej Mosnacek  * Write the string representation of the context associated with @sid
1361fede1483SOndrej Mosnacek  * into a dynamically allocated string of the correct size, but only if the
1362fede1483SOndrej Mosnacek  * context is invalid in the current policy.  Set @scontext to point to
1363fede1483SOndrej Mosnacek  * this string (or NULL if the context is valid) and set @scontext_len to
1364fede1483SOndrej Mosnacek  * the length of the string (or 0 if the context is valid).
1365fede1483SOndrej Mosnacek  */
1366fede1483SOndrej Mosnacek int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
1367fede1483SOndrej Mosnacek 				  char **scontext, u32 *scontext_len)
1368fede1483SOndrej Mosnacek {
1369fede1483SOndrej Mosnacek 	return security_sid_to_context_core(state, sid, scontext,
1370fede1483SOndrej Mosnacek 					    scontext_len, 1, 1);
137112b29f34SStephen Smalley }
137212b29f34SStephen Smalley 
13739a59daa0SStephen Smalley /*
13749a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
13759a59daa0SStephen Smalley  */
137612b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
137712b29f34SStephen Smalley 				    struct sidtab *sidtabp,
13789a59daa0SStephen Smalley 				    char *scontext,
137912b29f34SStephen Smalley 				    struct context *ctx,
13809a59daa0SStephen Smalley 				    u32 def_sid)
138112b29f34SStephen Smalley {
13821da177e4SLinus Torvalds 	struct role_datum *role;
13831da177e4SLinus Torvalds 	struct type_datum *typdatum;
13841da177e4SLinus Torvalds 	struct user_datum *usrdatum;
13851da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
13861da177e4SLinus Torvalds 	int rc = 0;
13871da177e4SLinus Torvalds 
138812b29f34SStephen Smalley 	context_init(ctx);
138912b29f34SStephen Smalley 
139012b29f34SStephen Smalley 	/* Parse the security context. */
139112b29f34SStephen Smalley 
139212b29f34SStephen Smalley 	rc = -EINVAL;
13939a59daa0SStephen Smalley 	scontextp = (char *) scontext;
139412b29f34SStephen Smalley 
139512b29f34SStephen Smalley 	/* Extract the user. */
139612b29f34SStephen Smalley 	p = scontextp;
139712b29f34SStephen Smalley 	while (*p && *p != ':')
139812b29f34SStephen Smalley 		p++;
139912b29f34SStephen Smalley 
140012b29f34SStephen Smalley 	if (*p == 0)
140112b29f34SStephen Smalley 		goto out;
140212b29f34SStephen Smalley 
140312b29f34SStephen Smalley 	*p++ = 0;
140412b29f34SStephen Smalley 
140512b29f34SStephen Smalley 	usrdatum = hashtab_search(pol->p_users.table, scontextp);
140612b29f34SStephen Smalley 	if (!usrdatum)
140712b29f34SStephen Smalley 		goto out;
140812b29f34SStephen Smalley 
140912b29f34SStephen Smalley 	ctx->user = usrdatum->value;
141012b29f34SStephen Smalley 
141112b29f34SStephen Smalley 	/* Extract role. */
141212b29f34SStephen Smalley 	scontextp = p;
141312b29f34SStephen Smalley 	while (*p && *p != ':')
141412b29f34SStephen Smalley 		p++;
141512b29f34SStephen Smalley 
141612b29f34SStephen Smalley 	if (*p == 0)
141712b29f34SStephen Smalley 		goto out;
141812b29f34SStephen Smalley 
141912b29f34SStephen Smalley 	*p++ = 0;
142012b29f34SStephen Smalley 
142112b29f34SStephen Smalley 	role = hashtab_search(pol->p_roles.table, scontextp);
142212b29f34SStephen Smalley 	if (!role)
142312b29f34SStephen Smalley 		goto out;
142412b29f34SStephen Smalley 	ctx->role = role->value;
142512b29f34SStephen Smalley 
142612b29f34SStephen Smalley 	/* Extract type. */
142712b29f34SStephen Smalley 	scontextp = p;
142812b29f34SStephen Smalley 	while (*p && *p != ':')
142912b29f34SStephen Smalley 		p++;
143012b29f34SStephen Smalley 	oldc = *p;
143112b29f34SStephen Smalley 	*p++ = 0;
143212b29f34SStephen Smalley 
143312b29f34SStephen Smalley 	typdatum = hashtab_search(pol->p_types.table, scontextp);
1434d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
143512b29f34SStephen Smalley 		goto out;
143612b29f34SStephen Smalley 
143712b29f34SStephen Smalley 	ctx->type = typdatum->value;
143812b29f34SStephen Smalley 
143995ffe194SJann Horn 	rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
144012b29f34SStephen Smalley 	if (rc)
144112b29f34SStephen Smalley 		goto out;
144212b29f34SStephen Smalley 
144312b29f34SStephen Smalley 	/* Check the validity of the new context. */
144495ffe194SJann Horn 	rc = -EINVAL;
14454b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
144612b29f34SStephen Smalley 		goto out;
144712b29f34SStephen Smalley 	rc = 0;
144812b29f34SStephen Smalley out:
14498e531af9SEric Paris 	if (rc)
14508e531af9SEric Paris 		context_destroy(ctx);
145112b29f34SStephen Smalley 	return rc;
145212b29f34SStephen Smalley }
145312b29f34SStephen Smalley 
1454aa8e712cSStephen Smalley static int security_context_to_sid_core(struct selinux_state *state,
1455aa8e712cSStephen Smalley 					const char *scontext, u32 scontext_len,
145612b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
145712b29f34SStephen Smalley 					int force)
145812b29f34SStephen Smalley {
1459aa8e712cSStephen Smalley 	struct policydb *policydb;
1460aa8e712cSStephen Smalley 	struct sidtab *sidtab;
14619a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
146212b29f34SStephen Smalley 	struct context context;
146312b29f34SStephen Smalley 	int rc = 0;
146412b29f34SStephen Smalley 
14652172fa70SStephen Smalley 	/* An empty security context is never valid. */
14662172fa70SStephen Smalley 	if (!scontext_len)
14672172fa70SStephen Smalley 		return -EINVAL;
14682172fa70SStephen Smalley 
1469ef28df55SPaul Moore 	/* Copy the string to allow changes and ensure a NUL terminator */
1470ef28df55SPaul Moore 	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1471ef28df55SPaul Moore 	if (!scontext2)
1472ef28df55SPaul Moore 		return -ENOMEM;
1473ef28df55SPaul Moore 
1474aa8e712cSStephen Smalley 	if (!state->initialized) {
14751da177e4SLinus Torvalds 		int i;
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
1478ef28df55SPaul Moore 			if (!strcmp(initial_sid_to_string[i], scontext2)) {
14791da177e4SLinus Torvalds 				*sid = i;
1480ef28df55SPaul Moore 				goto out;
14811da177e4SLinus Torvalds 			}
14821da177e4SLinus Torvalds 		}
14831da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
1484ef28df55SPaul Moore 		goto out;
14851da177e4SLinus Torvalds 	}
14861da177e4SLinus Torvalds 	*sid = SECSID_NULL;
14871da177e4SLinus Torvalds 
14889a59daa0SStephen Smalley 	if (force) {
14899a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
14904b02b524SEric Paris 		rc = -ENOMEM;
14919a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
14924b02b524SEric Paris 		if (!str)
14934b02b524SEric Paris 			goto out;
14949a59daa0SStephen Smalley 	}
1495aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
1496aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
149724ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
1498aa8e712cSStephen Smalley 	rc = string_to_context_struct(policydb, sidtab, scontext2,
149995ffe194SJann Horn 				      &context, def_sid);
150012b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
15019a59daa0SStephen Smalley 		context.str = str;
1502efe3de79SSachin Grover 		context.len = strlen(str) + 1;
15039a59daa0SStephen Smalley 		str = NULL;
150412b29f34SStephen Smalley 	} else if (rc)
15054b02b524SEric Paris 		goto out_unlock;
1506aa8e712cSStephen Smalley 	rc = sidtab_context_to_sid(sidtab, &context, sid);
15071da177e4SLinus Torvalds 	context_destroy(&context);
15084b02b524SEric Paris out_unlock:
1509aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
15104b02b524SEric Paris out:
15119a59daa0SStephen Smalley 	kfree(scontext2);
15129a59daa0SStephen Smalley 	kfree(str);
15131da177e4SLinus Torvalds 	return rc;
15141da177e4SLinus Torvalds }
15151da177e4SLinus Torvalds 
1516f5c1d5b2SJames Morris /**
1517f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1518f5c1d5b2SJames Morris  * @scontext: security context
1519f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1520f5c1d5b2SJames Morris  * @sid: security identifier, SID
152152a4c640SNikolay Aleksandrov  * @gfp: context for the allocation
1522f5c1d5b2SJames Morris  *
1523f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1524f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1525f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1526f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1527f5c1d5b2SJames Morris  */
1528aa8e712cSStephen Smalley int security_context_to_sid(struct selinux_state *state,
1529aa8e712cSStephen Smalley 			    const char *scontext, u32 scontext_len, u32 *sid,
153052a4c640SNikolay Aleksandrov 			    gfp_t gfp)
1531f5c1d5b2SJames Morris {
1532aa8e712cSStephen Smalley 	return security_context_to_sid_core(state, scontext, scontext_len,
153352a4c640SNikolay Aleksandrov 					    sid, SECSID_NULL, gfp, 0);
1534f5c1d5b2SJames Morris }
1535f5c1d5b2SJames Morris 
1536aa8e712cSStephen Smalley int security_context_str_to_sid(struct selinux_state *state,
1537aa8e712cSStephen Smalley 				const char *scontext, u32 *sid, gfp_t gfp)
153844be2f65SRasmus Villemoes {
1539aa8e712cSStephen Smalley 	return security_context_to_sid(state, scontext, strlen(scontext),
1540aa8e712cSStephen Smalley 				       sid, gfp);
154144be2f65SRasmus Villemoes }
154244be2f65SRasmus Villemoes 
1543f5c1d5b2SJames Morris /**
1544f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1545f5c1d5b2SJames Morris  * falling back to specified default if needed.
1546f5c1d5b2SJames Morris  *
1547f5c1d5b2SJames Morris  * @scontext: security context
1548f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1549f5c1d5b2SJames Morris  * @sid: security identifier, SID
1550d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1551f5c1d5b2SJames Morris  *
1552f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1553f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1554f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1555f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1556f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
155712b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1558f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1559f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1560f5c1d5b2SJames Morris  */
1561aa8e712cSStephen Smalley int security_context_to_sid_default(struct selinux_state *state,
1562aa8e712cSStephen Smalley 				    const char *scontext, u32 scontext_len,
15637bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1564f5c1d5b2SJames Morris {
1565aa8e712cSStephen Smalley 	return security_context_to_sid_core(state, scontext, scontext_len,
156612b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
156712b29f34SStephen Smalley }
156812b29f34SStephen Smalley 
1569aa8e712cSStephen Smalley int security_context_to_sid_force(struct selinux_state *state,
1570aa8e712cSStephen Smalley 				  const char *scontext, u32 scontext_len,
157112b29f34SStephen Smalley 				  u32 *sid)
157212b29f34SStephen Smalley {
1573aa8e712cSStephen Smalley 	return security_context_to_sid_core(state, scontext, scontext_len,
157412b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1575f5c1d5b2SJames Morris }
1576f5c1d5b2SJames Morris 
15771da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
1578aa8e712cSStephen Smalley 	struct selinux_state *state,
15791da177e4SLinus Torvalds 	struct context *scontext,
15801da177e4SLinus Torvalds 	struct context *tcontext,
15811da177e4SLinus Torvalds 	u16 tclass,
15821da177e4SLinus Torvalds 	struct context *newcontext)
15831da177e4SLinus Torvalds {
1584aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
15851da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
15861da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
1587ea74a685SRichard Guy Briggs 	struct audit_buffer *ab;
15881da177e4SLinus Torvalds 
1589aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, scontext, &s, &slen))
15901da177e4SLinus Torvalds 		goto out;
1591aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, tcontext, &t, &tlen))
15921da177e4SLinus Torvalds 		goto out;
1593aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
15941da177e4SLinus Torvalds 		goto out;
1595ea74a685SRichard Guy Briggs 	ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1596ea74a685SRichard Guy Briggs 	audit_log_format(ab,
1597ea74a685SRichard Guy Briggs 			 "op=security_compute_sid invalid_context=");
1598ea74a685SRichard Guy Briggs 	/* no need to record the NUL with untrusted strings */
1599ea74a685SRichard Guy Briggs 	audit_log_n_untrustedstring(ab, n, nlen - 1);
1600ea74a685SRichard Guy Briggs 	audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1601ea74a685SRichard Guy Briggs 			 s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1602ea74a685SRichard Guy Briggs 	audit_log_end(ab);
16031da177e4SLinus Torvalds out:
16041da177e4SLinus Torvalds 	kfree(s);
16051da177e4SLinus Torvalds 	kfree(t);
16061da177e4SLinus Torvalds 	kfree(n);
1607e5a5ca96SPaul Moore 	if (!enforcing_enabled(state))
16081da177e4SLinus Torvalds 		return 0;
16091da177e4SLinus Torvalds 	return -EACCES;
16101da177e4SLinus Torvalds }
16111da177e4SLinus Torvalds 
1612aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb,
1613aa8e712cSStephen Smalley 				  struct context *newcontext,
16142667991fSEric Paris 				  u32 stype, u32 ttype, u16 tclass,
1615f50a3ec9SKohei Kaigai 				  const char *objname)
1616652bb9b0SEric Paris {
16172463c26dSEric Paris 	struct filename_trans ft;
16182463c26dSEric Paris 	struct filename_trans_datum *otype;
161903a4c018SEric Paris 
162003a4c018SEric Paris 	/*
162103a4c018SEric Paris 	 * Most filename trans rules are going to live in specific directories
162203a4c018SEric Paris 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
162303a4c018SEric Paris 	 * if the ttype does not contain any rules.
162403a4c018SEric Paris 	 */
1625aa8e712cSStephen Smalley 	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1626652bb9b0SEric Paris 		return;
162703a4c018SEric Paris 
16282463c26dSEric Paris 	ft.stype = stype;
16292463c26dSEric Paris 	ft.ttype = ttype;
16302463c26dSEric Paris 	ft.tclass = tclass;
16312463c26dSEric Paris 	ft.name = objname;
16322463c26dSEric Paris 
1633aa8e712cSStephen Smalley 	otype = hashtab_search(policydb->filename_trans, &ft);
16342463c26dSEric Paris 	if (otype)
16352463c26dSEric Paris 		newcontext->type = otype->otype;
1636652bb9b0SEric Paris }
1637652bb9b0SEric Paris 
1638aa8e712cSStephen Smalley static int security_compute_sid(struct selinux_state *state,
1639aa8e712cSStephen Smalley 				u32 ssid,
16401da177e4SLinus Torvalds 				u32 tsid,
1641c6d3aaa4SStephen Smalley 				u16 orig_tclass,
16421da177e4SLinus Torvalds 				u32 specified,
1643f50a3ec9SKohei Kaigai 				const char *objname,
1644c6d3aaa4SStephen Smalley 				u32 *out_sid,
1645c6d3aaa4SStephen Smalley 				bool kern)
16461da177e4SLinus Torvalds {
1647aa8e712cSStephen Smalley 	struct policydb *policydb;
1648aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1649aa893269SEric Paris 	struct class_datum *cladatum = NULL;
16501da177e4SLinus Torvalds 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
16511da177e4SLinus Torvalds 	struct role_trans *roletr = NULL;
16521da177e4SLinus Torvalds 	struct avtab_key avkey;
16531da177e4SLinus Torvalds 	struct avtab_datum *avdatum;
16541da177e4SLinus Torvalds 	struct avtab_node *node;
1655c6d3aaa4SStephen Smalley 	u16 tclass;
16561da177e4SLinus Torvalds 	int rc = 0;
16576f5317e7SHarry Ciao 	bool sock;
16581da177e4SLinus Torvalds 
1659aa8e712cSStephen Smalley 	if (!state->initialized) {
1660c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1661c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
16621da177e4SLinus Torvalds 			*out_sid = ssid;
16631da177e4SLinus Torvalds 			break;
16641da177e4SLinus Torvalds 		default:
16651da177e4SLinus Torvalds 			*out_sid = tsid;
16661da177e4SLinus Torvalds 			break;
16671da177e4SLinus Torvalds 		}
16681da177e4SLinus Torvalds 		goto out;
16691da177e4SLinus Torvalds 	}
16701da177e4SLinus Torvalds 
1671851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1672851f8a69SVenkat Yekkirala 
1673aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
16741da177e4SLinus Torvalds 
16756f5317e7SHarry Ciao 	if (kern) {
1676aa8e712cSStephen Smalley 		tclass = unmap_class(&state->ss->map, orig_tclass);
16776f5317e7SHarry Ciao 		sock = security_is_socket_class(orig_tclass);
16786f5317e7SHarry Ciao 	} else {
1679c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
1680aa8e712cSStephen Smalley 		sock = security_is_socket_class(map_class(&state->ss->map,
1681aa8e712cSStephen Smalley 							  tclass));
16826f5317e7SHarry Ciao 	}
1683c6d3aaa4SStephen Smalley 
1684aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
168524ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
1686aa8e712cSStephen Smalley 
1687aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
16881da177e4SLinus Torvalds 	if (!scontext) {
1689b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1690744ba35eSEric Paris 		       __func__, ssid);
16911da177e4SLinus Torvalds 		rc = -EINVAL;
16921da177e4SLinus Torvalds 		goto out_unlock;
16931da177e4SLinus Torvalds 	}
1694aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
16951da177e4SLinus Torvalds 	if (!tcontext) {
1696b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1697744ba35eSEric Paris 		       __func__, tsid);
16981da177e4SLinus Torvalds 		rc = -EINVAL;
16991da177e4SLinus Torvalds 		goto out_unlock;
17001da177e4SLinus Torvalds 	}
17011da177e4SLinus Torvalds 
1702aa8e712cSStephen Smalley 	if (tclass && tclass <= policydb->p_classes.nprim)
1703aa8e712cSStephen Smalley 		cladatum = policydb->class_val_to_struct[tclass - 1];
1704aa893269SEric Paris 
17051da177e4SLinus Torvalds 	/* Set the user identity. */
17061da177e4SLinus Torvalds 	switch (specified) {
17071da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
17081da177e4SLinus Torvalds 	case AVTAB_CHANGE:
1709aa893269SEric Paris 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1710aa893269SEric Paris 			newcontext.user = tcontext->user;
1711aa893269SEric Paris 		} else {
1712aa893269SEric Paris 			/* notice this gets both DEFAULT_SOURCE and unset */
17131da177e4SLinus Torvalds 			/* Use the process user identity. */
17141da177e4SLinus Torvalds 			newcontext.user = scontext->user;
1715aa893269SEric Paris 		}
17161da177e4SLinus Torvalds 		break;
17171da177e4SLinus Torvalds 	case AVTAB_MEMBER:
17181da177e4SLinus Torvalds 		/* Use the related object owner. */
17191da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
17201da177e4SLinus Torvalds 		break;
17211da177e4SLinus Torvalds 	}
17221da177e4SLinus Torvalds 
1723aa893269SEric Paris 	/* Set the role to default values. */
1724aa893269SEric Paris 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
17251da177e4SLinus Torvalds 		newcontext.role = scontext->role;
1726aa893269SEric Paris 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1727aa893269SEric Paris 		newcontext.role = tcontext->role;
1728aa893269SEric Paris 	} else {
1729aa8e712cSStephen Smalley 		if ((tclass == policydb->process_class) || (sock == true))
1730aa893269SEric Paris 			newcontext.role = scontext->role;
1731aa893269SEric Paris 		else
1732aa893269SEric Paris 			newcontext.role = OBJECT_R_VAL;
1733aa893269SEric Paris 	}
1734aa893269SEric Paris 
1735aa893269SEric Paris 	/* Set the type to default values. */
1736eed7795dSEric Paris 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1737eed7795dSEric Paris 		newcontext.type = scontext->type;
1738eed7795dSEric Paris 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1739eed7795dSEric Paris 		newcontext.type = tcontext->type;
1740eed7795dSEric Paris 	} else {
1741aa8e712cSStephen Smalley 		if ((tclass == policydb->process_class) || (sock == true)) {
1742aa893269SEric Paris 			/* Use the type of process. */
17431da177e4SLinus Torvalds 			newcontext.type = scontext->type;
1744c6d3aaa4SStephen Smalley 		} else {
17451da177e4SLinus Torvalds 			/* Use the type of the related object. */
17461da177e4SLinus Torvalds 			newcontext.type = tcontext->type;
17471da177e4SLinus Torvalds 		}
1748eed7795dSEric Paris 	}
17491da177e4SLinus Torvalds 
17501da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
17511da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
17521da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
17531da177e4SLinus Torvalds 	avkey.target_class = tclass;
1754782ebb99SStephen Smalley 	avkey.specified = specified;
1755aa8e712cSStephen Smalley 	avdatum = avtab_search(&policydb->te_avtab, &avkey);
17561da177e4SLinus Torvalds 
17571da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
17581da177e4SLinus Torvalds 	if (!avdatum) {
1759aa8e712cSStephen Smalley 		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1760dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1761782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
17621da177e4SLinus Torvalds 				avdatum = &node->datum;
17631da177e4SLinus Torvalds 				break;
17641da177e4SLinus Torvalds 			}
17651da177e4SLinus Torvalds 		}
17661da177e4SLinus Torvalds 	}
17671da177e4SLinus Torvalds 
1768782ebb99SStephen Smalley 	if (avdatum) {
17691da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
1770fa1aa143SJeff Vander Stoep 		newcontext.type = avdatum->u.data;
17711da177e4SLinus Torvalds 	}
17721da177e4SLinus Torvalds 
17734742600cSEric Paris 	/* if we have a objname this is a file trans check so check those rules */
1774f50a3ec9SKohei Kaigai 	if (objname)
1775aa8e712cSStephen Smalley 		filename_compute_type(policydb, &newcontext, scontext->type,
1776f50a3ec9SKohei Kaigai 				      tcontext->type, tclass, objname);
1777652bb9b0SEric Paris 
17781da177e4SLinus Torvalds 	/* Check for class-specific changes. */
17791da177e4SLinus Torvalds 	if (specified & AVTAB_TRANSITION) {
17801da177e4SLinus Torvalds 		/* Look for a role transition rule. */
1781aa8e712cSStephen Smalley 		for (roletr = policydb->role_tr; roletr;
1782aa8e712cSStephen Smalley 		     roletr = roletr->next) {
178363a312caSHarry Ciao 			if ((roletr->role == scontext->role) &&
178463a312caSHarry Ciao 			    (roletr->type == tcontext->type) &&
178563a312caSHarry Ciao 			    (roletr->tclass == tclass)) {
17861da177e4SLinus Torvalds 				/* Use the role transition rule. */
17871da177e4SLinus Torvalds 				newcontext.role = roletr->new_role;
17881da177e4SLinus Torvalds 				break;
17891da177e4SLinus Torvalds 			}
17901da177e4SLinus Torvalds 		}
17911da177e4SLinus Torvalds 	}
17921da177e4SLinus Torvalds 
17931da177e4SLinus Torvalds 	/* Set the MLS attributes.
17941da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
1795aa8e712cSStephen Smalley 	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
17966f5317e7SHarry Ciao 			     &newcontext, sock);
17971da177e4SLinus Torvalds 	if (rc)
17981da177e4SLinus Torvalds 		goto out_unlock;
17991da177e4SLinus Torvalds 
18001da177e4SLinus Torvalds 	/* Check the validity of the context. */
1801aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcontext)) {
1802aa8e712cSStephen Smalley 		rc = compute_sid_handle_invalid_context(state, scontext,
18031da177e4SLinus Torvalds 							tcontext,
18041da177e4SLinus Torvalds 							tclass,
18051da177e4SLinus Torvalds 							&newcontext);
18061da177e4SLinus Torvalds 		if (rc)
18071da177e4SLinus Torvalds 			goto out_unlock;
18081da177e4SLinus Torvalds 	}
18091da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
1810aa8e712cSStephen Smalley 	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
18111da177e4SLinus Torvalds out_unlock:
1812aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
18131da177e4SLinus Torvalds 	context_destroy(&newcontext);
18141da177e4SLinus Torvalds out:
18151da177e4SLinus Torvalds 	return rc;
18161da177e4SLinus Torvalds }
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds /**
18191da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
18201da177e4SLinus Torvalds  * @ssid: source security identifier
18211da177e4SLinus Torvalds  * @tsid: target security identifier
18221da177e4SLinus Torvalds  * @tclass: target security class
18231da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
18241da177e4SLinus Torvalds  *
18251da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
18261da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
18271da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18281da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
18291da177e4SLinus Torvalds  * computed successfully.
18301da177e4SLinus Torvalds  */
1831aa8e712cSStephen Smalley int security_transition_sid(struct selinux_state *state,
1832aa8e712cSStephen Smalley 			    u32 ssid, u32 tsid, u16 tclass,
1833652bb9b0SEric Paris 			    const struct qstr *qstr, u32 *out_sid)
18341da177e4SLinus Torvalds {
1835aa8e712cSStephen Smalley 	return security_compute_sid(state, ssid, tsid, tclass,
1836aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1837f50a3ec9SKohei Kaigai 				    qstr ? qstr->name : NULL, out_sid, true);
1838c6d3aaa4SStephen Smalley }
1839c6d3aaa4SStephen Smalley 
1840aa8e712cSStephen Smalley int security_transition_sid_user(struct selinux_state *state,
1841aa8e712cSStephen Smalley 				 u32 ssid, u32 tsid, u16 tclass,
1842f50a3ec9SKohei Kaigai 				 const char *objname, u32 *out_sid)
1843c6d3aaa4SStephen Smalley {
1844aa8e712cSStephen Smalley 	return security_compute_sid(state, ssid, tsid, tclass,
1845aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1846f50a3ec9SKohei Kaigai 				    objname, out_sid, false);
18471da177e4SLinus Torvalds }
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds /**
18501da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
18511da177e4SLinus Torvalds  * @ssid: source security identifier
18521da177e4SLinus Torvalds  * @tsid: target security identifier
18531da177e4SLinus Torvalds  * @tclass: target security class
18541da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
18551da177e4SLinus Torvalds  *
18561da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
18571da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
18581da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18591da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
18601da177e4SLinus Torvalds  * computed successfully.
18611da177e4SLinus Torvalds  */
1862aa8e712cSStephen Smalley int security_member_sid(struct selinux_state *state,
1863aa8e712cSStephen Smalley 			u32 ssid,
18641da177e4SLinus Torvalds 			u32 tsid,
18651da177e4SLinus Torvalds 			u16 tclass,
18661da177e4SLinus Torvalds 			u32 *out_sid)
18671da177e4SLinus Torvalds {
1868aa8e712cSStephen Smalley 	return security_compute_sid(state, ssid, tsid, tclass,
1869aa8e712cSStephen Smalley 				    AVTAB_MEMBER, NULL,
1870652bb9b0SEric Paris 				    out_sid, false);
18711da177e4SLinus Torvalds }
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds /**
18741da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
18751da177e4SLinus Torvalds  * @ssid: source security identifier
18761da177e4SLinus Torvalds  * @tsid: target security identifier
18771da177e4SLinus Torvalds  * @tclass: target security class
18781da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
18791da177e4SLinus Torvalds  *
18801da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
18811da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
18821da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18831da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
18841da177e4SLinus Torvalds  * computed successfully.
18851da177e4SLinus Torvalds  */
1886aa8e712cSStephen Smalley int security_change_sid(struct selinux_state *state,
1887aa8e712cSStephen Smalley 			u32 ssid,
18881da177e4SLinus Torvalds 			u32 tsid,
18891da177e4SLinus Torvalds 			u16 tclass,
18901da177e4SLinus Torvalds 			u32 *out_sid)
18911da177e4SLinus Torvalds {
1892aa8e712cSStephen Smalley 	return security_compute_sid(state,
1893aa8e712cSStephen Smalley 				    ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1894652bb9b0SEric Paris 				    out_sid, false);
1895b94c7e67SChad Sellers }
1896b94c7e67SChad Sellers 
1897aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context(
1898aa8e712cSStephen Smalley 	struct selinux_state *state,
1899aa8e712cSStephen Smalley 	struct context *context)
19001da177e4SLinus Torvalds {
1901aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
19021da177e4SLinus Torvalds 	char *s;
19031da177e4SLinus Torvalds 	u32 len;
19041da177e4SLinus Torvalds 
1905e5a5ca96SPaul Moore 	if (enforcing_enabled(state))
19064b02b524SEric Paris 		return -EINVAL;
19074b02b524SEric Paris 
1908aa8e712cSStephen Smalley 	if (!context_struct_to_string(policydb, context, &s, &len)) {
1909b54c85c1Speter enderborg 		pr_warn("SELinux:  Context %s would be invalid if enforcing\n",
1910b54c85c1Speter enderborg 			s);
19111da177e4SLinus Torvalds 		kfree(s);
19121da177e4SLinus Torvalds 	}
19134b02b524SEric Paris 	return 0;
19141da177e4SLinus Torvalds }
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds struct convert_context_args {
1917aa8e712cSStephen Smalley 	struct selinux_state *state;
19181da177e4SLinus Torvalds 	struct policydb *oldp;
19191da177e4SLinus Torvalds 	struct policydb *newp;
19201da177e4SLinus Torvalds };
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds /*
19231da177e4SLinus Torvalds  * Convert the values in the security context
1924ee1a84fdSOndrej Mosnacek  * structure `oldc' from the values specified
19251da177e4SLinus Torvalds  * in the policy `p->oldp' to the values specified
1926ee1a84fdSOndrej Mosnacek  * in the policy `p->newp', storing the new context
1927ee1a84fdSOndrej Mosnacek  * in `newc'.  Verify that the context is valid
1928ee1a84fdSOndrej Mosnacek  * under the new policy.
19291da177e4SLinus Torvalds  */
1930ee1a84fdSOndrej Mosnacek static int convert_context(struct context *oldc, struct context *newc, void *p)
19311da177e4SLinus Torvalds {
19321da177e4SLinus Torvalds 	struct convert_context_args *args;
19330719aaf5SGuido Trentalancia 	struct ocontext *oc;
19341da177e4SLinus Torvalds 	struct role_datum *role;
19351da177e4SLinus Torvalds 	struct type_datum *typdatum;
19361da177e4SLinus Torvalds 	struct user_datum *usrdatum;
19371da177e4SLinus Torvalds 	char *s;
19381da177e4SLinus Torvalds 	u32 len;
193924ed7fdaSOndrej Mosnacek 	int rc;
19401da177e4SLinus Torvalds 
19411da177e4SLinus Torvalds 	args = p;
19421da177e4SLinus Torvalds 
1943ee1a84fdSOndrej Mosnacek 	if (oldc->str) {
1944ee1a84fdSOndrej Mosnacek 		s = kstrdup(oldc->str, GFP_KERNEL);
19454b02b524SEric Paris 		if (!s)
1946ee1a84fdSOndrej Mosnacek 			return -ENOMEM;
19474b02b524SEric Paris 
19489a59daa0SStephen Smalley 		rc = string_to_context_struct(args->newp, NULL, s,
1949ee1a84fdSOndrej Mosnacek 					      newc, SECSID_NULL);
1950ee1a84fdSOndrej Mosnacek 		if (rc == -EINVAL) {
195112b29f34SStephen Smalley 			/* Retain string representation for later mapping. */
1952ee1a84fdSOndrej Mosnacek 			context_init(newc);
1953ee1a84fdSOndrej Mosnacek 			newc->str = s;
1954ee1a84fdSOndrej Mosnacek 			newc->len = oldc->len;
1955ee1a84fdSOndrej Mosnacek 			return 0;
1956ee1a84fdSOndrej Mosnacek 		}
1957ee1a84fdSOndrej Mosnacek 		kfree(s);
1958ee1a84fdSOndrej Mosnacek 		if (rc) {
195912b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
1960b54c85c1Speter enderborg 			pr_err("SELinux:   Unable to map context %s, rc = %d.\n",
1961ee1a84fdSOndrej Mosnacek 			       oldc->str, -rc);
1962ee1a84fdSOndrej Mosnacek 			return rc;
196312b29f34SStephen Smalley 		}
1964ee1a84fdSOndrej Mosnacek 		pr_info("SELinux:  Context %s became valid (mapped).\n",
1965ee1a84fdSOndrej Mosnacek 			oldc->str);
1966ee1a84fdSOndrej Mosnacek 		return 0;
196712b29f34SStephen Smalley 	}
196812b29f34SStephen Smalley 
1969ee1a84fdSOndrej Mosnacek 	context_init(newc);
19701da177e4SLinus Torvalds 
19711da177e4SLinus Torvalds 	/* Convert the user. */
19724b02b524SEric Paris 	rc = -EINVAL;
19731da177e4SLinus Torvalds 	usrdatum = hashtab_search(args->newp->p_users.table,
1974ee1a84fdSOndrej Mosnacek 				  sym_name(args->oldp,
1975ee1a84fdSOndrej Mosnacek 					   SYM_USERS, oldc->user - 1));
19765d55a345SEric Paris 	if (!usrdatum)
19771da177e4SLinus Torvalds 		goto bad;
1978ee1a84fdSOndrej Mosnacek 	newc->user = usrdatum->value;
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 	/* Convert the role. */
19814b02b524SEric Paris 	rc = -EINVAL;
19821da177e4SLinus Torvalds 	role = hashtab_search(args->newp->p_roles.table,
1983ee1a84fdSOndrej Mosnacek 			      sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
19845d55a345SEric Paris 	if (!role)
19851da177e4SLinus Torvalds 		goto bad;
1986ee1a84fdSOndrej Mosnacek 	newc->role = role->value;
19871da177e4SLinus Torvalds 
19881da177e4SLinus Torvalds 	/* Convert the type. */
19894b02b524SEric Paris 	rc = -EINVAL;
19901da177e4SLinus Torvalds 	typdatum = hashtab_search(args->newp->p_types.table,
1991ee1a84fdSOndrej Mosnacek 				  sym_name(args->oldp,
1992ee1a84fdSOndrej Mosnacek 					   SYM_TYPES, oldc->type - 1));
19935d55a345SEric Paris 	if (!typdatum)
19941da177e4SLinus Torvalds 		goto bad;
1995ee1a84fdSOndrej Mosnacek 	newc->type = typdatum->value;
19961da177e4SLinus Torvalds 
19970719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
19980719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
1999ee1a84fdSOndrej Mosnacek 		rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
20001da177e4SLinus Torvalds 		if (rc)
20011da177e4SLinus Torvalds 			goto bad;
20020719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
20030719aaf5SGuido Trentalancia 		/*
20040719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
20050719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
20060719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
20070719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
20080719aaf5SGuido Trentalancia 		 * initial SIDs.
20090719aaf5SGuido Trentalancia 		 */
20100719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
20110719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
20120719aaf5SGuido Trentalancia 			oc = oc->next;
20134b02b524SEric Paris 		rc = -EINVAL;
20140719aaf5SGuido Trentalancia 		if (!oc) {
2015b54c85c1Speter enderborg 			pr_err("SELinux:  unable to look up"
20160719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
20170719aaf5SGuido Trentalancia 			goto bad;
20180719aaf5SGuido Trentalancia 		}
2019ee1a84fdSOndrej Mosnacek 		rc = mls_range_set(newc, &oc->context[0].range);
20200719aaf5SGuido Trentalancia 		if (rc)
20210719aaf5SGuido Trentalancia 			goto bad;
20220719aaf5SGuido Trentalancia 	}
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 	/* Check the validity of the new context. */
2025ee1a84fdSOndrej Mosnacek 	if (!policydb_context_isvalid(args->newp, newc)) {
2026ee1a84fdSOndrej Mosnacek 		rc = convert_context_handle_invalid_context(args->state, oldc);
20271da177e4SLinus Torvalds 		if (rc)
20281da177e4SLinus Torvalds 			goto bad;
20291da177e4SLinus Torvalds 	}
20301da177e4SLinus Torvalds 
2031ee1a84fdSOndrej Mosnacek 	return 0;
20321da177e4SLinus Torvalds bad:
203312b29f34SStephen Smalley 	/* Map old representation to string and save it. */
2034ee1a84fdSOndrej Mosnacek 	rc = context_struct_to_string(args->oldp, oldc, &s, &len);
20354b02b524SEric Paris 	if (rc)
20364b02b524SEric Paris 		return rc;
2037ee1a84fdSOndrej Mosnacek 	context_destroy(newc);
2038ee1a84fdSOndrej Mosnacek 	newc->str = s;
2039ee1a84fdSOndrej Mosnacek 	newc->len = len;
2040b54c85c1Speter enderborg 	pr_info("SELinux:  Context %s became invalid (unmapped).\n",
2041ee1a84fdSOndrej Mosnacek 		newc->str);
2042ee1a84fdSOndrej Mosnacek 	return 0;
20431da177e4SLinus Torvalds }
20441da177e4SLinus Torvalds 
2045aa8e712cSStephen Smalley static void security_load_policycaps(struct selinux_state *state)
20463bb56b25SPaul Moore {
2047aa8e712cSStephen Smalley 	struct policydb *p = &state->ss->policydb;
20484dc2fce3SStephen Smalley 	unsigned int i;
20494dc2fce3SStephen Smalley 	struct ebitmap_node *node;
20504dc2fce3SStephen Smalley 
2051aa8e712cSStephen Smalley 	for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
2052aa8e712cSStephen Smalley 		state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
20534dc2fce3SStephen Smalley 
20544dc2fce3SStephen Smalley 	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
20554dc2fce3SStephen Smalley 		pr_info("SELinux:  policy capability %s=%d\n",
20564dc2fce3SStephen Smalley 			selinux_policycap_names[i],
2057aa8e712cSStephen Smalley 			ebitmap_get_bit(&p->policycaps, i));
20584dc2fce3SStephen Smalley 
2059aa8e712cSStephen Smalley 	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
20604dc2fce3SStephen Smalley 		if (i >= ARRAY_SIZE(selinux_policycap_names))
20614dc2fce3SStephen Smalley 			pr_info("SELinux:  unknown policy capability %u\n",
20624dc2fce3SStephen Smalley 				i);
20634dc2fce3SStephen Smalley 	}
20643bb56b25SPaul Moore }
20653bb56b25SPaul Moore 
2066aa8e712cSStephen Smalley static int security_preserve_bools(struct selinux_state *state,
2067aa8e712cSStephen Smalley 				   struct policydb *newpolicydb);
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds /**
20701da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
20711da177e4SLinus Torvalds  * @data: binary policy data
20721da177e4SLinus Torvalds  * @len: length of data in bytes
20731da177e4SLinus Torvalds  *
20741da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
20751da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
20761da177e4SLinus Torvalds  * This function will flush the access vector cache after
20771da177e4SLinus Torvalds  * loading the new policy.
20781da177e4SLinus Torvalds  */
2079aa8e712cSStephen Smalley int security_load_policy(struct selinux_state *state, void *data, size_t len)
20801da177e4SLinus Torvalds {
2081aa8e712cSStephen Smalley 	struct policydb *policydb;
208224ed7fdaSOndrej Mosnacek 	struct sidtab *oldsidtab, *newsidtab;
2083b5495b42STim Gardner 	struct policydb *oldpolicydb, *newpolicydb;
2084aa8e712cSStephen Smalley 	struct selinux_mapping *oldmapping;
2085aa8e712cSStephen Smalley 	struct selinux_map newmap;
2086ee1a84fdSOndrej Mosnacek 	struct sidtab_convert_params convert_params;
20871da177e4SLinus Torvalds 	struct convert_context_args args;
20881da177e4SLinus Torvalds 	u32 seqno;
20891da177e4SLinus Torvalds 	int rc = 0;
20901da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
20911da177e4SLinus Torvalds 
20926396bb22SKees Cook 	oldpolicydb = kcalloc(2, sizeof(*oldpolicydb), GFP_KERNEL);
2093b5495b42STim Gardner 	if (!oldpolicydb) {
2094b5495b42STim Gardner 		rc = -ENOMEM;
2095b5495b42STim Gardner 		goto out;
2096b5495b42STim Gardner 	}
2097b5495b42STim Gardner 	newpolicydb = oldpolicydb + 1;
2098b5495b42STim Gardner 
2099aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
210024ed7fdaSOndrej Mosnacek 
210124ed7fdaSOndrej Mosnacek 	newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL);
210224ed7fdaSOndrej Mosnacek 	if (!newsidtab) {
210324ed7fdaSOndrej Mosnacek 		rc = -ENOMEM;
210424ed7fdaSOndrej Mosnacek 		goto out;
210524ed7fdaSOndrej Mosnacek 	}
2106aa8e712cSStephen Smalley 
2107aa8e712cSStephen Smalley 	if (!state->initialized) {
2108aa8e712cSStephen Smalley 		rc = policydb_read(policydb, fp);
210924ed7fdaSOndrej Mosnacek 		if (rc) {
211024ed7fdaSOndrej Mosnacek 			kfree(newsidtab);
2111aa8e712cSStephen Smalley 			goto out;
211224ed7fdaSOndrej Mosnacek 		}
2113aa8e712cSStephen Smalley 
2114aa8e712cSStephen Smalley 		policydb->len = len;
2115aa8e712cSStephen Smalley 		rc = selinux_set_mapping(policydb, secclass_map,
2116aa8e712cSStephen Smalley 					 &state->ss->map);
2117a2000050SEric Paris 		if (rc) {
211824ed7fdaSOndrej Mosnacek 			kfree(newsidtab);
2119aa8e712cSStephen Smalley 			policydb_destroy(policydb);
2120b5495b42STim Gardner 			goto out;
21211da177e4SLinus Torvalds 		}
2122a2000050SEric Paris 
212324ed7fdaSOndrej Mosnacek 		rc = policydb_load_isids(policydb, newsidtab);
2124a2000050SEric Paris 		if (rc) {
212524ed7fdaSOndrej Mosnacek 			kfree(newsidtab);
2126aa8e712cSStephen Smalley 			policydb_destroy(policydb);
2127b5495b42STim Gardner 			goto out;
21281da177e4SLinus Torvalds 		}
2129a2000050SEric Paris 
213024ed7fdaSOndrej Mosnacek 		state->ss->sidtab = newsidtab;
2131aa8e712cSStephen Smalley 		security_load_policycaps(state);
2132aa8e712cSStephen Smalley 		state->initialized = 1;
2133aa8e712cSStephen Smalley 		seqno = ++state->ss->latest_granting;
21341da177e4SLinus Torvalds 		selinux_complete_init();
21356b6bc620SStephen Smalley 		avc_ss_reset(state->avc, seqno);
21364c443d1bSStephen Smalley 		selnl_notify_policyload(seqno);
2137aa8e712cSStephen Smalley 		selinux_status_update_policyload(state, seqno);
21387420ed23SVenkat Yekkirala 		selinux_netlbl_cache_invalidate();
2139342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
2140b5495b42STim Gardner 		goto out;
21411da177e4SLinus Torvalds 	}
21421da177e4SLinus Torvalds 
2143b5495b42STim Gardner 	rc = policydb_read(newpolicydb, fp);
214424ed7fdaSOndrej Mosnacek 	if (rc) {
214524ed7fdaSOndrej Mosnacek 		kfree(newsidtab);
2146b5495b42STim Gardner 		goto out;
214724ed7fdaSOndrej Mosnacek 	}
21481da177e4SLinus Torvalds 
2149b5495b42STim Gardner 	newpolicydb->len = len;
21500719aaf5SGuido Trentalancia 	/* If switching between different policy types, log MLS status */
2151aa8e712cSStephen Smalley 	if (policydb->mls_enabled && !newpolicydb->mls_enabled)
2152b54c85c1Speter enderborg 		pr_info("SELinux: Disabling MLS support...\n");
2153aa8e712cSStephen Smalley 	else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
2154b54c85c1Speter enderborg 		pr_info("SELinux: Enabling MLS support...\n");
21550719aaf5SGuido Trentalancia 
215624ed7fdaSOndrej Mosnacek 	rc = policydb_load_isids(newpolicydb, newsidtab);
215742596eafSGuido Trentalancia 	if (rc) {
2158b54c85c1Speter enderborg 		pr_err("SELinux:  unable to load the initial SIDs\n");
2159b5495b42STim Gardner 		policydb_destroy(newpolicydb);
216024ed7fdaSOndrej Mosnacek 		kfree(newsidtab);
2161b5495b42STim Gardner 		goto out;
216212b29f34SStephen Smalley 	}
21631da177e4SLinus Torvalds 
2164aa8e712cSStephen Smalley 	rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap);
2165a2000050SEric Paris 	if (rc)
2166b94c7e67SChad Sellers 		goto err;
2167b94c7e67SChad Sellers 
2168aa8e712cSStephen Smalley 	rc = security_preserve_bools(state, newpolicydb);
2169e900a7d9SStephen Smalley 	if (rc) {
2170b54c85c1Speter enderborg 		pr_err("SELinux:  unable to preserve booleans\n");
2171e900a7d9SStephen Smalley 		goto err;
2172e900a7d9SStephen Smalley 	}
2173e900a7d9SStephen Smalley 
2174ee1a84fdSOndrej Mosnacek 	oldsidtab = state->ss->sidtab;
2175ee1a84fdSOndrej Mosnacek 
217612b29f34SStephen Smalley 	/*
217712b29f34SStephen Smalley 	 * Convert the internal representations of contexts
217812b29f34SStephen Smalley 	 * in the new SID table.
217912b29f34SStephen Smalley 	 */
2180aa8e712cSStephen Smalley 	args.state = state;
2181aa8e712cSStephen Smalley 	args.oldp = policydb;
2182b5495b42STim Gardner 	args.newp = newpolicydb;
2183ee1a84fdSOndrej Mosnacek 
2184ee1a84fdSOndrej Mosnacek 	convert_params.func = convert_context;
2185ee1a84fdSOndrej Mosnacek 	convert_params.args = &args;
2186ee1a84fdSOndrej Mosnacek 	convert_params.target = newsidtab;
2187ee1a84fdSOndrej Mosnacek 
2188ee1a84fdSOndrej Mosnacek 	rc = sidtab_convert(oldsidtab, &convert_params);
21890719aaf5SGuido Trentalancia 	if (rc) {
2190b54c85c1Speter enderborg 		pr_err("SELinux:  unable to convert the internal"
21910719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
21920719aaf5SGuido Trentalancia 			" table\n");
219312b29f34SStephen Smalley 		goto err;
21940719aaf5SGuido Trentalancia 	}
21951da177e4SLinus Torvalds 
21961da177e4SLinus Torvalds 	/* Save the old policydb and SID table to free later. */
2197aa8e712cSStephen Smalley 	memcpy(oldpolicydb, policydb, sizeof(*policydb));
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds 	/* Install the new policydb and SID table. */
2200aa8e712cSStephen Smalley 	write_lock_irq(&state->ss->policy_rwlock);
2201aa8e712cSStephen Smalley 	memcpy(policydb, newpolicydb, sizeof(*policydb));
220224ed7fdaSOndrej Mosnacek 	state->ss->sidtab = newsidtab;
2203aa8e712cSStephen Smalley 	security_load_policycaps(state);
2204aa8e712cSStephen Smalley 	oldmapping = state->ss->map.mapping;
2205aa8e712cSStephen Smalley 	state->ss->map.mapping = newmap.mapping;
2206aa8e712cSStephen Smalley 	state->ss->map.size = newmap.size;
2207aa8e712cSStephen Smalley 	seqno = ++state->ss->latest_granting;
2208aa8e712cSStephen Smalley 	write_unlock_irq(&state->ss->policy_rwlock);
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 	/* Free the old policydb and SID table. */
2211b5495b42STim Gardner 	policydb_destroy(oldpolicydb);
221224ed7fdaSOndrej Mosnacek 	sidtab_destroy(oldsidtab);
221324ed7fdaSOndrej Mosnacek 	kfree(oldsidtab);
2214aa8e712cSStephen Smalley 	kfree(oldmapping);
22151da177e4SLinus Torvalds 
22166b6bc620SStephen Smalley 	avc_ss_reset(state->avc, seqno);
22171da177e4SLinus Torvalds 	selnl_notify_policyload(seqno);
2218aa8e712cSStephen Smalley 	selinux_status_update_policyload(state, seqno);
22197420ed23SVenkat Yekkirala 	selinux_netlbl_cache_invalidate();
2220342a0cffSVenkat Yekkirala 	selinux_xfrm_notify_policyload();
22211da177e4SLinus Torvalds 
2222b5495b42STim Gardner 	rc = 0;
2223b5495b42STim Gardner 	goto out;
22241da177e4SLinus Torvalds 
22251da177e4SLinus Torvalds err:
2226aa8e712cSStephen Smalley 	kfree(newmap.mapping);
222724ed7fdaSOndrej Mosnacek 	sidtab_destroy(newsidtab);
222824ed7fdaSOndrej Mosnacek 	kfree(newsidtab);
2229b5495b42STim Gardner 	policydb_destroy(newpolicydb);
22301da177e4SLinus Torvalds 
2231b5495b42STim Gardner out:
2232b5495b42STim Gardner 	kfree(oldpolicydb);
2233b5495b42STim Gardner 	return rc;
22341da177e4SLinus Torvalds }
22351da177e4SLinus Torvalds 
2236aa8e712cSStephen Smalley size_t security_policydb_len(struct selinux_state *state)
2237cee74f47SEric Paris {
2238aa8e712cSStephen Smalley 	struct policydb *p = &state->ss->policydb;
2239cee74f47SEric Paris 	size_t len;
2240cee74f47SEric Paris 
2241aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2242aa8e712cSStephen Smalley 	len = p->len;
2243aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
2244cee74f47SEric Paris 
2245cee74f47SEric Paris 	return len;
2246cee74f47SEric Paris }
2247cee74f47SEric Paris 
22481da177e4SLinus Torvalds /**
22491da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
22501da177e4SLinus Torvalds  * @protocol: protocol number
22511da177e4SLinus Torvalds  * @port: port number
22521da177e4SLinus Torvalds  * @out_sid: security identifier
22531da177e4SLinus Torvalds  */
2254aa8e712cSStephen Smalley int security_port_sid(struct selinux_state *state,
2255aa8e712cSStephen Smalley 		      u8 protocol, u16 port, u32 *out_sid)
22561da177e4SLinus Torvalds {
2257aa8e712cSStephen Smalley 	struct policydb *policydb;
2258aa8e712cSStephen Smalley 	struct sidtab *sidtab;
22591da177e4SLinus Torvalds 	struct ocontext *c;
22601da177e4SLinus Torvalds 	int rc = 0;
22611da177e4SLinus Torvalds 
2262aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
22631da177e4SLinus Torvalds 
2264aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
226524ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
2266aa8e712cSStephen Smalley 
2267aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_PORT];
22681da177e4SLinus Torvalds 	while (c) {
22691da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
22701da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
22711da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
22721da177e4SLinus Torvalds 			break;
22731da177e4SLinus Torvalds 		c = c->next;
22741da177e4SLinus Torvalds 	}
22751da177e4SLinus Torvalds 
22761da177e4SLinus Torvalds 	if (c) {
22771da177e4SLinus Torvalds 		if (!c->sid[0]) {
2278aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
22791da177e4SLinus Torvalds 						   &c->context[0],
22801da177e4SLinus Torvalds 						   &c->sid[0]);
22811da177e4SLinus Torvalds 			if (rc)
22821da177e4SLinus Torvalds 				goto out;
22831da177e4SLinus Torvalds 		}
22841da177e4SLinus Torvalds 		*out_sid = c->sid[0];
22851da177e4SLinus Torvalds 	} else {
22861da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
22871da177e4SLinus Torvalds 	}
22881da177e4SLinus Torvalds 
22891da177e4SLinus Torvalds out:
2290aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
22911da177e4SLinus Torvalds 	return rc;
22921da177e4SLinus Torvalds }
22931da177e4SLinus Torvalds 
22941da177e4SLinus Torvalds /**
2295cfc4d882SDaniel Jurgens  * security_pkey_sid - Obtain the SID for a pkey.
2296cfc4d882SDaniel Jurgens  * @subnet_prefix: Subnet Prefix
2297cfc4d882SDaniel Jurgens  * @pkey_num: pkey number
2298cfc4d882SDaniel Jurgens  * @out_sid: security identifier
2299cfc4d882SDaniel Jurgens  */
2300aa8e712cSStephen Smalley int security_ib_pkey_sid(struct selinux_state *state,
2301aa8e712cSStephen Smalley 			 u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2302cfc4d882SDaniel Jurgens {
2303aa8e712cSStephen Smalley 	struct policydb *policydb;
2304aa8e712cSStephen Smalley 	struct sidtab *sidtab;
2305cfc4d882SDaniel Jurgens 	struct ocontext *c;
2306cfc4d882SDaniel Jurgens 	int rc = 0;
2307cfc4d882SDaniel Jurgens 
2308aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2309cfc4d882SDaniel Jurgens 
2310aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
231124ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
2312aa8e712cSStephen Smalley 
2313aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBPKEY];
2314cfc4d882SDaniel Jurgens 	while (c) {
2315cfc4d882SDaniel Jurgens 		if (c->u.ibpkey.low_pkey <= pkey_num &&
2316cfc4d882SDaniel Jurgens 		    c->u.ibpkey.high_pkey >= pkey_num &&
2317cfc4d882SDaniel Jurgens 		    c->u.ibpkey.subnet_prefix == subnet_prefix)
2318cfc4d882SDaniel Jurgens 			break;
2319cfc4d882SDaniel Jurgens 
2320cfc4d882SDaniel Jurgens 		c = c->next;
2321cfc4d882SDaniel Jurgens 	}
2322cfc4d882SDaniel Jurgens 
2323cfc4d882SDaniel Jurgens 	if (c) {
2324cfc4d882SDaniel Jurgens 		if (!c->sid[0]) {
2325aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
2326cfc4d882SDaniel Jurgens 						   &c->context[0],
2327cfc4d882SDaniel Jurgens 						   &c->sid[0]);
2328cfc4d882SDaniel Jurgens 			if (rc)
2329cfc4d882SDaniel Jurgens 				goto out;
2330cfc4d882SDaniel Jurgens 		}
2331cfc4d882SDaniel Jurgens 		*out_sid = c->sid[0];
2332cfc4d882SDaniel Jurgens 	} else
2333cfc4d882SDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2334cfc4d882SDaniel Jurgens 
2335cfc4d882SDaniel Jurgens out:
2336aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
2337cfc4d882SDaniel Jurgens 	return rc;
2338cfc4d882SDaniel Jurgens }
2339cfc4d882SDaniel Jurgens 
2340cfc4d882SDaniel Jurgens /**
2341ab861dfcSDaniel Jurgens  * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2342ab861dfcSDaniel Jurgens  * @dev_name: device name
2343ab861dfcSDaniel Jurgens  * @port: port number
2344ab861dfcSDaniel Jurgens  * @out_sid: security identifier
2345ab861dfcSDaniel Jurgens  */
2346aa8e712cSStephen Smalley int security_ib_endport_sid(struct selinux_state *state,
2347aa8e712cSStephen Smalley 			    const char *dev_name, u8 port_num, u32 *out_sid)
2348ab861dfcSDaniel Jurgens {
2349aa8e712cSStephen Smalley 	struct policydb *policydb;
2350aa8e712cSStephen Smalley 	struct sidtab *sidtab;
2351ab861dfcSDaniel Jurgens 	struct ocontext *c;
2352ab861dfcSDaniel Jurgens 	int rc = 0;
2353ab861dfcSDaniel Jurgens 
2354aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2355ab861dfcSDaniel Jurgens 
2356aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
235724ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
2358aa8e712cSStephen Smalley 
2359aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBENDPORT];
2360ab861dfcSDaniel Jurgens 	while (c) {
2361ab861dfcSDaniel Jurgens 		if (c->u.ibendport.port == port_num &&
2362ab861dfcSDaniel Jurgens 		    !strncmp(c->u.ibendport.dev_name,
2363ab861dfcSDaniel Jurgens 			     dev_name,
2364ab861dfcSDaniel Jurgens 			     IB_DEVICE_NAME_MAX))
2365ab861dfcSDaniel Jurgens 			break;
2366ab861dfcSDaniel Jurgens 
2367ab861dfcSDaniel Jurgens 		c = c->next;
2368ab861dfcSDaniel Jurgens 	}
2369ab861dfcSDaniel Jurgens 
2370ab861dfcSDaniel Jurgens 	if (c) {
2371ab861dfcSDaniel Jurgens 		if (!c->sid[0]) {
2372aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
2373ab861dfcSDaniel Jurgens 						   &c->context[0],
2374ab861dfcSDaniel Jurgens 						   &c->sid[0]);
2375ab861dfcSDaniel Jurgens 			if (rc)
2376ab861dfcSDaniel Jurgens 				goto out;
2377ab861dfcSDaniel Jurgens 		}
2378ab861dfcSDaniel Jurgens 		*out_sid = c->sid[0];
2379ab861dfcSDaniel Jurgens 	} else
2380ab861dfcSDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2381ab861dfcSDaniel Jurgens 
2382ab861dfcSDaniel Jurgens out:
2383aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
2384ab861dfcSDaniel Jurgens 	return rc;
2385ab861dfcSDaniel Jurgens }
2386ab861dfcSDaniel Jurgens 
2387ab861dfcSDaniel Jurgens /**
23881da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
23891da177e4SLinus Torvalds  * @name: interface name
23901da177e4SLinus Torvalds  * @if_sid: interface SID
23911da177e4SLinus Torvalds  */
2392aa8e712cSStephen Smalley int security_netif_sid(struct selinux_state *state,
2393aa8e712cSStephen Smalley 		       char *name, u32 *if_sid)
23941da177e4SLinus Torvalds {
2395aa8e712cSStephen Smalley 	struct policydb *policydb;
2396aa8e712cSStephen Smalley 	struct sidtab *sidtab;
23971da177e4SLinus Torvalds 	int rc = 0;
23981da177e4SLinus Torvalds 	struct ocontext *c;
23991da177e4SLinus Torvalds 
2400aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
24011da177e4SLinus Torvalds 
2402aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
240324ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
2404aa8e712cSStephen Smalley 
2405aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_NETIF];
24061da177e4SLinus Torvalds 	while (c) {
24071da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
24081da177e4SLinus Torvalds 			break;
24091da177e4SLinus Torvalds 		c = c->next;
24101da177e4SLinus Torvalds 	}
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	if (c) {
24131da177e4SLinus Torvalds 		if (!c->sid[0] || !c->sid[1]) {
2414aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
24151da177e4SLinus Torvalds 						  &c->context[0],
24161da177e4SLinus Torvalds 						  &c->sid[0]);
24171da177e4SLinus Torvalds 			if (rc)
24181da177e4SLinus Torvalds 				goto out;
2419aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
24201da177e4SLinus Torvalds 						   &c->context[1],
24211da177e4SLinus Torvalds 						   &c->sid[1]);
24221da177e4SLinus Torvalds 			if (rc)
24231da177e4SLinus Torvalds 				goto out;
24241da177e4SLinus Torvalds 		}
24251da177e4SLinus Torvalds 		*if_sid = c->sid[0];
2426e8bfdb9dSPaul Moore 	} else
24271da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
24281da177e4SLinus Torvalds 
24291da177e4SLinus Torvalds out:
2430aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
24311da177e4SLinus Torvalds 	return rc;
24321da177e4SLinus Torvalds }
24331da177e4SLinus Torvalds 
24341da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
24351da177e4SLinus Torvalds {
24361da177e4SLinus Torvalds 	int i, fail = 0;
24371da177e4SLinus Torvalds 
24381da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
24391da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
24401da177e4SLinus Torvalds 			fail = 1;
24411da177e4SLinus Torvalds 			break;
24421da177e4SLinus Torvalds 		}
24431da177e4SLinus Torvalds 
24441da177e4SLinus Torvalds 	return !fail;
24451da177e4SLinus Torvalds }
24461da177e4SLinus Torvalds 
24471da177e4SLinus Torvalds /**
24481da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
24491da177e4SLinus Torvalds  * @domain: communication domain aka address family
24501da177e4SLinus Torvalds  * @addrp: address
24511da177e4SLinus Torvalds  * @addrlen: address length in bytes
24521da177e4SLinus Torvalds  * @out_sid: security identifier
24531da177e4SLinus Torvalds  */
2454aa8e712cSStephen Smalley int security_node_sid(struct selinux_state *state,
2455aa8e712cSStephen Smalley 		      u16 domain,
24561da177e4SLinus Torvalds 		      void *addrp,
24571da177e4SLinus Torvalds 		      u32 addrlen,
24581da177e4SLinus Torvalds 		      u32 *out_sid)
24591da177e4SLinus Torvalds {
2460aa8e712cSStephen Smalley 	struct policydb *policydb;
2461aa8e712cSStephen Smalley 	struct sidtab *sidtab;
24624b02b524SEric Paris 	int rc;
24631da177e4SLinus Torvalds 	struct ocontext *c;
24641da177e4SLinus Torvalds 
2465aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2466aa8e712cSStephen Smalley 
2467aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
246824ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
24691da177e4SLinus Torvalds 
24701da177e4SLinus Torvalds 	switch (domain) {
24711da177e4SLinus Torvalds 	case AF_INET: {
24721da177e4SLinus Torvalds 		u32 addr;
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 		rc = -EINVAL;
24754b02b524SEric Paris 		if (addrlen != sizeof(u32))
24761da177e4SLinus Torvalds 			goto out;
24771da177e4SLinus Torvalds 
24781da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
24791da177e4SLinus Torvalds 
2480aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE];
24811da177e4SLinus Torvalds 		while (c) {
24821da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
24831da177e4SLinus Torvalds 				break;
24841da177e4SLinus Torvalds 			c = c->next;
24851da177e4SLinus Torvalds 		}
24861da177e4SLinus Torvalds 		break;
24871da177e4SLinus Torvalds 	}
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds 	case AF_INET6:
24901da177e4SLinus Torvalds 		rc = -EINVAL;
24914b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
24921da177e4SLinus Torvalds 			goto out;
2493aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE6];
24941da177e4SLinus Torvalds 		while (c) {
24951da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
24961da177e4SLinus Torvalds 						c->u.node6.mask))
24971da177e4SLinus Torvalds 				break;
24981da177e4SLinus Torvalds 			c = c->next;
24991da177e4SLinus Torvalds 		}
25001da177e4SLinus Torvalds 		break;
25011da177e4SLinus Torvalds 
25021da177e4SLinus Torvalds 	default:
25034b02b524SEric Paris 		rc = 0;
25041da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
25051da177e4SLinus Torvalds 		goto out;
25061da177e4SLinus Torvalds 	}
25071da177e4SLinus Torvalds 
25081da177e4SLinus Torvalds 	if (c) {
25091da177e4SLinus Torvalds 		if (!c->sid[0]) {
2510aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab,
25111da177e4SLinus Torvalds 						   &c->context[0],
25121da177e4SLinus Torvalds 						   &c->sid[0]);
25131da177e4SLinus Torvalds 			if (rc)
25141da177e4SLinus Torvalds 				goto out;
25151da177e4SLinus Torvalds 		}
25161da177e4SLinus Torvalds 		*out_sid = c->sid[0];
25171da177e4SLinus Torvalds 	} else {
25181da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
25191da177e4SLinus Torvalds 	}
25201da177e4SLinus Torvalds 
25214b02b524SEric Paris 	rc = 0;
25221da177e4SLinus Torvalds out:
2523aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
25241da177e4SLinus Torvalds 	return rc;
25251da177e4SLinus Torvalds }
25261da177e4SLinus Torvalds 
25271da177e4SLinus Torvalds #define SIDS_NEL 25
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds /**
25301da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
25311da177e4SLinus Torvalds  * @fromsid: starting SID
25321da177e4SLinus Torvalds  * @username: username
25331da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
25341da177e4SLinus Torvalds  * @nel: number of elements in @sids
25351da177e4SLinus Torvalds  *
25361da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
25371da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
25381da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
25391da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
25401da177e4SLinus Torvalds  * number of elements in the array.
25411da177e4SLinus Torvalds  */
25421da177e4SLinus Torvalds 
2543aa8e712cSStephen Smalley int security_get_user_sids(struct selinux_state *state,
2544aa8e712cSStephen Smalley 			   u32 fromsid,
25451da177e4SLinus Torvalds 			   char *username,
25461da177e4SLinus Torvalds 			   u32 **sids,
25471da177e4SLinus Torvalds 			   u32 *nel)
25481da177e4SLinus Torvalds {
2549aa8e712cSStephen Smalley 	struct policydb *policydb;
2550aa8e712cSStephen Smalley 	struct sidtab *sidtab;
25511da177e4SLinus Torvalds 	struct context *fromcon, usercon;
25522c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
25531da177e4SLinus Torvalds 	u32 mynel = 0, maxnel = SIDS_NEL;
25541da177e4SLinus Torvalds 	struct user_datum *user;
25551da177e4SLinus Torvalds 	struct role_datum *role;
2556782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
25571da177e4SLinus Torvalds 	int rc = 0, i, j;
25581da177e4SLinus Torvalds 
25591da177e4SLinus Torvalds 	*sids = NULL;
25601da177e4SLinus Torvalds 	*nel = 0;
25612c3c05dbSStephen Smalley 
2562aa8e712cSStephen Smalley 	if (!state->initialized)
25631da177e4SLinus Torvalds 		goto out;
25641da177e4SLinus Torvalds 
2565aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2566aa8e712cSStephen Smalley 
2567aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
256824ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
25691da177e4SLinus Torvalds 
257012b29f34SStephen Smalley 	context_init(&usercon);
257112b29f34SStephen Smalley 
25724b02b524SEric Paris 	rc = -EINVAL;
2573aa8e712cSStephen Smalley 	fromcon = sidtab_search(sidtab, fromsid);
25744b02b524SEric Paris 	if (!fromcon)
25751da177e4SLinus Torvalds 		goto out_unlock;
25761da177e4SLinus Torvalds 
25771da177e4SLinus Torvalds 	rc = -EINVAL;
2578aa8e712cSStephen Smalley 	user = hashtab_search(policydb->p_users.table, username);
25794b02b524SEric Paris 	if (!user)
25801da177e4SLinus Torvalds 		goto out_unlock;
25814b02b524SEric Paris 
25821da177e4SLinus Torvalds 	usercon.user = user->value;
25831da177e4SLinus Torvalds 
25841da177e4SLinus Torvalds 	rc = -ENOMEM;
25854b02b524SEric Paris 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
25864b02b524SEric Paris 	if (!mysids)
25871da177e4SLinus Torvalds 		goto out_unlock;
25881da177e4SLinus Torvalds 
25899fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2590aa8e712cSStephen Smalley 		role = policydb->role_val_to_struct[i];
25911da177e4SLinus Torvalds 		usercon.role = i + 1;
25929fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
25931da177e4SLinus Torvalds 			usercon.type = j + 1;
25941da177e4SLinus Torvalds 
2595aa8e712cSStephen Smalley 			if (mls_setup_user_range(policydb, fromcon, user,
2596aa8e712cSStephen Smalley 						 &usercon))
25971da177e4SLinus Torvalds 				continue;
25981da177e4SLinus Torvalds 
2599aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
26002c3c05dbSStephen Smalley 			if (rc)
26011da177e4SLinus Torvalds 				goto out_unlock;
26021da177e4SLinus Torvalds 			if (mynel < maxnel) {
26031da177e4SLinus Torvalds 				mysids[mynel++] = sid;
26041da177e4SLinus Torvalds 			} else {
26054b02b524SEric Paris 				rc = -ENOMEM;
26061da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
260789d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
26084b02b524SEric Paris 				if (!mysids2)
26091da177e4SLinus Torvalds 					goto out_unlock;
26101da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
26111da177e4SLinus Torvalds 				kfree(mysids);
26121da177e4SLinus Torvalds 				mysids = mysids2;
26131da177e4SLinus Torvalds 				mysids[mynel++] = sid;
26141da177e4SLinus Torvalds 			}
26151da177e4SLinus Torvalds 		}
26161da177e4SLinus Torvalds 	}
26174b02b524SEric Paris 	rc = 0;
26181da177e4SLinus Torvalds out_unlock:
2619aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
26202c3c05dbSStephen Smalley 	if (rc || !mynel) {
26212c3c05dbSStephen Smalley 		kfree(mysids);
26222c3c05dbSStephen Smalley 		goto out;
26232c3c05dbSStephen Smalley 	}
26242c3c05dbSStephen Smalley 
26254b02b524SEric Paris 	rc = -ENOMEM;
26262c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
26272c3c05dbSStephen Smalley 	if (!mysids2) {
26282c3c05dbSStephen Smalley 		kfree(mysids);
26292c3c05dbSStephen Smalley 		goto out;
26302c3c05dbSStephen Smalley 	}
26312c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
2632f01e1af4SLinus Torvalds 		struct av_decision dummy_avd;
26336b6bc620SStephen Smalley 		rc = avc_has_perm_noaudit(state,
26346b6bc620SStephen Smalley 					  fromsid, mysids[i],
2635c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
26362c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
2637f01e1af4SLinus Torvalds 					  &dummy_avd);
26382c3c05dbSStephen Smalley 		if (!rc)
26392c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
26402c3c05dbSStephen Smalley 		cond_resched();
26412c3c05dbSStephen Smalley 	}
26422c3c05dbSStephen Smalley 	rc = 0;
26432c3c05dbSStephen Smalley 	kfree(mysids);
26442c3c05dbSStephen Smalley 	*sids = mysids2;
26452c3c05dbSStephen Smalley 	*nel = j;
26461da177e4SLinus Torvalds out:
26471da177e4SLinus Torvalds 	return rc;
26481da177e4SLinus Torvalds }
26491da177e4SLinus Torvalds 
26501da177e4SLinus Torvalds /**
2651f31e7994SWaiman Long  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
26521da177e4SLinus Torvalds  * @fstype: filesystem type
26531da177e4SLinus Torvalds  * @path: path from root of mount
26541da177e4SLinus Torvalds  * @sclass: file security class
26551da177e4SLinus Torvalds  * @sid: SID for path
26561da177e4SLinus Torvalds  *
26571da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
26581da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
26591da177e4SLinus Torvalds  * transition SIDs or task SIDs.
2660f31e7994SWaiman Long  *
2661f31e7994SWaiman Long  * The caller must acquire the policy_rwlock before calling this function.
26621da177e4SLinus Torvalds  */
2663aa8e712cSStephen Smalley static inline int __security_genfs_sid(struct selinux_state *state,
2664aa8e712cSStephen Smalley 				       const char *fstype,
26651da177e4SLinus Torvalds 				       char *path,
2666c6d3aaa4SStephen Smalley 				       u16 orig_sclass,
26671da177e4SLinus Torvalds 				       u32 *sid)
26681da177e4SLinus Torvalds {
2669aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
267024ed7fdaSOndrej Mosnacek 	struct sidtab *sidtab = state->ss->sidtab;
26711da177e4SLinus Torvalds 	int len;
2672c6d3aaa4SStephen Smalley 	u16 sclass;
26731da177e4SLinus Torvalds 	struct genfs *genfs;
26741da177e4SLinus Torvalds 	struct ocontext *c;
26754b02b524SEric Paris 	int rc, cmp = 0;
26761da177e4SLinus Torvalds 
2677b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2678b1aa5301SStephen Smalley 		path++;
2679b1aa5301SStephen Smalley 
2680aa8e712cSStephen Smalley 	sclass = unmap_class(&state->ss->map, orig_sclass);
26814b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2682c6d3aaa4SStephen Smalley 
2683aa8e712cSStephen Smalley 	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
26841da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
26851da177e4SLinus Torvalds 		if (cmp <= 0)
26861da177e4SLinus Torvalds 			break;
26871da177e4SLinus Torvalds 	}
26881da177e4SLinus Torvalds 
26891da177e4SLinus Torvalds 	rc = -ENOENT;
26904b02b524SEric Paris 	if (!genfs || cmp)
26911da177e4SLinus Torvalds 		goto out;
26921da177e4SLinus Torvalds 
26931da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
26941da177e4SLinus Torvalds 		len = strlen(c->u.name);
26951da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
26961da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
26971da177e4SLinus Torvalds 			break;
26981da177e4SLinus Torvalds 	}
26991da177e4SLinus Torvalds 
27001da177e4SLinus Torvalds 	rc = -ENOENT;
27014b02b524SEric Paris 	if (!c)
27021da177e4SLinus Torvalds 		goto out;
27031da177e4SLinus Torvalds 
27041da177e4SLinus Torvalds 	if (!c->sid[0]) {
2705aa8e712cSStephen Smalley 		rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
27061da177e4SLinus Torvalds 		if (rc)
27071da177e4SLinus Torvalds 			goto out;
27081da177e4SLinus Torvalds 	}
27091da177e4SLinus Torvalds 
27101da177e4SLinus Torvalds 	*sid = c->sid[0];
27114b02b524SEric Paris 	rc = 0;
27121da177e4SLinus Torvalds out:
27131da177e4SLinus Torvalds 	return rc;
27141da177e4SLinus Torvalds }
27151da177e4SLinus Torvalds 
27161da177e4SLinus Torvalds /**
2717f31e7994SWaiman Long  * security_genfs_sid - Obtain a SID for a file in a filesystem
2718f31e7994SWaiman Long  * @fstype: filesystem type
2719f31e7994SWaiman Long  * @path: path from root of mount
2720f31e7994SWaiman Long  * @sclass: file security class
2721f31e7994SWaiman Long  * @sid: SID for path
2722f31e7994SWaiman Long  *
2723f31e7994SWaiman Long  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2724f31e7994SWaiman Long  * it afterward.
2725f31e7994SWaiman Long  */
2726aa8e712cSStephen Smalley int security_genfs_sid(struct selinux_state *state,
2727aa8e712cSStephen Smalley 		       const char *fstype,
2728f31e7994SWaiman Long 		       char *path,
2729f31e7994SWaiman Long 		       u16 orig_sclass,
2730f31e7994SWaiman Long 		       u32 *sid)
2731f31e7994SWaiman Long {
2732f31e7994SWaiman Long 	int retval;
2733f31e7994SWaiman Long 
2734aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2735aa8e712cSStephen Smalley 	retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
2736aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
2737f31e7994SWaiman Long 	return retval;
2738f31e7994SWaiman Long }
2739f31e7994SWaiman Long 
2740f31e7994SWaiman Long /**
27411da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
2742a64c54cfSEric Paris  * @sb: superblock in question
27431da177e4SLinus Torvalds  */
2744aa8e712cSStephen Smalley int security_fs_use(struct selinux_state *state, struct super_block *sb)
27451da177e4SLinus Torvalds {
2746aa8e712cSStephen Smalley 	struct policydb *policydb;
2747aa8e712cSStephen Smalley 	struct sidtab *sidtab;
27481da177e4SLinus Torvalds 	int rc = 0;
27491da177e4SLinus Torvalds 	struct ocontext *c;
2750a64c54cfSEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
2751a64c54cfSEric Paris 	const char *fstype = sb->s_type->name;
27521da177e4SLinus Torvalds 
2753aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
27541da177e4SLinus Torvalds 
2755aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
275624ed7fdaSOndrej Mosnacek 	sidtab = state->ss->sidtab;
2757aa8e712cSStephen Smalley 
2758aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_FSUSE];
27594d546f81SPaul Moore 	while (c) {
27604d546f81SPaul Moore 		if (strcmp(fstype, c->u.name) == 0)
27611da177e4SLinus Torvalds 			break;
27624d546f81SPaul Moore 		c = c->next;
27631da177e4SLinus Torvalds 	}
27641da177e4SLinus Torvalds 
27651da177e4SLinus Torvalds 	if (c) {
2766a64c54cfSEric Paris 		sbsec->behavior = c->v.behavior;
27671da177e4SLinus Torvalds 		if (!c->sid[0]) {
2768aa8e712cSStephen Smalley 			rc = sidtab_context_to_sid(sidtab, &c->context[0],
27691da177e4SLinus Torvalds 						   &c->sid[0]);
27701da177e4SLinus Torvalds 			if (rc)
27711da177e4SLinus Torvalds 				goto out;
27721da177e4SLinus Torvalds 		}
2773a64c54cfSEric Paris 		sbsec->sid = c->sid[0];
2774089be43eSJames Morris 	} else {
2775aa8e712cSStephen Smalley 		rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
2776f31e7994SWaiman Long 					  &sbsec->sid);
27771da177e4SLinus Torvalds 		if (rc) {
2778a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_NONE;
27791da177e4SLinus Torvalds 			rc = 0;
27801da177e4SLinus Torvalds 		} else {
2781a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_GENFS;
27821da177e4SLinus Torvalds 		}
2783089be43eSJames Morris 	}
27841da177e4SLinus Torvalds 
27851da177e4SLinus Torvalds out:
2786aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
27871da177e4SLinus Torvalds 	return rc;
27881da177e4SLinus Torvalds }
27891da177e4SLinus Torvalds 
2790aa8e712cSStephen Smalley int security_get_bools(struct selinux_state *state,
2791aa8e712cSStephen Smalley 		       int *len, char ***names, int **values)
27921da177e4SLinus Torvalds {
2793aa8e712cSStephen Smalley 	struct policydb *policydb;
27944b02b524SEric Paris 	int i, rc;
27951da177e4SLinus Torvalds 
2796274f62e1SStephen Smalley 	if (!state->initialized) {
2797274f62e1SStephen Smalley 		*len = 0;
2798274f62e1SStephen Smalley 		*names = NULL;
2799274f62e1SStephen Smalley 		*values = NULL;
2800274f62e1SStephen Smalley 		return 0;
2801274f62e1SStephen Smalley 	}
2802274f62e1SStephen Smalley 
2803aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2804aa8e712cSStephen Smalley 
2805aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
2806aa8e712cSStephen Smalley 
28071da177e4SLinus Torvalds 	*names = NULL;
28081da177e4SLinus Torvalds 	*values = NULL;
28091da177e4SLinus Torvalds 
28101da177e4SLinus Torvalds 	rc = 0;
2811aa8e712cSStephen Smalley 	*len = policydb->p_bools.nprim;
28124b02b524SEric Paris 	if (!*len)
28131da177e4SLinus Torvalds 		goto out;
28141da177e4SLinus Torvalds 
28154b02b524SEric Paris 	rc = -ENOMEM;
2816e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
28171da177e4SLinus Torvalds 	if (!*names)
28181da177e4SLinus Torvalds 		goto err;
28191da177e4SLinus Torvalds 
28204b02b524SEric Paris 	rc = -ENOMEM;
2821e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
28221da177e4SLinus Torvalds 	if (!*values)
28231da177e4SLinus Torvalds 		goto err;
28241da177e4SLinus Torvalds 
28251da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
2826aa8e712cSStephen Smalley 		(*values)[i] = policydb->bool_val_to_struct[i]->state;
28274b02b524SEric Paris 
28284b02b524SEric Paris 		rc = -ENOMEM;
2829aa8e712cSStephen Smalley 		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
2830aa8e712cSStephen Smalley 				      GFP_ATOMIC);
28311da177e4SLinus Torvalds 		if (!(*names)[i])
28321da177e4SLinus Torvalds 			goto err;
28331da177e4SLinus Torvalds 	}
28341da177e4SLinus Torvalds 	rc = 0;
28351da177e4SLinus Torvalds out:
2836aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
28371da177e4SLinus Torvalds 	return rc;
28381da177e4SLinus Torvalds err:
28391da177e4SLinus Torvalds 	if (*names) {
28401da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
28411da177e4SLinus Torvalds 			kfree((*names)[i]);
28421da177e4SLinus Torvalds 	}
28431da177e4SLinus Torvalds 	kfree(*values);
28441da177e4SLinus Torvalds 	goto out;
28451da177e4SLinus Torvalds }
28461da177e4SLinus Torvalds 
28471da177e4SLinus Torvalds 
2848aa8e712cSStephen Smalley int security_set_bools(struct selinux_state *state, int len, int *values)
28491da177e4SLinus Torvalds {
2850aa8e712cSStephen Smalley 	struct policydb *policydb;
28514b02b524SEric Paris 	int i, rc;
28521da177e4SLinus Torvalds 	int lenp, seqno = 0;
28531da177e4SLinus Torvalds 	struct cond_node *cur;
28541da177e4SLinus Torvalds 
2855aa8e712cSStephen Smalley 	write_lock_irq(&state->ss->policy_rwlock);
2856aa8e712cSStephen Smalley 
2857aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
28581da177e4SLinus Torvalds 
28591da177e4SLinus Torvalds 	rc = -EFAULT;
2860aa8e712cSStephen Smalley 	lenp = policydb->p_bools.nprim;
28614b02b524SEric Paris 	if (len != lenp)
28621da177e4SLinus Torvalds 		goto out;
28631da177e4SLinus Torvalds 
28641da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
2865aa8e712cSStephen Smalley 		if (!!values[i] != policydb->bool_val_to_struct[i]->state) {
2866cdfb6b34SRichard Guy Briggs 			audit_log(audit_context(), GFP_ATOMIC,
2867af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
28684746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
2869aa8e712cSStephen Smalley 				sym_name(policydb, SYM_BOOLS, i),
2870af601e46SSteve Grubb 				!!values[i],
2871aa8e712cSStephen Smalley 				policydb->bool_val_to_struct[i]->state,
2872581abc09SEric W. Biederman 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
28734746ec5bSEric Paris 				audit_get_sessionid(current));
2874af601e46SSteve Grubb 		}
28755d55a345SEric Paris 		if (values[i])
2876aa8e712cSStephen Smalley 			policydb->bool_val_to_struct[i]->state = 1;
28775d55a345SEric Paris 		else
2878aa8e712cSStephen Smalley 			policydb->bool_val_to_struct[i]->state = 0;
28791da177e4SLinus Torvalds 	}
28801da177e4SLinus Torvalds 
2881aa8e712cSStephen Smalley 	for (cur = policydb->cond_list; cur; cur = cur->next) {
2882aa8e712cSStephen Smalley 		rc = evaluate_cond_node(policydb, cur);
28831da177e4SLinus Torvalds 		if (rc)
28841da177e4SLinus Torvalds 			goto out;
28851da177e4SLinus Torvalds 	}
28861da177e4SLinus Torvalds 
2887aa8e712cSStephen Smalley 	seqno = ++state->ss->latest_granting;
28884b02b524SEric Paris 	rc = 0;
28891da177e4SLinus Torvalds out:
2890aa8e712cSStephen Smalley 	write_unlock_irq(&state->ss->policy_rwlock);
28911da177e4SLinus Torvalds 	if (!rc) {
28926b6bc620SStephen Smalley 		avc_ss_reset(state->avc, seqno);
28931da177e4SLinus Torvalds 		selnl_notify_policyload(seqno);
2894aa8e712cSStephen Smalley 		selinux_status_update_policyload(state, seqno);
2895342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
28961da177e4SLinus Torvalds 	}
28971da177e4SLinus Torvalds 	return rc;
28981da177e4SLinus Torvalds }
28991da177e4SLinus Torvalds 
2900aa8e712cSStephen Smalley int security_get_bool_value(struct selinux_state *state,
2901aa8e712cSStephen Smalley 			    int index)
29021da177e4SLinus Torvalds {
2903aa8e712cSStephen Smalley 	struct policydb *policydb;
29044b02b524SEric Paris 	int rc;
29051da177e4SLinus Torvalds 	int len;
29061da177e4SLinus Torvalds 
2907aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
2908aa8e712cSStephen Smalley 
2909aa8e712cSStephen Smalley 	policydb = &state->ss->policydb;
29101da177e4SLinus Torvalds 
29111da177e4SLinus Torvalds 	rc = -EFAULT;
2912aa8e712cSStephen Smalley 	len = policydb->p_bools.nprim;
29130fd71a62SPrarit Bhargava 	if (index >= len)
29141da177e4SLinus Torvalds 		goto out;
29151da177e4SLinus Torvalds 
2916aa8e712cSStephen Smalley 	rc = policydb->bool_val_to_struct[index]->state;
29171da177e4SLinus Torvalds out:
2918aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
29191da177e4SLinus Torvalds 	return rc;
29201da177e4SLinus Torvalds }
2921376bd9cbSDarrel Goeddel 
2922aa8e712cSStephen Smalley static int security_preserve_bools(struct selinux_state *state,
2923aa8e712cSStephen Smalley 				   struct policydb *policydb)
2924e900a7d9SStephen Smalley {
2925e900a7d9SStephen Smalley 	int rc, nbools = 0, *bvalues = NULL, i;
2926e900a7d9SStephen Smalley 	char **bnames = NULL;
2927e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
2928e900a7d9SStephen Smalley 	struct cond_node *cur;
2929e900a7d9SStephen Smalley 
2930aa8e712cSStephen Smalley 	rc = security_get_bools(state, &nbools, &bnames, &bvalues);
2931e900a7d9SStephen Smalley 	if (rc)
2932e900a7d9SStephen Smalley 		goto out;
2933e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
2934aa8e712cSStephen Smalley 		booldatum = hashtab_search(policydb->p_bools.table, bnames[i]);
2935e900a7d9SStephen Smalley 		if (booldatum)
2936e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
2937e900a7d9SStephen Smalley 	}
2938aa8e712cSStephen Smalley 	for (cur = policydb->cond_list; cur; cur = cur->next) {
2939aa8e712cSStephen Smalley 		rc = evaluate_cond_node(policydb, cur);
2940e900a7d9SStephen Smalley 		if (rc)
2941e900a7d9SStephen Smalley 			goto out;
2942e900a7d9SStephen Smalley 	}
2943e900a7d9SStephen Smalley 
2944e900a7d9SStephen Smalley out:
2945e900a7d9SStephen Smalley 	if (bnames) {
2946e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
2947e900a7d9SStephen Smalley 			kfree(bnames[i]);
2948e900a7d9SStephen Smalley 	}
2949e900a7d9SStephen Smalley 	kfree(bnames);
2950e900a7d9SStephen Smalley 	kfree(bvalues);
2951e900a7d9SStephen Smalley 	return rc;
2952e900a7d9SStephen Smalley }
2953e900a7d9SStephen Smalley 
295408554d6bSVenkat Yekkirala /*
295508554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
295608554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
295708554d6bSVenkat Yekkirala  */
2958aa8e712cSStephen Smalley int security_sid_mls_copy(struct selinux_state *state,
2959aa8e712cSStephen Smalley 			  u32 sid, u32 mls_sid, u32 *new_sid)
296008554d6bSVenkat Yekkirala {
2961aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
296224ed7fdaSOndrej Mosnacek 	struct sidtab *sidtab = state->ss->sidtab;
296308554d6bSVenkat Yekkirala 	struct context *context1;
296408554d6bSVenkat Yekkirala 	struct context *context2;
296508554d6bSVenkat Yekkirala 	struct context newcon;
296608554d6bSVenkat Yekkirala 	char *s;
296708554d6bSVenkat Yekkirala 	u32 len;
29684b02b524SEric Paris 	int rc;
296908554d6bSVenkat Yekkirala 
29704b02b524SEric Paris 	rc = 0;
2971aa8e712cSStephen Smalley 	if (!state->initialized || !policydb->mls_enabled) {
297208554d6bSVenkat Yekkirala 		*new_sid = sid;
297308554d6bSVenkat Yekkirala 		goto out;
297408554d6bSVenkat Yekkirala 	}
297508554d6bSVenkat Yekkirala 
297608554d6bSVenkat Yekkirala 	context_init(&newcon);
297708554d6bSVenkat Yekkirala 
2978aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
29794b02b524SEric Paris 
29804b02b524SEric Paris 	rc = -EINVAL;
2981aa8e712cSStephen Smalley 	context1 = sidtab_search(sidtab, sid);
298208554d6bSVenkat Yekkirala 	if (!context1) {
2983b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
2984744ba35eSEric Paris 			__func__, sid);
298508554d6bSVenkat Yekkirala 		goto out_unlock;
298608554d6bSVenkat Yekkirala 	}
298708554d6bSVenkat Yekkirala 
29884b02b524SEric Paris 	rc = -EINVAL;
2989aa8e712cSStephen Smalley 	context2 = sidtab_search(sidtab, mls_sid);
299008554d6bSVenkat Yekkirala 	if (!context2) {
2991b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
2992744ba35eSEric Paris 			__func__, mls_sid);
299308554d6bSVenkat Yekkirala 		goto out_unlock;
299408554d6bSVenkat Yekkirala 	}
299508554d6bSVenkat Yekkirala 
299608554d6bSVenkat Yekkirala 	newcon.user = context1->user;
299708554d6bSVenkat Yekkirala 	newcon.role = context1->role;
299808554d6bSVenkat Yekkirala 	newcon.type = context1->type;
29990efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
300008554d6bSVenkat Yekkirala 	if (rc)
300108554d6bSVenkat Yekkirala 		goto out_unlock;
300208554d6bSVenkat Yekkirala 
300308554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
3004aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcon)) {
3005aa8e712cSStephen Smalley 		rc = convert_context_handle_invalid_context(state, &newcon);
30064b02b524SEric Paris 		if (rc) {
3007aa8e712cSStephen Smalley 			if (!context_struct_to_string(policydb, &newcon, &s,
3008aa8e712cSStephen Smalley 						      &len)) {
3009ea74a685SRichard Guy Briggs 				struct audit_buffer *ab;
3010ea74a685SRichard Guy Briggs 
3011ea74a685SRichard Guy Briggs 				ab = audit_log_start(audit_context(),
3012ea74a685SRichard Guy Briggs 						     GFP_ATOMIC,
3013ea74a685SRichard Guy Briggs 						     AUDIT_SELINUX_ERR);
3014ea74a685SRichard Guy Briggs 				audit_log_format(ab,
3015ea74a685SRichard Guy Briggs 						 "op=security_sid_mls_copy invalid_context=");
3016ea74a685SRichard Guy Briggs 				/* don't record NUL with untrusted strings */
3017ea74a685SRichard Guy Briggs 				audit_log_n_untrustedstring(ab, s, len - 1);
3018ea74a685SRichard Guy Briggs 				audit_log_end(ab);
301908554d6bSVenkat Yekkirala 				kfree(s);
302008554d6bSVenkat Yekkirala 			}
30214b02b524SEric Paris 			goto out_unlock;
30224b02b524SEric Paris 		}
30234b02b524SEric Paris 	}
302408554d6bSVenkat Yekkirala 
3025aa8e712cSStephen Smalley 	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
302608554d6bSVenkat Yekkirala out_unlock:
3027aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
302808554d6bSVenkat Yekkirala 	context_destroy(&newcon);
302908554d6bSVenkat Yekkirala out:
303008554d6bSVenkat Yekkirala 	return rc;
303108554d6bSVenkat Yekkirala }
303208554d6bSVenkat Yekkirala 
3033220deb96SPaul Moore /**
3034220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3035220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
3036220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
3037220deb96SPaul Moore  * @xfrm_sid: XFRM SID
3038220deb96SPaul Moore  *
3039220deb96SPaul Moore  * Description:
3040220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3041220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
3042220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
3043220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
3044220deb96SPaul Moore  *
3045220deb96SPaul Moore  *                                 | function return |      @sid
3046220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
3047220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
3048220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
3049220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
3050220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
3051220deb96SPaul Moore  *
3052220deb96SPaul Moore  */
3053aa8e712cSStephen Smalley int security_net_peersid_resolve(struct selinux_state *state,
3054aa8e712cSStephen Smalley 				 u32 nlbl_sid, u32 nlbl_type,
3055220deb96SPaul Moore 				 u32 xfrm_sid,
3056220deb96SPaul Moore 				 u32 *peer_sid)
3057220deb96SPaul Moore {
3058aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
305924ed7fdaSOndrej Mosnacek 	struct sidtab *sidtab = state->ss->sidtab;
3060220deb96SPaul Moore 	int rc;
3061220deb96SPaul Moore 	struct context *nlbl_ctx;
3062220deb96SPaul Moore 	struct context *xfrm_ctx;
3063220deb96SPaul Moore 
30644b02b524SEric Paris 	*peer_sid = SECSID_NULL;
30654b02b524SEric Paris 
3066220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
3067220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
3068220deb96SPaul Moore 	 * single or absent peer SID/label */
3069220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
3070220deb96SPaul Moore 		*peer_sid = nlbl_sid;
3071220deb96SPaul Moore 		return 0;
3072220deb96SPaul Moore 	}
3073220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3074220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3075220deb96SPaul Moore 	 * is present */
3076220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3077220deb96SPaul Moore 		*peer_sid = xfrm_sid;
3078220deb96SPaul Moore 		return 0;
3079220deb96SPaul Moore 	}
3080220deb96SPaul Moore 
3081aa8e712cSStephen Smalley 	/*
3082aa8e712cSStephen Smalley 	 * We don't need to check initialized here since the only way both
3083220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3084aa8e712cSStephen Smalley 	 * security server was initialized and state->initialized was true.
3085aa8e712cSStephen Smalley 	 */
3086aa8e712cSStephen Smalley 	if (!policydb->mls_enabled)
3087220deb96SPaul Moore 		return 0;
3088220deb96SPaul Moore 
3089aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
3090220deb96SPaul Moore 
30914b02b524SEric Paris 	rc = -EINVAL;
3092aa8e712cSStephen Smalley 	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3093220deb96SPaul Moore 	if (!nlbl_ctx) {
3094b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3095744ba35eSEric Paris 		       __func__, nlbl_sid);
30964b02b524SEric Paris 		goto out;
3097220deb96SPaul Moore 	}
30984b02b524SEric Paris 	rc = -EINVAL;
3099aa8e712cSStephen Smalley 	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3100220deb96SPaul Moore 	if (!xfrm_ctx) {
3101b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3102744ba35eSEric Paris 		       __func__, xfrm_sid);
31034b02b524SEric Paris 		goto out;
3104220deb96SPaul Moore 	}
3105220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
31064b02b524SEric Paris 	if (rc)
31074b02b524SEric Paris 		goto out;
3108220deb96SPaul Moore 
3109220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
3110220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
3111220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
3112220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
3113220deb96SPaul Moore 	 * expressive */
3114220deb96SPaul Moore 	*peer_sid = xfrm_sid;
31154b02b524SEric Paris out:
3116aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
3117220deb96SPaul Moore 	return rc;
3118220deb96SPaul Moore }
3119220deb96SPaul Moore 
312055fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
312155fcf09bSChristopher J. PeBenito {
312255fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
312355fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
312455fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
312555fcf09bSChristopher J. PeBenito 
312655fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
312755fcf09bSChristopher J. PeBenito 	if (!classes[value])
312855fcf09bSChristopher J. PeBenito 		return -ENOMEM;
312955fcf09bSChristopher J. PeBenito 
313055fcf09bSChristopher J. PeBenito 	return 0;
313155fcf09bSChristopher J. PeBenito }
313255fcf09bSChristopher J. PeBenito 
3133aa8e712cSStephen Smalley int security_get_classes(struct selinux_state *state,
3134aa8e712cSStephen Smalley 			 char ***classes, int *nclasses)
313555fcf09bSChristopher J. PeBenito {
3136aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
31374b02b524SEric Paris 	int rc;
313855fcf09bSChristopher J. PeBenito 
3139274f62e1SStephen Smalley 	if (!state->initialized) {
3140274f62e1SStephen Smalley 		*nclasses = 0;
3141274f62e1SStephen Smalley 		*classes = NULL;
3142274f62e1SStephen Smalley 		return 0;
3143274f62e1SStephen Smalley 	}
3144274f62e1SStephen Smalley 
3145aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
314655fcf09bSChristopher J. PeBenito 
31474b02b524SEric Paris 	rc = -ENOMEM;
3148aa8e712cSStephen Smalley 	*nclasses = policydb->p_classes.nprim;
31499f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
315055fcf09bSChristopher J. PeBenito 	if (!*classes)
315155fcf09bSChristopher J. PeBenito 		goto out;
315255fcf09bSChristopher J. PeBenito 
3153aa8e712cSStephen Smalley 	rc = hashtab_map(policydb->p_classes.table, get_classes_callback,
315455fcf09bSChristopher J. PeBenito 			*classes);
31554b02b524SEric Paris 	if (rc) {
315655fcf09bSChristopher J. PeBenito 		int i;
315755fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
315855fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
315955fcf09bSChristopher J. PeBenito 		kfree(*classes);
316055fcf09bSChristopher J. PeBenito 	}
316155fcf09bSChristopher J. PeBenito 
316255fcf09bSChristopher J. PeBenito out:
3163aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
316455fcf09bSChristopher J. PeBenito 	return rc;
316555fcf09bSChristopher J. PeBenito }
316655fcf09bSChristopher J. PeBenito 
316755fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
316855fcf09bSChristopher J. PeBenito {
316955fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
317055fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
317155fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
317255fcf09bSChristopher J. PeBenito 
317355fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
317455fcf09bSChristopher J. PeBenito 	if (!perms[value])
317555fcf09bSChristopher J. PeBenito 		return -ENOMEM;
317655fcf09bSChristopher J. PeBenito 
317755fcf09bSChristopher J. PeBenito 	return 0;
317855fcf09bSChristopher J. PeBenito }
317955fcf09bSChristopher J. PeBenito 
3180aa8e712cSStephen Smalley int security_get_permissions(struct selinux_state *state,
3181aa8e712cSStephen Smalley 			     char *class, char ***perms, int *nperms)
318255fcf09bSChristopher J. PeBenito {
3183aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
31844b02b524SEric Paris 	int rc, i;
318555fcf09bSChristopher J. PeBenito 	struct class_datum *match;
318655fcf09bSChristopher J. PeBenito 
3187aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
318855fcf09bSChristopher J. PeBenito 
31894b02b524SEric Paris 	rc = -EINVAL;
3190aa8e712cSStephen Smalley 	match = hashtab_search(policydb->p_classes.table, class);
319155fcf09bSChristopher J. PeBenito 	if (!match) {
3192b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized class %s\n",
3193dd6f953aSHarvey Harrison 			__func__, class);
319455fcf09bSChristopher J. PeBenito 		goto out;
319555fcf09bSChristopher J. PeBenito 	}
319655fcf09bSChristopher J. PeBenito 
31974b02b524SEric Paris 	rc = -ENOMEM;
319855fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
31999f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
320055fcf09bSChristopher J. PeBenito 	if (!*perms)
320155fcf09bSChristopher J. PeBenito 		goto out;
320255fcf09bSChristopher J. PeBenito 
320355fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
320455fcf09bSChristopher J. PeBenito 		rc = hashtab_map(match->comdatum->permissions.table,
320555fcf09bSChristopher J. PeBenito 				get_permissions_callback, *perms);
32064b02b524SEric Paris 		if (rc)
320755fcf09bSChristopher J. PeBenito 			goto err;
320855fcf09bSChristopher J. PeBenito 	}
320955fcf09bSChristopher J. PeBenito 
321055fcf09bSChristopher J. PeBenito 	rc = hashtab_map(match->permissions.table, get_permissions_callback,
321155fcf09bSChristopher J. PeBenito 			*perms);
32124b02b524SEric Paris 	if (rc)
321355fcf09bSChristopher J. PeBenito 		goto err;
321455fcf09bSChristopher J. PeBenito 
321555fcf09bSChristopher J. PeBenito out:
3216aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
321755fcf09bSChristopher J. PeBenito 	return rc;
321855fcf09bSChristopher J. PeBenito 
321955fcf09bSChristopher J. PeBenito err:
3220aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
322155fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
322255fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
322355fcf09bSChristopher J. PeBenito 	kfree(*perms);
322455fcf09bSChristopher J. PeBenito 	return rc;
322555fcf09bSChristopher J. PeBenito }
322655fcf09bSChristopher J. PeBenito 
3227aa8e712cSStephen Smalley int security_get_reject_unknown(struct selinux_state *state)
32283f12070eSEric Paris {
3229aa8e712cSStephen Smalley 	return state->ss->policydb.reject_unknown;
32303f12070eSEric Paris }
32313f12070eSEric Paris 
3232aa8e712cSStephen Smalley int security_get_allow_unknown(struct selinux_state *state)
32333f12070eSEric Paris {
3234aa8e712cSStephen Smalley 	return state->ss->policydb.allow_unknown;
32353f12070eSEric Paris }
32363f12070eSEric Paris 
32373bb56b25SPaul Moore /**
32383bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
32393bb56b25SPaul Moore  * @req_cap: capability
32403bb56b25SPaul Moore  *
32413bb56b25SPaul Moore  * Description:
32423bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
32433bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
32443bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
32453bb56b25SPaul Moore  *
32463bb56b25SPaul Moore  */
3247aa8e712cSStephen Smalley int security_policycap_supported(struct selinux_state *state,
3248aa8e712cSStephen Smalley 				 unsigned int req_cap)
32493bb56b25SPaul Moore {
3250aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
32513bb56b25SPaul Moore 	int rc;
32523bb56b25SPaul Moore 
3253aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
3254aa8e712cSStephen Smalley 	rc = ebitmap_get_bit(&policydb->policycaps, req_cap);
3255aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
32563bb56b25SPaul Moore 
32573bb56b25SPaul Moore 	return rc;
32583bb56b25SPaul Moore }
32593bb56b25SPaul Moore 
3260376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3261376bd9cbSDarrel Goeddel 	u32 au_seqno;
3262376bd9cbSDarrel Goeddel 	struct context au_ctxt;
3263376bd9cbSDarrel Goeddel };
3264376bd9cbSDarrel Goeddel 
32659d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3266376bd9cbSDarrel Goeddel {
32679d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
32689d57a7f9SAhmed S. Darwish 
3269376bd9cbSDarrel Goeddel 	if (rule) {
3270376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
3271376bd9cbSDarrel Goeddel 		kfree(rule);
3272376bd9cbSDarrel Goeddel 	}
3273376bd9cbSDarrel Goeddel }
3274376bd9cbSDarrel Goeddel 
32759d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3276376bd9cbSDarrel Goeddel {
3277aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
3278aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
3279376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
3280376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
3281376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
3282376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
32839d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3284376bd9cbSDarrel Goeddel 	int rc = 0;
3285376bd9cbSDarrel Goeddel 
3286376bd9cbSDarrel Goeddel 	*rule = NULL;
3287376bd9cbSDarrel Goeddel 
3288aa8e712cSStephen Smalley 	if (!state->initialized)
32893ad40d64SSteve G 		return -EOPNOTSUPP;
3290376bd9cbSDarrel Goeddel 
3291376bd9cbSDarrel Goeddel 	switch (field) {
32923a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
32933a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
32943a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
32956e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
32966e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
32976e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3298376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
32995af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
3300376bd9cbSDarrel Goeddel 			return -EINVAL;
3301376bd9cbSDarrel Goeddel 		break;
33023a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
33033a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
33046e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
33056e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
330625985edcSLucas De Marchi 		/* we do not allow a range, indicated by the presence of '-' */
3307376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
3308376bd9cbSDarrel Goeddel 			return -EINVAL;
3309376bd9cbSDarrel Goeddel 		break;
3310376bd9cbSDarrel Goeddel 	default:
3311376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
3312376bd9cbSDarrel Goeddel 		return -EINVAL;
3313376bd9cbSDarrel Goeddel 	}
3314376bd9cbSDarrel Goeddel 
3315376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
3316376bd9cbSDarrel Goeddel 	if (!tmprule)
3317376bd9cbSDarrel Goeddel 		return -ENOMEM;
3318376bd9cbSDarrel Goeddel 
3319376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
3320376bd9cbSDarrel Goeddel 
3321aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
3322376bd9cbSDarrel Goeddel 
3323aa8e712cSStephen Smalley 	tmprule->au_seqno = state->ss->latest_granting;
3324376bd9cbSDarrel Goeddel 
3325376bd9cbSDarrel Goeddel 	switch (field) {
33263a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
33276e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
33284b02b524SEric Paris 		rc = -EINVAL;
3329aa8e712cSStephen Smalley 		userdatum = hashtab_search(policydb->p_users.table, rulestr);
3330376bd9cbSDarrel Goeddel 		if (!userdatum)
33314b02b524SEric Paris 			goto out;
3332376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
3333376bd9cbSDarrel Goeddel 		break;
33343a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
33356e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
33364b02b524SEric Paris 		rc = -EINVAL;
3337aa8e712cSStephen Smalley 		roledatum = hashtab_search(policydb->p_roles.table, rulestr);
3338376bd9cbSDarrel Goeddel 		if (!roledatum)
33394b02b524SEric Paris 			goto out;
3340376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
3341376bd9cbSDarrel Goeddel 		break;
33423a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
33436e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
33444b02b524SEric Paris 		rc = -EINVAL;
3345aa8e712cSStephen Smalley 		typedatum = hashtab_search(policydb->p_types.table, rulestr);
3346376bd9cbSDarrel Goeddel 		if (!typedatum)
33474b02b524SEric Paris 			goto out;
3348376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
3349376bd9cbSDarrel Goeddel 		break;
33503a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
33513a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
33526e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
33536e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
3354aa8e712cSStephen Smalley 		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3355aa8e712cSStephen Smalley 				     GFP_ATOMIC);
33564b02b524SEric Paris 		if (rc)
33574b02b524SEric Paris 			goto out;
3358376bd9cbSDarrel Goeddel 		break;
3359376bd9cbSDarrel Goeddel 	}
33604b02b524SEric Paris 	rc = 0;
33614b02b524SEric Paris out:
3362aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
3363376bd9cbSDarrel Goeddel 
3364376bd9cbSDarrel Goeddel 	if (rc) {
3365376bd9cbSDarrel Goeddel 		selinux_audit_rule_free(tmprule);
3366376bd9cbSDarrel Goeddel 		tmprule = NULL;
3367376bd9cbSDarrel Goeddel 	}
3368376bd9cbSDarrel Goeddel 
3369376bd9cbSDarrel Goeddel 	*rule = tmprule;
3370376bd9cbSDarrel Goeddel 
3371376bd9cbSDarrel Goeddel 	return rc;
3372376bd9cbSDarrel Goeddel }
3373376bd9cbSDarrel Goeddel 
33749d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
33759d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
33769d57a7f9SAhmed S. Darwish {
33779d57a7f9SAhmed S. Darwish 	int i;
33789d57a7f9SAhmed S. Darwish 
33799d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
33809d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
33819d57a7f9SAhmed S. Darwish 		switch (f->type) {
33829d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
33839d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
33849d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
33859d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
33869d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
33879d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
33889d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
33899d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
33909d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
33919d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
33929d57a7f9SAhmed S. Darwish 			return 1;
33939d57a7f9SAhmed S. Darwish 		}
33949d57a7f9SAhmed S. Darwish 	}
33959d57a7f9SAhmed S. Darwish 
33969d57a7f9SAhmed S. Darwish 	return 0;
33979d57a7f9SAhmed S. Darwish }
33989d57a7f9SAhmed S. Darwish 
339990462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3400376bd9cbSDarrel Goeddel {
3401aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
3402376bd9cbSDarrel Goeddel 	struct context *ctxt;
3403376bd9cbSDarrel Goeddel 	struct mls_level *level;
34049d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
3405376bd9cbSDarrel Goeddel 	int match = 0;
3406376bd9cbSDarrel Goeddel 
34079ad42a79SRichard Guy Briggs 	if (unlikely(!rule)) {
34089ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3409376bd9cbSDarrel Goeddel 		return -ENOENT;
3410376bd9cbSDarrel Goeddel 	}
3411376bd9cbSDarrel Goeddel 
3412aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
3413376bd9cbSDarrel Goeddel 
3414aa8e712cSStephen Smalley 	if (rule->au_seqno < state->ss->latest_granting) {
3415376bd9cbSDarrel Goeddel 		match = -ESTALE;
3416376bd9cbSDarrel Goeddel 		goto out;
3417376bd9cbSDarrel Goeddel 	}
3418376bd9cbSDarrel Goeddel 
341924ed7fdaSOndrej Mosnacek 	ctxt = sidtab_search(state->ss->sidtab, sid);
34209ad42a79SRichard Guy Briggs 	if (unlikely(!ctxt)) {
34219ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
34229a2f44f0SStephen Smalley 			  sid);
3423376bd9cbSDarrel Goeddel 		match = -ENOENT;
3424376bd9cbSDarrel Goeddel 		goto out;
3425376bd9cbSDarrel Goeddel 	}
3426376bd9cbSDarrel Goeddel 
3427376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
3428376bd9cbSDarrel Goeddel 	   without a match */
3429376bd9cbSDarrel Goeddel 	switch (field) {
34303a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
34316e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3432376bd9cbSDarrel Goeddel 		switch (op) {
34335af75d8dSAl Viro 		case Audit_equal:
3434376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
3435376bd9cbSDarrel Goeddel 			break;
34365af75d8dSAl Viro 		case Audit_not_equal:
3437376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
3438376bd9cbSDarrel Goeddel 			break;
3439376bd9cbSDarrel Goeddel 		}
3440376bd9cbSDarrel Goeddel 		break;
34413a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
34426e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3443376bd9cbSDarrel Goeddel 		switch (op) {
34445af75d8dSAl Viro 		case Audit_equal:
3445376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
3446376bd9cbSDarrel Goeddel 			break;
34475af75d8dSAl Viro 		case Audit_not_equal:
3448376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
3449376bd9cbSDarrel Goeddel 			break;
3450376bd9cbSDarrel Goeddel 		}
3451376bd9cbSDarrel Goeddel 		break;
34523a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
34536e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3454376bd9cbSDarrel Goeddel 		switch (op) {
34555af75d8dSAl Viro 		case Audit_equal:
3456376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
3457376bd9cbSDarrel Goeddel 			break;
34585af75d8dSAl Viro 		case Audit_not_equal:
3459376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
3460376bd9cbSDarrel Goeddel 			break;
3461376bd9cbSDarrel Goeddel 		}
3462376bd9cbSDarrel Goeddel 		break;
34633a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
34643a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
34656e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
34666e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
34676e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
34686e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
3469376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3470376bd9cbSDarrel Goeddel 		switch (op) {
34715af75d8dSAl Viro 		case Audit_equal:
3472376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3473376bd9cbSDarrel Goeddel 					     level);
3474376bd9cbSDarrel Goeddel 			break;
34755af75d8dSAl Viro 		case Audit_not_equal:
3476376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3477376bd9cbSDarrel Goeddel 					      level);
3478376bd9cbSDarrel Goeddel 			break;
34795af75d8dSAl Viro 		case Audit_lt:
3480376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3481376bd9cbSDarrel Goeddel 					       level) &&
3482376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3483376bd9cbSDarrel Goeddel 					       level));
3484376bd9cbSDarrel Goeddel 			break;
34855af75d8dSAl Viro 		case Audit_le:
3486376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3487376bd9cbSDarrel Goeddel 					      level);
3488376bd9cbSDarrel Goeddel 			break;
34895af75d8dSAl Viro 		case Audit_gt:
3490376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
3491376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
3492376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
3493376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
3494376bd9cbSDarrel Goeddel 			break;
34955af75d8dSAl Viro 		case Audit_ge:
3496376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
3497376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
3498376bd9cbSDarrel Goeddel 			break;
3499376bd9cbSDarrel Goeddel 		}
3500376bd9cbSDarrel Goeddel 	}
3501376bd9cbSDarrel Goeddel 
3502376bd9cbSDarrel Goeddel out:
3503aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
3504376bd9cbSDarrel Goeddel 	return match;
3505376bd9cbSDarrel Goeddel }
3506376bd9cbSDarrel Goeddel 
35079d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules;
3508376bd9cbSDarrel Goeddel 
3509562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3510376bd9cbSDarrel Goeddel {
3511376bd9cbSDarrel Goeddel 	int err = 0;
3512376bd9cbSDarrel Goeddel 
3513376bd9cbSDarrel Goeddel 	if (event == AVC_CALLBACK_RESET && aurule_callback)
3514376bd9cbSDarrel Goeddel 		err = aurule_callback();
3515376bd9cbSDarrel Goeddel 	return err;
3516376bd9cbSDarrel Goeddel }
3517376bd9cbSDarrel Goeddel 
3518376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3519376bd9cbSDarrel Goeddel {
3520376bd9cbSDarrel Goeddel 	int err;
3521376bd9cbSDarrel Goeddel 
3522562c99f2SWanlong Gao 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3523376bd9cbSDarrel Goeddel 	if (err)
3524376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
3525376bd9cbSDarrel Goeddel 
3526376bd9cbSDarrel Goeddel 	return err;
3527376bd9cbSDarrel Goeddel }
3528376bd9cbSDarrel Goeddel __initcall(aurule_init);
3529376bd9cbSDarrel Goeddel 
35307420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
35317420ed23SVenkat Yekkirala /**
35325778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
35335778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
35345dbe1eb0SPaul Moore  * @sid: the SELinux SID
35357420ed23SVenkat Yekkirala  *
35367420ed23SVenkat Yekkirala  * Description:
35377420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
35385778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
35395778eabdSPaul Moore  * already been initialized.
35407420ed23SVenkat Yekkirala  *
35417420ed23SVenkat Yekkirala  */
35425778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
35435dbe1eb0SPaul Moore 				      u32 sid)
35447420ed23SVenkat Yekkirala {
35455dbe1eb0SPaul Moore 	u32 *sid_cache;
35467420ed23SVenkat Yekkirala 
35475dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
35485dbe1eb0SPaul Moore 	if (sid_cache == NULL)
35495dbe1eb0SPaul Moore 		return;
35505778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
35515dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
35525dbe1eb0SPaul Moore 		kfree(sid_cache);
35535778eabdSPaul Moore 		return;
35540ec8abd7SJesper Juhl 	}
35557420ed23SVenkat Yekkirala 
35565dbe1eb0SPaul Moore 	*sid_cache = sid;
35575dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
35585dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
35595778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
35607420ed23SVenkat Yekkirala }
35617420ed23SVenkat Yekkirala 
35627420ed23SVenkat Yekkirala /**
35635778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
35647420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
35657420ed23SVenkat Yekkirala  * @sid: the SELinux SID
35667420ed23SVenkat Yekkirala  *
35677420ed23SVenkat Yekkirala  * Description:
35685778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
35697420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
357025985edcSLucas De Marchi  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
35715dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
35725dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
35735dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
35745dbe1eb0SPaul Moore  * failure.
35757420ed23SVenkat Yekkirala  *
35767420ed23SVenkat Yekkirala  */
3577aa8e712cSStephen Smalley int security_netlbl_secattr_to_sid(struct selinux_state *state,
3578aa8e712cSStephen Smalley 				   struct netlbl_lsm_secattr *secattr,
35797420ed23SVenkat Yekkirala 				   u32 *sid)
35807420ed23SVenkat Yekkirala {
3581aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
358224ed7fdaSOndrej Mosnacek 	struct sidtab *sidtab = state->ss->sidtab;
35837ae9f23cSEric Paris 	int rc;
35847420ed23SVenkat Yekkirala 	struct context *ctx;
35857420ed23SVenkat Yekkirala 	struct context ctx_new;
35865778eabdSPaul Moore 
3587aa8e712cSStephen Smalley 	if (!state->initialized) {
35885778eabdSPaul Moore 		*sid = SECSID_NULL;
35895778eabdSPaul Moore 		return 0;
35905778eabdSPaul Moore 	}
35917420ed23SVenkat Yekkirala 
3592aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
35937420ed23SVenkat Yekkirala 
35947ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
35955dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
35967ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
359716efd454SPaul Moore 		*sid = secattr->attr.secid;
35987ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
35997ae9f23cSEric Paris 		rc = -EIDRM;
3600aa8e712cSStephen Smalley 		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
36017420ed23SVenkat Yekkirala 		if (ctx == NULL)
36027ae9f23cSEric Paris 			goto out;
36037420ed23SVenkat Yekkirala 
360481990fbdSPaul Moore 		context_init(&ctx_new);
36057420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
36067420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
36077420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
3608aa8e712cSStephen Smalley 		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3609701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3610aa8e712cSStephen Smalley 			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
36117ae9f23cSEric Paris 			if (rc)
36127ae9f23cSEric Paris 				goto out;
36137420ed23SVenkat Yekkirala 		}
36147ae9f23cSEric Paris 		rc = -EIDRM;
3615aa8e712cSStephen Smalley 		if (!mls_context_isvalid(policydb, &ctx_new))
36167ae9f23cSEric Paris 			goto out_free;
36177420ed23SVenkat Yekkirala 
3618aa8e712cSStephen Smalley 		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
36197ae9f23cSEric Paris 		if (rc)
36207ae9f23cSEric Paris 			goto out_free;
36217420ed23SVenkat Yekkirala 
36225dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
36235778eabdSPaul Moore 
36247420ed23SVenkat Yekkirala 		ebitmap_destroy(&ctx_new.range.level[0].cat);
36257ae9f23cSEric Paris 	} else
3626388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
36277420ed23SVenkat Yekkirala 
3628aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
36297ae9f23cSEric Paris 	return 0;
36307ae9f23cSEric Paris out_free:
36317ae9f23cSEric Paris 	ebitmap_destroy(&ctx_new.range.level[0].cat);
36327ae9f23cSEric Paris out:
3633aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
36347420ed23SVenkat Yekkirala 	return rc;
36357420ed23SVenkat Yekkirala }
36367420ed23SVenkat Yekkirala 
36377420ed23SVenkat Yekkirala /**
36385778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
36395778eabdSPaul Moore  * @sid: the SELinux SID
36405778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
36417420ed23SVenkat Yekkirala  *
36427420ed23SVenkat Yekkirala  * Description:
36435778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
36445778eabdSPaul Moore  * Returns zero on success, negative values on failure.
36457420ed23SVenkat Yekkirala  *
36467420ed23SVenkat Yekkirala  */
3647aa8e712cSStephen Smalley int security_netlbl_sid_to_secattr(struct selinux_state *state,
3648aa8e712cSStephen Smalley 				   u32 sid, struct netlbl_lsm_secattr *secattr)
36497420ed23SVenkat Yekkirala {
3650aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
365199d854d2SPaul Moore 	int rc;
36527420ed23SVenkat Yekkirala 	struct context *ctx;
36537420ed23SVenkat Yekkirala 
3654aa8e712cSStephen Smalley 	if (!state->initialized)
36557420ed23SVenkat Yekkirala 		return 0;
36567420ed23SVenkat Yekkirala 
3657aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
36584b02b524SEric Paris 
365999d854d2SPaul Moore 	rc = -ENOENT;
366024ed7fdaSOndrej Mosnacek 	ctx = sidtab_search(state->ss->sidtab, sid);
36614b02b524SEric Paris 	if (ctx == NULL)
36624b02b524SEric Paris 		goto out;
36634b02b524SEric Paris 
36644b02b524SEric Paris 	rc = -ENOMEM;
3665aa8e712cSStephen Smalley 	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
36667420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
36674b02b524SEric Paris 	if (secattr->domain == NULL)
36684b02b524SEric Paris 		goto out;
36694b02b524SEric Paris 
36708d75899dSPaul Moore 	secattr->attr.secid = sid;
36718d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3672aa8e712cSStephen Smalley 	mls_export_netlbl_lvl(policydb, ctx, secattr);
3673aa8e712cSStephen Smalley 	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
36744b02b524SEric Paris out:
3675aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
3676f8687afeSPaul Moore 	return rc;
3677f8687afeSPaul Moore }
36787420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3679cee74f47SEric Paris 
3680cee74f47SEric Paris /**
3681cee74f47SEric Paris  * security_read_policy - read the policy.
3682cee74f47SEric Paris  * @data: binary policy data
3683cee74f47SEric Paris  * @len: length of data in bytes
3684cee74f47SEric Paris  *
3685cee74f47SEric Paris  */
3686aa8e712cSStephen Smalley int security_read_policy(struct selinux_state *state,
3687aa8e712cSStephen Smalley 			 void **data, size_t *len)
3688cee74f47SEric Paris {
3689aa8e712cSStephen Smalley 	struct policydb *policydb = &state->ss->policydb;
3690cee74f47SEric Paris 	int rc;
3691cee74f47SEric Paris 	struct policy_file fp;
3692cee74f47SEric Paris 
3693aa8e712cSStephen Smalley 	if (!state->initialized)
3694cee74f47SEric Paris 		return -EINVAL;
3695cee74f47SEric Paris 
3696aa8e712cSStephen Smalley 	*len = security_policydb_len(state);
3697cee74f47SEric Paris 
3698845ca30fSEric Paris 	*data = vmalloc_user(*len);
3699cee74f47SEric Paris 	if (!*data)
3700cee74f47SEric Paris 		return -ENOMEM;
3701cee74f47SEric Paris 
3702cee74f47SEric Paris 	fp.data = *data;
3703cee74f47SEric Paris 	fp.len = *len;
3704cee74f47SEric Paris 
3705aa8e712cSStephen Smalley 	read_lock(&state->ss->policy_rwlock);
3706aa8e712cSStephen Smalley 	rc = policydb_write(policydb, &fp);
3707aa8e712cSStephen Smalley 	read_unlock(&state->ss->policy_rwlock);
3708cee74f47SEric Paris 
3709cee74f47SEric Paris 	if (rc)
3710cee74f47SEric Paris 		return rc;
3711cee74f47SEric Paris 
3712cee74f47SEric Paris 	*len = (unsigned long)fp.data - (unsigned long)*data;
3713cee74f47SEric Paris 	return 0;
3714cee74f47SEric Paris 
3715cee74f47SEric Paris }
3716