xref: /openbmc/linux/security/selinux/ss/services.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Implementation of the security services.
41da177e4SLinus Torvalds  *
50fe53224SStephen Smalley  * Authors : Stephen Smalley, <stephen.smalley.work@gmail.com>
61da177e4SLinus Torvalds  *	     James Morris <jmorris@redhat.com>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *	Support for enhanced MLS infrastructure.
11376bd9cbSDarrel Goeddel  *	Support for context based audit filters.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *	Added conditional policy language extensions
161da177e4SLinus Torvalds  *
1782c21bfaSPaul Moore  * Updated: Hewlett-Packard <paul@paul-moore.com>
187420ed23SVenkat Yekkirala  *
197420ed23SVenkat Yekkirala  *      Added support for NetLabel
203bb56b25SPaul Moore  *      Added support for the policy capability bitmap
217420ed23SVenkat Yekkirala  *
22b94c7e67SChad Sellers  * Updated: Chad Sellers <csellers@tresys.com>
23b94c7e67SChad Sellers  *
24b94c7e67SChad Sellers  *  Added validation of kernel classes and permissions
25b94c7e67SChad Sellers  *
2644c2d9bdSKaiGai Kohei  * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
2744c2d9bdSKaiGai Kohei  *
2844c2d9bdSKaiGai Kohei  *  Added support for bounds domain and audit messaged on masked permissions
2944c2d9bdSKaiGai Kohei  *
300719aaf5SGuido Trentalancia  * Updated: Guido Trentalancia <guido@trentalancia.com>
310719aaf5SGuido Trentalancia  *
320719aaf5SGuido Trentalancia  *  Added support for runtime switching of the policy type
330719aaf5SGuido Trentalancia  *
3444c2d9bdSKaiGai Kohei  * Copyright (C) 2008, 2009 NEC Corporation
353bb56b25SPaul Moore  * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
36376bd9cbSDarrel Goeddel  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
37b94c7e67SChad Sellers  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
381da177e4SLinus Torvalds  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
391da177e4SLinus Torvalds  */
401da177e4SLinus Torvalds #include <linux/kernel.h>
411da177e4SLinus Torvalds #include <linux/slab.h>
421da177e4SLinus Torvalds #include <linux/string.h>
431da177e4SLinus Torvalds #include <linux/spinlock.h>
449f2ad665SPaul Moore #include <linux/rcupdate.h>
451da177e4SLinus Torvalds #include <linux/errno.h>
461da177e4SLinus Torvalds #include <linux/in.h>
471da177e4SLinus Torvalds #include <linux/sched.h>
481da177e4SLinus Torvalds #include <linux/audit.h>
49f0d3d989SStephen Rothwell #include <linux/vmalloc.h>
501aea7808SCasey Schaufler #include <linux/lsm_hooks.h>
517420ed23SVenkat Yekkirala #include <net/netlabel.h>
52bb003079SIngo Molnar 
531da177e4SLinus Torvalds #include "flask.h"
541da177e4SLinus Torvalds #include "avc.h"
551da177e4SLinus Torvalds #include "avc_ss.h"
561da177e4SLinus Torvalds #include "security.h"
571da177e4SLinus Torvalds #include "context.h"
581da177e4SLinus Torvalds #include "policydb.h"
591da177e4SLinus Torvalds #include "sidtab.h"
601da177e4SLinus Torvalds #include "services.h"
611da177e4SLinus Torvalds #include "conditional.h"
621da177e4SLinus Torvalds #include "mls.h"
637420ed23SVenkat Yekkirala #include "objsec.h"
64c60475bfSPaul Moore #include "netlabel.h"
653de4bab5SPaul Moore #include "xfrm.h"
6602752760SPaul Moore #include "ebitmap.h"
679d57a7f9SAhmed S. Darwish #include "audit.h"
68339949beSStephen Smalley #include "policycap_names.h"
69fdd1ffe8SLakshmi Ramasubramanian #include "ima.h"
704dc2fce3SStephen Smalley 
716406887aSOndrej Mosnacek struct selinux_policy_convert_data {
726406887aSOndrej Mosnacek 	struct convert_context_args args;
736406887aSOndrej Mosnacek 	struct sidtab_convert_params sidtab_params;
746406887aSOndrej Mosnacek };
756406887aSOndrej Mosnacek 
761da177e4SLinus Torvalds /* Forward declaration. */
77aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *policydb,
78aa8e712cSStephen Smalley 				    struct context *context,
79aa8e712cSStephen Smalley 				    char **scontext,
801da177e4SLinus Torvalds 				    u32 *scontext_len);
811da177e4SLinus Torvalds 
82d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *policydb,
83d97bd23cSOndrej Mosnacek 				  struct sidtab *sidtab,
84d97bd23cSOndrej Mosnacek 				  struct sidtab_entry *entry,
85d97bd23cSOndrej Mosnacek 				  char **scontext,
86d97bd23cSOndrej Mosnacek 				  u32 *scontext_len);
87d97bd23cSOndrej Mosnacek 
88aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
89aa8e712cSStephen Smalley 				      struct context *scontext,
90d9250deaSKaiGai Kohei 				      struct context *tcontext,
91d9250deaSKaiGai Kohei 				      u16 tclass,
92fa1aa143SJeff Vander Stoep 				      struct av_decision *avd,
93fa1aa143SJeff Vander Stoep 				      struct extended_perms *xperms);
94c6d3aaa4SStephen Smalley 
selinux_set_mapping(struct policydb * pol,const struct security_class_mapping * map,struct selinux_map * out_map)95c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol,
96ded34574SChristian Göttsche 			       const struct security_class_mapping *map,
97aa8e712cSStephen Smalley 			       struct selinux_map *out_map)
98c6d3aaa4SStephen Smalley {
99c6d3aaa4SStephen Smalley 	u16 i, j;
100c6d3aaa4SStephen Smalley 	bool print_unknown_handle = false;
101c6d3aaa4SStephen Smalley 
102c6d3aaa4SStephen Smalley 	/* Find number of classes in the input mapping */
103c6d3aaa4SStephen Smalley 	if (!map)
104c6d3aaa4SStephen Smalley 		return -EINVAL;
105c6d3aaa4SStephen Smalley 	i = 0;
106c6d3aaa4SStephen Smalley 	while (map[i].name)
107c6d3aaa4SStephen Smalley 		i++;
108c6d3aaa4SStephen Smalley 
109c6d3aaa4SStephen Smalley 	/* Allocate space for the class records, plus one for class zero */
110aa8e712cSStephen Smalley 	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
111aa8e712cSStephen Smalley 	if (!out_map->mapping)
112c6d3aaa4SStephen Smalley 		return -ENOMEM;
113c6d3aaa4SStephen Smalley 
114c6d3aaa4SStephen Smalley 	/* Store the raw class and permission values */
115c6d3aaa4SStephen Smalley 	j = 0;
116c6d3aaa4SStephen Smalley 	while (map[j].name) {
117ded34574SChristian Göttsche 		const struct security_class_mapping *p_in = map + (j++);
118aa8e712cSStephen Smalley 		struct selinux_mapping *p_out = out_map->mapping + j;
119002903e1SChristian Göttsche 		u16 k;
120c6d3aaa4SStephen Smalley 
121c6d3aaa4SStephen Smalley 		/* An empty class string skips ahead */
122c6d3aaa4SStephen Smalley 		if (!strcmp(p_in->name, "")) {
123c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
124c6d3aaa4SStephen Smalley 			continue;
125c6d3aaa4SStephen Smalley 		}
126c6d3aaa4SStephen Smalley 
127c6d3aaa4SStephen Smalley 		p_out->value = string_to_security_class(pol, p_in->name);
128c6d3aaa4SStephen Smalley 		if (!p_out->value) {
129b54c85c1Speter enderborg 			pr_info("SELinux:  Class %s not defined in policy.\n",
130c6d3aaa4SStephen Smalley 			       p_in->name);
131c6d3aaa4SStephen Smalley 			if (pol->reject_unknown)
132c6d3aaa4SStephen Smalley 				goto err;
133c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
134c6d3aaa4SStephen Smalley 			print_unknown_handle = true;
135c6d3aaa4SStephen Smalley 			continue;
136c6d3aaa4SStephen Smalley 		}
137c6d3aaa4SStephen Smalley 
138c6d3aaa4SStephen Smalley 		k = 0;
139342e9157SMatthias Kaehlcke 		while (p_in->perms[k]) {
140c6d3aaa4SStephen Smalley 			/* An empty permission string skips ahead */
141c6d3aaa4SStephen Smalley 			if (!*p_in->perms[k]) {
142c6d3aaa4SStephen Smalley 				k++;
143c6d3aaa4SStephen Smalley 				continue;
144c6d3aaa4SStephen Smalley 			}
145c6d3aaa4SStephen Smalley 			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
146c6d3aaa4SStephen Smalley 							    p_in->perms[k]);
147c6d3aaa4SStephen Smalley 			if (!p_out->perms[k]) {
148b54c85c1Speter enderborg 				pr_info("SELinux:  Permission %s in class %s not defined in policy.\n",
149c6d3aaa4SStephen Smalley 				       p_in->perms[k], p_in->name);
150c6d3aaa4SStephen Smalley 				if (pol->reject_unknown)
151c6d3aaa4SStephen Smalley 					goto err;
152c6d3aaa4SStephen Smalley 				print_unknown_handle = true;
153c6d3aaa4SStephen Smalley 			}
154c6d3aaa4SStephen Smalley 
155c6d3aaa4SStephen Smalley 			k++;
156c6d3aaa4SStephen Smalley 		}
157c6d3aaa4SStephen Smalley 		p_out->num_perms = k;
158c6d3aaa4SStephen Smalley 	}
159c6d3aaa4SStephen Smalley 
160c6d3aaa4SStephen Smalley 	if (print_unknown_handle)
161b54c85c1Speter enderborg 		pr_info("SELinux: the above unknown classes and permissions will be %s\n",
162c6d3aaa4SStephen Smalley 		       pol->allow_unknown ? "allowed" : "denied");
163c6d3aaa4SStephen Smalley 
164aa8e712cSStephen Smalley 	out_map->size = i;
165c6d3aaa4SStephen Smalley 	return 0;
166c6d3aaa4SStephen Smalley err:
167aa8e712cSStephen Smalley 	kfree(out_map->mapping);
168aa8e712cSStephen Smalley 	out_map->mapping = NULL;
169c6d3aaa4SStephen Smalley 	return -EINVAL;
170c6d3aaa4SStephen Smalley }
171c6d3aaa4SStephen Smalley 
172c6d3aaa4SStephen Smalley /*
173c6d3aaa4SStephen Smalley  * Get real, policy values from mapped values
174c6d3aaa4SStephen Smalley  */
175c6d3aaa4SStephen Smalley 
unmap_class(struct selinux_map * map,u16 tclass)176aa8e712cSStephen Smalley static u16 unmap_class(struct selinux_map *map, u16 tclass)
177c6d3aaa4SStephen Smalley {
178aa8e712cSStephen Smalley 	if (tclass < map->size)
179aa8e712cSStephen Smalley 		return map->mapping[tclass].value;
180c6d3aaa4SStephen Smalley 
181c6d3aaa4SStephen Smalley 	return tclass;
182c6d3aaa4SStephen Smalley }
183c6d3aaa4SStephen Smalley 
1846f5317e7SHarry Ciao /*
1856f5317e7SHarry Ciao  * Get kernel value for class from its policy value
1866f5317e7SHarry Ciao  */
map_class(struct selinux_map * map,u16 pol_value)187aa8e712cSStephen Smalley static u16 map_class(struct selinux_map *map, u16 pol_value)
1886f5317e7SHarry Ciao {
1896f5317e7SHarry Ciao 	u16 i;
1906f5317e7SHarry Ciao 
191aa8e712cSStephen Smalley 	for (i = 1; i < map->size; i++) {
192aa8e712cSStephen Smalley 		if (map->mapping[i].value == pol_value)
1936f5317e7SHarry Ciao 			return i;
1946f5317e7SHarry Ciao 	}
1956f5317e7SHarry Ciao 
19685cd6da5SStephen Smalley 	return SECCLASS_NULL;
1976f5317e7SHarry Ciao }
1986f5317e7SHarry Ciao 
map_decision(struct selinux_map * map,u16 tclass,struct av_decision * avd,int allow_unknown)199aa8e712cSStephen Smalley static void map_decision(struct selinux_map *map,
200aa8e712cSStephen Smalley 			 u16 tclass, struct av_decision *avd,
201c6d3aaa4SStephen Smalley 			 int allow_unknown)
202c6d3aaa4SStephen Smalley {
203aa8e712cSStephen Smalley 	if (tclass < map->size) {
204aa8e712cSStephen Smalley 		struct selinux_mapping *mapping = &map->mapping[tclass];
205aa8e712cSStephen Smalley 		unsigned int i, n = mapping->num_perms;
206c6d3aaa4SStephen Smalley 		u32 result;
207c6d3aaa4SStephen Smalley 
208c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
209aa8e712cSStephen Smalley 			if (avd->allowed & mapping->perms[i])
210aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
211aa8e712cSStephen Smalley 			if (allow_unknown && !mapping->perms[i])
212aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
213c6d3aaa4SStephen Smalley 		}
214c6d3aaa4SStephen Smalley 		avd->allowed = result;
215c6d3aaa4SStephen Smalley 
216c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++)
217aa8e712cSStephen Smalley 			if (avd->auditallow & mapping->perms[i])
218aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
219c6d3aaa4SStephen Smalley 		avd->auditallow = result;
220c6d3aaa4SStephen Smalley 
221c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
222aa8e712cSStephen Smalley 			if (avd->auditdeny & mapping->perms[i])
223aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
224aa8e712cSStephen Smalley 			if (!allow_unknown && !mapping->perms[i])
225aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
226c6d3aaa4SStephen Smalley 		}
2270bce9527SEric Paris 		/*
2280bce9527SEric Paris 		 * In case the kernel has a bug and requests a permission
2290bce9527SEric Paris 		 * between num_perms and the maximum permission number, we
2300bce9527SEric Paris 		 * should audit that denial
2310bce9527SEric Paris 		 */
2320bce9527SEric Paris 		for (; i < (sizeof(u32)*8); i++)
233aa4b6051SChristian Göttsche 			result |= (u32)1<<i;
234c6d3aaa4SStephen Smalley 		avd->auditdeny = result;
235c6d3aaa4SStephen Smalley 	}
236c6d3aaa4SStephen Smalley }
237c6d3aaa4SStephen Smalley 
security_mls_enabled(void)238e67b7985SStephen Smalley int security_mls_enabled(void)
2390719aaf5SGuido Trentalancia {
24046169802SStephen Smalley 	int mls_enabled;
2411b8b31a2SStephen Smalley 	struct selinux_policy *policy;
242aa8e712cSStephen Smalley 
243e67b7985SStephen Smalley 	if (!selinux_initialized())
24446169802SStephen Smalley 		return 0;
24546169802SStephen Smalley 
2461b8b31a2SStephen Smalley 	rcu_read_lock();
247e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
2481b8b31a2SStephen Smalley 	mls_enabled = policy->policydb.mls_enabled;
2491b8b31a2SStephen Smalley 	rcu_read_unlock();
25046169802SStephen Smalley 	return 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  */
constraint_expr_eval(struct policydb * policydb,struct context * scontext,struct context * tcontext,struct context * xcontext,struct constraint_expr * cexpr)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  */
dump_masked_av_helper(void * k,void * d,void * args)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 
security_dump_masked_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,u32 permissions,const char * reason)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 &&
48203414a49SOndrej Mosnacek 	    hashtab_map(&common_dat->permissions.table,
48344c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
48444c2d9bdSKaiGai Kohei 		goto out;
48544c2d9bdSKaiGai Kohei 
48603414a49SOndrej Mosnacek 	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 
52844c2d9bdSKaiGai Kohei /*
529d9250deaSKaiGai Kohei  * security_boundary_permission - drops violated permissions
530d9250deaSKaiGai Kohei  * on boundary constraint.
531d9250deaSKaiGai Kohei  */
type_attribute_bounds_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd)532aa8e712cSStephen Smalley static void type_attribute_bounds_av(struct policydb *policydb,
533aa8e712cSStephen Smalley 				     struct context *scontext,
534d9250deaSKaiGai Kohei 				     struct context *tcontext,
535d9250deaSKaiGai Kohei 				     u16 tclass,
536d9250deaSKaiGai Kohei 				     struct av_decision *avd)
537d9250deaSKaiGai Kohei {
5382ae3ba39SKaiGai Kohei 	struct context lo_scontext;
5397ea59202SStephen Smalley 	struct context lo_tcontext, *tcontextp = tcontext;
5402ae3ba39SKaiGai Kohei 	struct av_decision lo_avd;
54123bdecb0SEric Paris 	struct type_datum *source;
54223bdecb0SEric Paris 	struct type_datum *target;
5432ae3ba39SKaiGai Kohei 	u32 masked = 0;
544d9250deaSKaiGai Kohei 
545f07ea1d4SOndrej Mosnacek 	source = policydb->type_val_to_struct[scontext->type - 1];
54623bdecb0SEric Paris 	BUG_ON(!source);
54723bdecb0SEric Paris 
5487ea59202SStephen Smalley 	if (!source->bounds)
5497ea59202SStephen Smalley 		return;
5507ea59202SStephen Smalley 
551f07ea1d4SOndrej Mosnacek 	target = policydb->type_val_to_struct[tcontext->type - 1];
55223bdecb0SEric Paris 	BUG_ON(!target);
55323bdecb0SEric Paris 
554d9250deaSKaiGai Kohei 	memset(&lo_avd, 0, sizeof(lo_avd));
555d9250deaSKaiGai Kohei 
556d9250deaSKaiGai Kohei 	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
557d9250deaSKaiGai Kohei 	lo_scontext.type = source->bounds;
558d9250deaSKaiGai Kohei 
5592ae3ba39SKaiGai Kohei 	if (target->bounds) {
5602ae3ba39SKaiGai Kohei 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5612ae3ba39SKaiGai Kohei 		lo_tcontext.type = target->bounds;
5627ea59202SStephen Smalley 		tcontextp = &lo_tcontext;
5632ae3ba39SKaiGai Kohei 	}
5642ae3ba39SKaiGai Kohei 
565aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, &lo_scontext,
5667ea59202SStephen Smalley 				  tcontextp,
5672ae3ba39SKaiGai Kohei 				  tclass,
568fa1aa143SJeff Vander Stoep 				  &lo_avd,
569fa1aa143SJeff Vander Stoep 				  NULL);
5702ae3ba39SKaiGai Kohei 
5717ea59202SStephen Smalley 	masked = ~lo_avd.allowed & avd->allowed;
5727ea59202SStephen Smalley 
5737ea59202SStephen Smalley 	if (likely(!masked))
5747ea59202SStephen Smalley 		return;		/* no masked permission */
5757ea59202SStephen Smalley 
576d9250deaSKaiGai Kohei 	/* mask violated permissions */
577d9250deaSKaiGai Kohei 	avd->allowed &= ~masked;
578d9250deaSKaiGai Kohei 
57944c2d9bdSKaiGai Kohei 	/* audit masked permissions */
580aa8e712cSStephen Smalley 	security_dump_masked_av(policydb, scontext, tcontext,
58144c2d9bdSKaiGai Kohei 				tclass, masked, "bounds");
582d9250deaSKaiGai Kohei }
583d9250deaSKaiGai Kohei 
584d9250deaSKaiGai Kohei /*
585fa1aa143SJeff Vander Stoep  * flag which drivers have permissions
5863d9047a0SChristian Göttsche  * only looking for ioctl based extended permissions
587fa1aa143SJeff Vander Stoep  */
services_compute_xperms_drivers(struct extended_perms * xperms,struct avtab_node * node)588fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers(
589fa1aa143SJeff Vander Stoep 		struct extended_perms *xperms,
590fa1aa143SJeff Vander Stoep 		struct avtab_node *node)
591fa1aa143SJeff Vander Stoep {
592fa1aa143SJeff Vander Stoep 	unsigned int i;
593fa1aa143SJeff Vander Stoep 
594fa1aa143SJeff Vander Stoep 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
595fa1aa143SJeff Vander Stoep 		/* if one or more driver has all permissions allowed */
596fa1aa143SJeff Vander Stoep 		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
597fa1aa143SJeff Vander Stoep 			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
598fa1aa143SJeff Vander Stoep 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
599fa1aa143SJeff Vander Stoep 		/* if allowing permissions within a driver */
600fa1aa143SJeff Vander Stoep 		security_xperm_set(xperms->drivers.p,
601fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->driver);
602fa1aa143SJeff Vander Stoep 	}
603fa1aa143SJeff Vander Stoep 
604fa1aa143SJeff Vander Stoep 	xperms->len = 1;
605fa1aa143SJeff Vander Stoep }
606fa1aa143SJeff Vander Stoep 
607fa1aa143SJeff Vander Stoep /*
608fa1aa143SJeff Vander Stoep  * Compute access vectors and extended permissions based on a context
609fa1aa143SJeff Vander Stoep  * structure pair for the permissions in a particular class.
6101da177e4SLinus Torvalds  */
context_struct_compute_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd,struct extended_perms * xperms)611aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
612aa8e712cSStephen Smalley 				      struct context *scontext,
6131da177e4SLinus Torvalds 				      struct context *tcontext,
6141da177e4SLinus Torvalds 				      u16 tclass,
615fa1aa143SJeff Vander Stoep 				      struct av_decision *avd,
616fa1aa143SJeff Vander Stoep 				      struct extended_perms *xperms)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds 	struct constraint_node *constraint;
6191da177e4SLinus Torvalds 	struct role_allow *ra;
6201da177e4SLinus Torvalds 	struct avtab_key avkey;
621782ebb99SStephen Smalley 	struct avtab_node *node;
6221da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
623782ebb99SStephen Smalley 	struct ebitmap *sattr, *tattr;
624782ebb99SStephen Smalley 	struct ebitmap_node *snode, *tnode;
625782ebb99SStephen Smalley 	unsigned int i, j;
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	avd->allowed = 0;
6281da177e4SLinus Torvalds 	avd->auditallow = 0;
6291da177e4SLinus Torvalds 	avd->auditdeny = 0xffffffff;
630fa1aa143SJeff Vander Stoep 	if (xperms) {
631fa1aa143SJeff Vander Stoep 		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
632fa1aa143SJeff Vander Stoep 		xperms->len = 0;
633fa1aa143SJeff Vander Stoep 	}
6341da177e4SLinus Torvalds 
635aa8e712cSStephen Smalley 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
636c6d3aaa4SStephen Smalley 		if (printk_ratelimit())
637b54c85c1Speter enderborg 			pr_warn("SELinux:  Invalid class %hu\n", tclass);
63819439d05SStephen Smalley 		return;
639c6d3aaa4SStephen Smalley 	}
6403f12070eSEric Paris 
641aa8e712cSStephen Smalley 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
6423f12070eSEric Paris 
6433f12070eSEric Paris 	/*
6441da177e4SLinus Torvalds 	 * If a specific type enforcement rule was defined for
6451da177e4SLinus Torvalds 	 * this permission check, then use it.
6461da177e4SLinus Torvalds 	 */
6471da177e4SLinus Torvalds 	avkey.target_class = tclass;
648fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
649acdf52d9SKent Overstreet 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
650acdf52d9SKent Overstreet 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
6519fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(sattr, snode, i) {
6529fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
653782ebb99SStephen Smalley 			avkey.source_type = i + 1;
654782ebb99SStephen Smalley 			avkey.target_type = j + 1;
655aa8e712cSStephen Smalley 			for (node = avtab_search_node(&policydb->te_avtab,
656aa8e712cSStephen Smalley 						      &avkey);
657dbc74c65SVesa-Matti Kari 			     node;
658782ebb99SStephen Smalley 			     node = avtab_search_node_next(node, avkey.specified)) {
659782ebb99SStephen Smalley 				if (node->key.specified == AVTAB_ALLOWED)
660fa1aa143SJeff Vander Stoep 					avd->allowed |= node->datum.u.data;
661782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITALLOW)
662fa1aa143SJeff Vander Stoep 					avd->auditallow |= node->datum.u.data;
663782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITDENY)
664fa1aa143SJeff Vander Stoep 					avd->auditdeny &= node->datum.u.data;
665fa1aa143SJeff Vander Stoep 				else if (xperms && (node->key.specified & AVTAB_XPERMS))
666fa1aa143SJeff Vander Stoep 					services_compute_xperms_drivers(xperms, node);
6671da177e4SLinus Torvalds 			}
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 			/* Check conditional av table for additional permissions */
670aa8e712cSStephen Smalley 			cond_compute_av(&policydb->te_cond_avtab, &avkey,
671fa1aa143SJeff Vander Stoep 					avd, xperms);
6721da177e4SLinus Torvalds 
673782ebb99SStephen Smalley 		}
674782ebb99SStephen Smalley 	}
675782ebb99SStephen Smalley 
6761da177e4SLinus Torvalds 	/*
6771da177e4SLinus Torvalds 	 * Remove any permissions prohibited by a constraint (this includes
6781da177e4SLinus Torvalds 	 * the MLS policy).
6791da177e4SLinus Torvalds 	 */
6801da177e4SLinus Torvalds 	constraint = tclass_datum->constraints;
6811da177e4SLinus Torvalds 	while (constraint) {
6821da177e4SLinus Torvalds 		if ((constraint->permissions & (avd->allowed)) &&
683aa8e712cSStephen Smalley 		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
6841da177e4SLinus Torvalds 					  constraint->expr)) {
685caabbdc0SKaiGai Kohei 			avd->allowed &= ~(constraint->permissions);
6861da177e4SLinus Torvalds 		}
6871da177e4SLinus Torvalds 		constraint = constraint->next;
6881da177e4SLinus Torvalds 	}
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	/*
6911da177e4SLinus Torvalds 	 * If checking process transition permission and the
6921da177e4SLinus Torvalds 	 * role is changing, then check the (current_role, new_role)
6931da177e4SLinus Torvalds 	 * pair.
6941da177e4SLinus Torvalds 	 */
695aa8e712cSStephen Smalley 	if (tclass == policydb->process_class &&
696aa8e712cSStephen Smalley 	    (avd->allowed & policydb->process_trans_perms) &&
6971da177e4SLinus Torvalds 	    scontext->role != tcontext->role) {
698aa8e712cSStephen Smalley 		for (ra = policydb->role_allow; ra; ra = ra->next) {
6991da177e4SLinus Torvalds 			if (scontext->role == ra->role &&
7001da177e4SLinus Torvalds 			    tcontext->role == ra->new_role)
7011da177e4SLinus Torvalds 				break;
7021da177e4SLinus Torvalds 		}
7031da177e4SLinus Torvalds 		if (!ra)
704aa8e712cSStephen Smalley 			avd->allowed &= ~policydb->process_trans_perms;
7051da177e4SLinus Torvalds 	}
7061da177e4SLinus Torvalds 
707d9250deaSKaiGai Kohei 	/*
708d9250deaSKaiGai Kohei 	 * If the given source and target types have boundary
709d9250deaSKaiGai Kohei 	 * constraint, lazy checks have to mask any violated
710d9250deaSKaiGai Kohei 	 * permission and notice it to userspace via audit.
711d9250deaSKaiGai Kohei 	 */
712aa8e712cSStephen Smalley 	type_attribute_bounds_av(policydb, scontext, tcontext,
71319439d05SStephen Smalley 				 tclass, avd);
71422df4adbSStephen Smalley }
71522df4adbSStephen Smalley 
security_validtrans_handle_fail(struct selinux_policy * policy,struct sidtab_entry * oentry,struct sidtab_entry * nentry,struct sidtab_entry * tentry,u16 tclass)716e67b7985SStephen Smalley static int security_validtrans_handle_fail(struct selinux_policy *policy,
717d97bd23cSOndrej Mosnacek 					struct sidtab_entry *oentry,
718d97bd23cSOndrej Mosnacek 					struct sidtab_entry *nentry,
719d97bd23cSOndrej Mosnacek 					struct sidtab_entry *tentry,
7201da177e4SLinus Torvalds 					u16 tclass)
7211da177e4SLinus Torvalds {
7221b8b31a2SStephen Smalley 	struct policydb *p = &policy->policydb;
7231b8b31a2SStephen Smalley 	struct sidtab *sidtab = policy->sidtab;
7241da177e4SLinus Torvalds 	char *o = NULL, *n = NULL, *t = NULL;
7251da177e4SLinus Torvalds 	u32 olen, nlen, tlen;
7261da177e4SLinus Torvalds 
727d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen))
7281da177e4SLinus Torvalds 		goto out;
729d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen))
7301da177e4SLinus Torvalds 		goto out;
731d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen))
7321da177e4SLinus Torvalds 		goto out;
733cdfb6b34SRichard Guy Briggs 	audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
7344093a844SRichard Guy Briggs 		  "op=security_validate_transition seresult=denied"
7351da177e4SLinus Torvalds 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
736aa8e712cSStephen Smalley 		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
7371da177e4SLinus Torvalds out:
7381da177e4SLinus Torvalds 	kfree(o);
7391da177e4SLinus Torvalds 	kfree(n);
7401da177e4SLinus Torvalds 	kfree(t);
7411da177e4SLinus Torvalds 
742e67b7985SStephen Smalley 	if (!enforcing_enabled())
7431da177e4SLinus Torvalds 		return 0;
7441da177e4SLinus Torvalds 	return -EPERM;
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds 
security_compute_validatetrans(u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass,bool user)747e67b7985SStephen Smalley static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
748f9df6458SAndrew Perepechko 					  u16 orig_tclass, bool user)
7491da177e4SLinus Torvalds {
7501b8b31a2SStephen Smalley 	struct selinux_policy *policy;
751aa8e712cSStephen Smalley 	struct policydb *policydb;
752aa8e712cSStephen Smalley 	struct sidtab *sidtab;
753d97bd23cSOndrej Mosnacek 	struct sidtab_entry *oentry;
754d97bd23cSOndrej Mosnacek 	struct sidtab_entry *nentry;
755d97bd23cSOndrej Mosnacek 	struct sidtab_entry *tentry;
7561da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
7571da177e4SLinus Torvalds 	struct constraint_node *constraint;
758c6d3aaa4SStephen Smalley 	u16 tclass;
7591da177e4SLinus Torvalds 	int rc = 0;
7601da177e4SLinus Torvalds 
761aa8e712cSStephen Smalley 
762e67b7985SStephen Smalley 	if (!selinux_initialized())
7631da177e4SLinus Torvalds 		return 0;
7641da177e4SLinus Torvalds 
7651b8b31a2SStephen Smalley 	rcu_read_lock();
766aa8e712cSStephen Smalley 
767e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
7681b8b31a2SStephen Smalley 	policydb = &policy->policydb;
7691b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
7701da177e4SLinus Torvalds 
771f9df6458SAndrew Perepechko 	if (!user)
7721b8b31a2SStephen Smalley 		tclass = unmap_class(&policy->map, orig_tclass);
773f9df6458SAndrew Perepechko 	else
774f9df6458SAndrew Perepechko 		tclass = orig_tclass;
775c6d3aaa4SStephen Smalley 
776aa8e712cSStephen Smalley 	if (!tclass || tclass > policydb->p_classes.nprim) {
7771da177e4SLinus Torvalds 		rc = -EINVAL;
7781da177e4SLinus Torvalds 		goto out;
7791da177e4SLinus Torvalds 	}
780aa8e712cSStephen Smalley 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
7811da177e4SLinus Torvalds 
782d97bd23cSOndrej Mosnacek 	oentry = sidtab_search_entry(sidtab, oldsid);
783d97bd23cSOndrej Mosnacek 	if (!oentry) {
784b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
785744ba35eSEric Paris 			__func__, oldsid);
7861da177e4SLinus Torvalds 		rc = -EINVAL;
7871da177e4SLinus Torvalds 		goto out;
7881da177e4SLinus Torvalds 	}
7891da177e4SLinus Torvalds 
790d97bd23cSOndrej Mosnacek 	nentry = sidtab_search_entry(sidtab, newsid);
791d97bd23cSOndrej Mosnacek 	if (!nentry) {
792b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
793744ba35eSEric Paris 			__func__, newsid);
7941da177e4SLinus Torvalds 		rc = -EINVAL;
7951da177e4SLinus Torvalds 		goto out;
7961da177e4SLinus Torvalds 	}
7971da177e4SLinus Torvalds 
798d97bd23cSOndrej Mosnacek 	tentry = sidtab_search_entry(sidtab, tasksid);
799d97bd23cSOndrej Mosnacek 	if (!tentry) {
800b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
801744ba35eSEric Paris 			__func__, tasksid);
8021da177e4SLinus Torvalds 		rc = -EINVAL;
8031da177e4SLinus Torvalds 		goto out;
8041da177e4SLinus Torvalds 	}
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	constraint = tclass_datum->validatetrans;
8071da177e4SLinus Torvalds 	while (constraint) {
808d97bd23cSOndrej Mosnacek 		if (!constraint_expr_eval(policydb, &oentry->context,
809d97bd23cSOndrej Mosnacek 					  &nentry->context, &tentry->context,
810d97bd23cSOndrej Mosnacek 					  constraint->expr)) {
811f9df6458SAndrew Perepechko 			if (user)
812f9df6458SAndrew Perepechko 				rc = -EPERM;
813f9df6458SAndrew Perepechko 			else
814e67b7985SStephen Smalley 				rc = security_validtrans_handle_fail(policy,
815d97bd23cSOndrej Mosnacek 								oentry,
816d97bd23cSOndrej Mosnacek 								nentry,
817d97bd23cSOndrej Mosnacek 								tentry,
818f9df6458SAndrew Perepechko 								tclass);
8191da177e4SLinus Torvalds 			goto out;
8201da177e4SLinus Torvalds 		}
8211da177e4SLinus Torvalds 		constraint = constraint->next;
8221da177e4SLinus Torvalds 	}
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds out:
8251b8b31a2SStephen Smalley 	rcu_read_unlock();
8261da177e4SLinus Torvalds 	return rc;
8271da177e4SLinus Torvalds }
8281da177e4SLinus Torvalds 
security_validate_transition_user(u32 oldsid,u32 newsid,u32 tasksid,u16 tclass)829e67b7985SStephen Smalley int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
830f9df6458SAndrew Perepechko 				      u16 tclass)
831f9df6458SAndrew Perepechko {
832e67b7985SStephen Smalley 	return security_compute_validatetrans(oldsid, newsid, tasksid,
833f9df6458SAndrew Perepechko 					      tclass, true);
834f9df6458SAndrew Perepechko }
835f9df6458SAndrew Perepechko 
security_validate_transition(u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass)836e67b7985SStephen Smalley int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
837f9df6458SAndrew Perepechko 				 u16 orig_tclass)
838f9df6458SAndrew Perepechko {
839e67b7985SStephen Smalley 	return security_compute_validatetrans(oldsid, newsid, tasksid,
840f9df6458SAndrew Perepechko 					      orig_tclass, false);
841f9df6458SAndrew Perepechko }
842f9df6458SAndrew Perepechko 
843d9250deaSKaiGai Kohei /*
844d9250deaSKaiGai Kohei  * security_bounded_transition - check whether the given
845d9250deaSKaiGai Kohei  * transition is directed to bounded, or not.
846d9250deaSKaiGai Kohei  * It returns 0, if @newsid is bounded by @oldsid.
847d9250deaSKaiGai Kohei  * Otherwise, it returns error code.
848d9250deaSKaiGai Kohei  *
849d9250deaSKaiGai Kohei  * @oldsid : current security identifier
850d9250deaSKaiGai Kohei  * @newsid : destinated security identifier
851d9250deaSKaiGai Kohei  */
security_bounded_transition(u32 old_sid,u32 new_sid)852e67b7985SStephen Smalley int security_bounded_transition(u32 old_sid, u32 new_sid)
853d9250deaSKaiGai Kohei {
8541b8b31a2SStephen Smalley 	struct selinux_policy *policy;
855aa8e712cSStephen Smalley 	struct policydb *policydb;
856aa8e712cSStephen Smalley 	struct sidtab *sidtab;
857d97bd23cSOndrej Mosnacek 	struct sidtab_entry *old_entry, *new_entry;
858d9250deaSKaiGai Kohei 	struct type_datum *type;
859c50e125dSChristian Göttsche 	u32 index;
8604b02b524SEric Paris 	int rc;
861d9250deaSKaiGai Kohei 
862e67b7985SStephen Smalley 	if (!selinux_initialized())
8634b14752eSPaul Moore 		return 0;
8644b14752eSPaul Moore 
8651b8b31a2SStephen Smalley 	rcu_read_lock();
866e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
8671b8b31a2SStephen Smalley 	policydb = &policy->policydb;
8681b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
869d9250deaSKaiGai Kohei 
8704b02b524SEric Paris 	rc = -EINVAL;
871d97bd23cSOndrej Mosnacek 	old_entry = sidtab_search_entry(sidtab, old_sid);
872d97bd23cSOndrej Mosnacek 	if (!old_entry) {
873b54c85c1Speter enderborg 		pr_err("SELinux: %s: unrecognized SID %u\n",
874d9250deaSKaiGai Kohei 		       __func__, old_sid);
875d9250deaSKaiGai Kohei 		goto out;
876d9250deaSKaiGai Kohei 	}
877d9250deaSKaiGai Kohei 
8784b02b524SEric Paris 	rc = -EINVAL;
879d97bd23cSOndrej Mosnacek 	new_entry = sidtab_search_entry(sidtab, new_sid);
880d97bd23cSOndrej Mosnacek 	if (!new_entry) {
881b54c85c1Speter enderborg 		pr_err("SELinux: %s: unrecognized SID %u\n",
882d9250deaSKaiGai Kohei 		       __func__, new_sid);
883d9250deaSKaiGai Kohei 		goto out;
884d9250deaSKaiGai Kohei 	}
885d9250deaSKaiGai Kohei 
886d9250deaSKaiGai Kohei 	rc = 0;
8874b02b524SEric Paris 	/* type/domain unchanged */
888d97bd23cSOndrej Mosnacek 	if (old_entry->context.type == new_entry->context.type)
889d9250deaSKaiGai Kohei 		goto out;
890d9250deaSKaiGai Kohei 
891d97bd23cSOndrej Mosnacek 	index = new_entry->context.type;
892d9250deaSKaiGai Kohei 	while (true) {
893f07ea1d4SOndrej Mosnacek 		type = policydb->type_val_to_struct[index - 1];
894d9250deaSKaiGai Kohei 		BUG_ON(!type);
895d9250deaSKaiGai Kohei 
896d9250deaSKaiGai Kohei 		/* not bounded anymore */
897d9250deaSKaiGai Kohei 		rc = -EPERM;
8984b02b524SEric Paris 		if (!type->bounds)
899d9250deaSKaiGai Kohei 			break;
900d9250deaSKaiGai Kohei 
901d9250deaSKaiGai Kohei 		/* @newsid is bounded by @oldsid */
902d9250deaSKaiGai Kohei 		rc = 0;
903d97bd23cSOndrej Mosnacek 		if (type->bounds == old_entry->context.type)
904d9250deaSKaiGai Kohei 			break;
9054b02b524SEric Paris 
906d9250deaSKaiGai Kohei 		index = type->bounds;
907d9250deaSKaiGai Kohei 	}
90844c2d9bdSKaiGai Kohei 
90944c2d9bdSKaiGai Kohei 	if (rc) {
91044c2d9bdSKaiGai Kohei 		char *old_name = NULL;
91144c2d9bdSKaiGai Kohei 		char *new_name = NULL;
9122da5d31bSJames Morris 		u32 length;
91344c2d9bdSKaiGai Kohei 
914d97bd23cSOndrej Mosnacek 		if (!sidtab_entry_to_string(policydb, sidtab, old_entry,
91544c2d9bdSKaiGai Kohei 					    &old_name, &length) &&
916d97bd23cSOndrej Mosnacek 		    !sidtab_entry_to_string(policydb, sidtab, new_entry,
91744c2d9bdSKaiGai Kohei 					    &new_name, &length)) {
918cdfb6b34SRichard Guy Briggs 			audit_log(audit_context(),
91944c2d9bdSKaiGai Kohei 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
92044c2d9bdSKaiGai Kohei 				  "op=security_bounded_transition "
9214093a844SRichard Guy Briggs 				  "seresult=denied "
92244c2d9bdSKaiGai Kohei 				  "oldcontext=%s newcontext=%s",
92344c2d9bdSKaiGai Kohei 				  old_name, new_name);
92444c2d9bdSKaiGai Kohei 		}
92544c2d9bdSKaiGai Kohei 		kfree(new_name);
92644c2d9bdSKaiGai Kohei 		kfree(old_name);
92744c2d9bdSKaiGai Kohei 	}
928d9250deaSKaiGai Kohei out:
9291b8b31a2SStephen Smalley 	rcu_read_unlock();
930d9250deaSKaiGai Kohei 
931d9250deaSKaiGai Kohei 	return rc;
932d9250deaSKaiGai Kohei }
933d9250deaSKaiGai Kohei 
avd_init(struct selinux_policy * policy,struct av_decision * avd)9341b8b31a2SStephen Smalley static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
935c6d3aaa4SStephen Smalley {
93619439d05SStephen Smalley 	avd->allowed = 0;
93719439d05SStephen Smalley 	avd->auditallow = 0;
93819439d05SStephen Smalley 	avd->auditdeny = 0xffffffff;
9391b8b31a2SStephen Smalley 	if (policy)
9401b8b31a2SStephen Smalley 		avd->seqno = policy->latest_granting;
9411b8b31a2SStephen Smalley 	else
9421b8b31a2SStephen Smalley 		avd->seqno = 0;
94319439d05SStephen Smalley 	avd->flags = 0;
944c6d3aaa4SStephen Smalley }
945c6d3aaa4SStephen Smalley 
services_compute_xperms_decision(struct extended_perms_decision * xpermd,struct avtab_node * node)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 {
959*c1dbd28aSThiébaud Weksteen 		pr_warn_once(
960*c1dbd28aSThiébaud Weksteen 			"SELinux: unknown extended permission (%u) will be ignored\n",
961*c1dbd28aSThiébaud Weksteen 			node->datum.u.xperms->specified);
962*c1dbd28aSThiébaud Weksteen 		return;
963fa1aa143SJeff Vander Stoep 	}
964fa1aa143SJeff Vander Stoep 
965fa1aa143SJeff Vander Stoep 	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
966fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_ALLOWED;
967fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
968fa1aa143SJeff Vander Stoep 			memset(xpermd->allowed->p, 0xff,
969fa1aa143SJeff Vander Stoep 					sizeof(xpermd->allowed->p));
970fa1aa143SJeff Vander Stoep 		}
971fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
972fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
973fa1aa143SJeff Vander Stoep 				xpermd->allowed->p[i] |=
974fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
975fa1aa143SJeff Vander Stoep 		}
976fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
977fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_AUDITALLOW;
978fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
979fa1aa143SJeff Vander Stoep 			memset(xpermd->auditallow->p, 0xff,
980fa1aa143SJeff Vander Stoep 					sizeof(xpermd->auditallow->p));
981fa1aa143SJeff Vander Stoep 		}
982fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
983fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
984fa1aa143SJeff Vander Stoep 				xpermd->auditallow->p[i] |=
985fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
986fa1aa143SJeff Vander Stoep 		}
987fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
988fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_DONTAUDIT;
989fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
990fa1aa143SJeff Vander Stoep 			memset(xpermd->dontaudit->p, 0xff,
991fa1aa143SJeff Vander Stoep 					sizeof(xpermd->dontaudit->p));
992fa1aa143SJeff Vander Stoep 		}
993fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
994fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
995fa1aa143SJeff Vander Stoep 				xpermd->dontaudit->p[i] |=
996fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
997fa1aa143SJeff Vander Stoep 		}
998fa1aa143SJeff Vander Stoep 	} else {
999*c1dbd28aSThiébaud Weksteen 		pr_warn_once("SELinux: unknown specified key (%u)\n",
1000*c1dbd28aSThiébaud Weksteen 			     node->key.specified);
1001fa1aa143SJeff Vander Stoep 	}
1002fa1aa143SJeff Vander Stoep }
1003fa1aa143SJeff Vander Stoep 
security_compute_xperms_decision(u32 ssid,u32 tsid,u16 orig_tclass,u8 driver,struct extended_perms_decision * xpermd)1004e67b7985SStephen Smalley void security_compute_xperms_decision(u32 ssid,
1005fa1aa143SJeff Vander Stoep 				      u32 tsid,
1006fa1aa143SJeff Vander Stoep 				      u16 orig_tclass,
1007fa1aa143SJeff Vander Stoep 				      u8 driver,
1008fa1aa143SJeff Vander Stoep 				      struct extended_perms_decision *xpermd)
1009fa1aa143SJeff Vander Stoep {
10101b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1011aa8e712cSStephen Smalley 	struct policydb *policydb;
1012aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1013fa1aa143SJeff Vander Stoep 	u16 tclass;
1014fa1aa143SJeff Vander Stoep 	struct context *scontext, *tcontext;
1015fa1aa143SJeff Vander Stoep 	struct avtab_key avkey;
1016fa1aa143SJeff Vander Stoep 	struct avtab_node *node;
1017fa1aa143SJeff Vander Stoep 	struct ebitmap *sattr, *tattr;
1018fa1aa143SJeff Vander Stoep 	struct ebitmap_node *snode, *tnode;
1019fa1aa143SJeff Vander Stoep 	unsigned int i, j;
1020fa1aa143SJeff Vander Stoep 
1021fa1aa143SJeff Vander Stoep 	xpermd->driver = driver;
1022fa1aa143SJeff Vander Stoep 	xpermd->used = 0;
1023fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1024fa1aa143SJeff Vander Stoep 	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1025fa1aa143SJeff Vander Stoep 	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1026fa1aa143SJeff Vander Stoep 
10271b8b31a2SStephen Smalley 	rcu_read_lock();
1028e67b7985SStephen Smalley 	if (!selinux_initialized())
1029fa1aa143SJeff Vander Stoep 		goto allow;
1030fa1aa143SJeff Vander Stoep 
1031e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
10321b8b31a2SStephen Smalley 	policydb = &policy->policydb;
10331b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1034aa8e712cSStephen Smalley 
1035aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
1036fa1aa143SJeff Vander Stoep 	if (!scontext) {
1037b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1038fa1aa143SJeff Vander Stoep 		       __func__, ssid);
1039fa1aa143SJeff Vander Stoep 		goto out;
1040fa1aa143SJeff Vander Stoep 	}
1041fa1aa143SJeff Vander Stoep 
1042aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
1043fa1aa143SJeff Vander Stoep 	if (!tcontext) {
1044b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1045fa1aa143SJeff Vander Stoep 		       __func__, tsid);
1046fa1aa143SJeff Vander Stoep 		goto out;
1047fa1aa143SJeff Vander Stoep 	}
1048fa1aa143SJeff Vander Stoep 
10491b8b31a2SStephen Smalley 	tclass = unmap_class(&policy->map, orig_tclass);
1050fa1aa143SJeff Vander Stoep 	if (unlikely(orig_tclass && !tclass)) {
1051aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1052fa1aa143SJeff Vander Stoep 			goto allow;
1053fa1aa143SJeff Vander Stoep 		goto out;
1054fa1aa143SJeff Vander Stoep 	}
1055fa1aa143SJeff Vander Stoep 
1056fa1aa143SJeff Vander Stoep 
1057aa8e712cSStephen Smalley 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1058fa1aa143SJeff Vander Stoep 		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
1059fa1aa143SJeff Vander Stoep 		goto out;
1060fa1aa143SJeff Vander Stoep 	}
1061fa1aa143SJeff Vander Stoep 
1062fa1aa143SJeff Vander Stoep 	avkey.target_class = tclass;
1063fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_XPERMS;
1064acdf52d9SKent Overstreet 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
1065acdf52d9SKent Overstreet 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1066fa1aa143SJeff Vander Stoep 	ebitmap_for_each_positive_bit(sattr, snode, i) {
1067fa1aa143SJeff Vander Stoep 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1068fa1aa143SJeff Vander Stoep 			avkey.source_type = i + 1;
1069fa1aa143SJeff Vander Stoep 			avkey.target_type = j + 1;
1070aa8e712cSStephen Smalley 			for (node = avtab_search_node(&policydb->te_avtab,
1071aa8e712cSStephen Smalley 						      &avkey);
1072fa1aa143SJeff Vander Stoep 			     node;
1073fa1aa143SJeff Vander Stoep 			     node = avtab_search_node_next(node, avkey.specified))
1074fa1aa143SJeff Vander Stoep 				services_compute_xperms_decision(xpermd, node);
1075fa1aa143SJeff Vander Stoep 
1076aa8e712cSStephen Smalley 			cond_compute_xperms(&policydb->te_cond_avtab,
1077fa1aa143SJeff Vander Stoep 						&avkey, xpermd);
1078fa1aa143SJeff Vander Stoep 		}
1079fa1aa143SJeff Vander Stoep 	}
1080fa1aa143SJeff Vander Stoep out:
10811b8b31a2SStephen Smalley 	rcu_read_unlock();
1082fa1aa143SJeff Vander Stoep 	return;
1083fa1aa143SJeff Vander Stoep allow:
1084fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1085fa1aa143SJeff Vander Stoep 	goto out;
1086fa1aa143SJeff Vander Stoep }
1087c6d3aaa4SStephen Smalley 
10881da177e4SLinus Torvalds /**
10891da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
10901da177e4SLinus Torvalds  * @ssid: source security identifier
10911da177e4SLinus Torvalds  * @tsid: target security identifier
1092e9fd7292SPaul Moore  * @orig_tclass: target security class
10931da177e4SLinus Torvalds  * @avd: access vector decisions
1094fa1aa143SJeff Vander Stoep  * @xperms: extended permissions
10951da177e4SLinus Torvalds  *
10961da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
10971da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
10981da177e4SLinus Torvalds  */
security_compute_av(u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision * avd,struct extended_perms * xperms)1099e67b7985SStephen Smalley void security_compute_av(u32 ssid,
11001da177e4SLinus Torvalds 			 u32 tsid,
1101c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
1102fa1aa143SJeff Vander Stoep 			 struct av_decision *avd,
1103fa1aa143SJeff Vander Stoep 			 struct extended_perms *xperms)
1104c6d3aaa4SStephen Smalley {
11051b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1106aa8e712cSStephen Smalley 	struct policydb *policydb;
1107aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1108c6d3aaa4SStephen Smalley 	u16 tclass;
110919439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
1110c6d3aaa4SStephen Smalley 
11111b8b31a2SStephen Smalley 	rcu_read_lock();
1112e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
11131b8b31a2SStephen Smalley 	avd_init(policy, avd);
1114fa1aa143SJeff Vander Stoep 	xperms->len = 0;
1115e67b7985SStephen Smalley 	if (!selinux_initialized())
1116c6d3aaa4SStephen Smalley 		goto allow;
1117c6d3aaa4SStephen Smalley 
11181b8b31a2SStephen Smalley 	policydb = &policy->policydb;
11191b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1120aa8e712cSStephen Smalley 
1121aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
112219439d05SStephen Smalley 	if (!scontext) {
1123b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
112419439d05SStephen Smalley 		       __func__, ssid);
112519439d05SStephen Smalley 		goto out;
112619439d05SStephen Smalley 	}
112719439d05SStephen Smalley 
112819439d05SStephen Smalley 	/* permissive domain? */
1129aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
113019439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
113119439d05SStephen Smalley 
1132aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
113319439d05SStephen Smalley 	if (!tcontext) {
1134b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
113519439d05SStephen Smalley 		       __func__, tsid);
113619439d05SStephen Smalley 		goto out;
113719439d05SStephen Smalley 	}
113819439d05SStephen Smalley 
11391b8b31a2SStephen Smalley 	tclass = unmap_class(&policy->map, orig_tclass);
1140c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
1141aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1142c6d3aaa4SStephen Smalley 			goto allow;
1143b7f3008aSStephen Smalley 		goto out;
1144c6d3aaa4SStephen Smalley 	}
1145aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1146aa8e712cSStephen Smalley 				  xperms);
11471b8b31a2SStephen Smalley 	map_decision(&policy->map, orig_tclass, avd,
1148aa8e712cSStephen Smalley 		     policydb->allow_unknown);
1149b7f3008aSStephen Smalley out:
11501b8b31a2SStephen Smalley 	rcu_read_unlock();
115119439d05SStephen Smalley 	return;
1152c6d3aaa4SStephen Smalley allow:
1153c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
1154b7f3008aSStephen Smalley 	goto out;
1155c6d3aaa4SStephen Smalley }
1156c6d3aaa4SStephen Smalley 
security_compute_av_user(u32 ssid,u32 tsid,u16 tclass,struct av_decision * avd)1157e67b7985SStephen Smalley void security_compute_av_user(u32 ssid,
1158c6d3aaa4SStephen Smalley 			      u32 tsid,
11591da177e4SLinus Torvalds 			      u16 tclass,
11601da177e4SLinus Torvalds 			      struct av_decision *avd)
11611da177e4SLinus Torvalds {
11621b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1163aa8e712cSStephen Smalley 	struct policydb *policydb;
1164aa8e712cSStephen Smalley 	struct sidtab *sidtab;
116519439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
11661da177e4SLinus Torvalds 
11671b8b31a2SStephen Smalley 	rcu_read_lock();
1168e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
11691b8b31a2SStephen Smalley 	avd_init(policy, avd);
1170e67b7985SStephen Smalley 	if (!selinux_initialized())
117119439d05SStephen Smalley 		goto allow;
117219439d05SStephen Smalley 
11731b8b31a2SStephen Smalley 	policydb = &policy->policydb;
11741b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1175aa8e712cSStephen Smalley 
1176aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
117719439d05SStephen Smalley 	if (!scontext) {
1178b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
117919439d05SStephen Smalley 		       __func__, ssid);
118019439d05SStephen Smalley 		goto out;
118119439d05SStephen Smalley 	}
118219439d05SStephen Smalley 
118319439d05SStephen Smalley 	/* permissive domain? */
1184aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
118519439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
118619439d05SStephen Smalley 
1187aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
118819439d05SStephen Smalley 	if (!tcontext) {
1189b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
119019439d05SStephen Smalley 		       __func__, tsid);
119119439d05SStephen Smalley 		goto out;
119219439d05SStephen Smalley 	}
119319439d05SStephen Smalley 
119419439d05SStephen Smalley 	if (unlikely(!tclass)) {
1195aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
119619439d05SStephen Smalley 			goto allow;
119719439d05SStephen Smalley 		goto out;
119819439d05SStephen Smalley 	}
119919439d05SStephen Smalley 
1200aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1201aa8e712cSStephen Smalley 				  NULL);
120219439d05SStephen Smalley  out:
12031b8b31a2SStephen Smalley 	rcu_read_unlock();
120419439d05SStephen Smalley 	return;
120519439d05SStephen Smalley allow:
120619439d05SStephen Smalley 	avd->allowed = 0xffffffff;
120719439d05SStephen Smalley 	goto out;
12081da177e4SLinus Torvalds }
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds /*
12111da177e4SLinus Torvalds  * Write the security context string representation of
12121da177e4SLinus Torvalds  * the context structure `context' into a dynamically
12131da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
12141da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
12151da177e4SLinus Torvalds  * the length of the string.
12161da177e4SLinus Torvalds  */
context_struct_to_string(struct policydb * p,struct context * context,char ** scontext,u32 * scontext_len)1217aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p,
1218aa8e712cSStephen Smalley 				    struct context *context,
1219aa8e712cSStephen Smalley 				    char **scontext, u32 *scontext_len)
12201da177e4SLinus Torvalds {
12211da177e4SLinus Torvalds 	char *scontextp;
12221da177e4SLinus Torvalds 
1223d5630b9dSEric Paris 	if (scontext)
12241da177e4SLinus Torvalds 		*scontext = NULL;
12251da177e4SLinus Torvalds 	*scontext_len = 0;
12261da177e4SLinus Torvalds 
122712b29f34SStephen Smalley 	if (context->len) {
122812b29f34SStephen Smalley 		*scontext_len = context->len;
1229bb7081abSEric Paris 		if (scontext) {
123012b29f34SStephen Smalley 			*scontext = kstrdup(context->str, GFP_ATOMIC);
123112b29f34SStephen Smalley 			if (!(*scontext))
123212b29f34SStephen Smalley 				return -ENOMEM;
1233bb7081abSEric Paris 		}
123412b29f34SStephen Smalley 		return 0;
123512b29f34SStephen Smalley 	}
123612b29f34SStephen Smalley 
12371da177e4SLinus Torvalds 	/* Compute the size of the context. */
1238aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1239aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1240aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1241aa8e712cSStephen Smalley 	*scontext_len += mls_compute_context_len(p, context);
12421da177e4SLinus Torvalds 
1243d5630b9dSEric Paris 	if (!scontext)
1244d5630b9dSEric Paris 		return 0;
1245d5630b9dSEric Paris 
12461da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
12471da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12485d55a345SEric Paris 	if (!scontextp)
12491da177e4SLinus Torvalds 		return -ENOMEM;
12501da177e4SLinus Torvalds 	*scontext = scontextp;
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	/*
12531da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
12541da177e4SLinus Torvalds 	 */
12559529c788SRasmus Villemoes 	scontextp += sprintf(scontextp, "%s:%s:%s",
1256aa8e712cSStephen Smalley 		sym_name(p, SYM_USERS, context->user - 1),
1257aa8e712cSStephen Smalley 		sym_name(p, SYM_ROLES, context->role - 1),
1258aa8e712cSStephen Smalley 		sym_name(p, SYM_TYPES, context->type - 1));
12591da177e4SLinus Torvalds 
1260aa8e712cSStephen Smalley 	mls_sid_to_context(p, context, &scontextp);
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 	*scontextp = 0;
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	return 0;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds 
sidtab_entry_to_string(struct policydb * p,struct sidtab * sidtab,struct sidtab_entry * entry,char ** scontext,u32 * scontext_len)1267d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *p,
1268d97bd23cSOndrej Mosnacek 				  struct sidtab *sidtab,
1269d97bd23cSOndrej Mosnacek 				  struct sidtab_entry *entry,
1270d97bd23cSOndrej Mosnacek 				  char **scontext, u32 *scontext_len)
1271d97bd23cSOndrej Mosnacek {
1272d97bd23cSOndrej Mosnacek 	int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
1273d97bd23cSOndrej Mosnacek 
1274d97bd23cSOndrej Mosnacek 	if (rc != -ENOENT)
1275d97bd23cSOndrej Mosnacek 		return rc;
1276d97bd23cSOndrej Mosnacek 
1277d97bd23cSOndrej Mosnacek 	rc = context_struct_to_string(p, &entry->context, scontext,
1278d97bd23cSOndrej Mosnacek 				      scontext_len);
1279d97bd23cSOndrej Mosnacek 	if (!rc && scontext)
1280d97bd23cSOndrej Mosnacek 		sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
1281d97bd23cSOndrej Mosnacek 	return rc;
1282d97bd23cSOndrej Mosnacek }
1283d97bd23cSOndrej Mosnacek 
12841da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12851da177e4SLinus Torvalds 
security_sidtab_hash_stats(char * page)1286e67b7985SStephen Smalley int security_sidtab_hash_stats(char *page)
128766f8e2f0SJeff Vander Stoep {
12881b8b31a2SStephen Smalley 	struct selinux_policy *policy;
128966f8e2f0SJeff Vander Stoep 	int rc;
129066f8e2f0SJeff Vander Stoep 
1291e67b7985SStephen Smalley 	if (!selinux_initialized()) {
129215b590a8SPaul Moore 		pr_err("SELinux: %s:  called before initial load_policy\n",
129315b590a8SPaul Moore 		       __func__);
129415b590a8SPaul Moore 		return -EINVAL;
129515b590a8SPaul Moore 	}
129615b590a8SPaul Moore 
12971b8b31a2SStephen Smalley 	rcu_read_lock();
1298e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
12991b8b31a2SStephen Smalley 	rc = sidtab_hash_stats(policy->sidtab, page);
13001b8b31a2SStephen Smalley 	rcu_read_unlock();
130166f8e2f0SJeff Vander Stoep 
130266f8e2f0SJeff Vander Stoep 	return rc;
130366f8e2f0SJeff Vander Stoep }
130466f8e2f0SJeff Vander Stoep 
security_get_initial_sid_context(u32 sid)1305f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1306f0ee2e46SJames Carter {
1307f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1308f0ee2e46SJames Carter 		return NULL;
1309f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1310f0ee2e46SJames Carter }
1311f0ee2e46SJames Carter 
security_sid_to_context_core(u32 sid,char ** scontext,u32 * scontext_len,int force,int only_invalid)1312e67b7985SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
1313fede1483SOndrej Mosnacek 					u32 *scontext_len, int force,
1314fede1483SOndrej Mosnacek 					int only_invalid)
13151da177e4SLinus Torvalds {
13161b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1317aa8e712cSStephen Smalley 	struct policydb *policydb;
1318aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1319d97bd23cSOndrej Mosnacek 	struct sidtab_entry *entry;
13201da177e4SLinus Torvalds 	int rc = 0;
13211da177e4SLinus Torvalds 
1322d5630b9dSEric Paris 	if (scontext)
13234f4acf3aSStephen Smalley 		*scontext = NULL;
13244f4acf3aSStephen Smalley 	*scontext_len  = 0;
13254f4acf3aSStephen Smalley 
1326e67b7985SStephen Smalley 	if (!selinux_initialized()) {
13271da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
13281da177e4SLinus Torvalds 			char *scontextp;
1329e3e0b582SStephen Smalley 			const char *s = initial_sid_to_string[sid];
13301da177e4SLinus Torvalds 
1331e3e0b582SStephen Smalley 			if (!s)
1332e3e0b582SStephen Smalley 				return -EINVAL;
1333e3e0b582SStephen Smalley 			*scontext_len = strlen(s) + 1;
1334d5630b9dSEric Paris 			if (!scontext)
1335e3e0b582SStephen Smalley 				return 0;
1336e3e0b582SStephen Smalley 			scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
1337e3e0b582SStephen Smalley 			if (!scontextp)
1338e3e0b582SStephen Smalley 				return -ENOMEM;
13391da177e4SLinus Torvalds 			*scontext = scontextp;
1340e3e0b582SStephen Smalley 			return 0;
13411da177e4SLinus Torvalds 		}
1342b54c85c1Speter enderborg 		pr_err("SELinux: %s:  called before initial "
1343744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
1344e3e0b582SStephen Smalley 		return -EINVAL;
13451da177e4SLinus Torvalds 	}
13461b8b31a2SStephen Smalley 	rcu_read_lock();
1347e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
13481b8b31a2SStephen Smalley 	policydb = &policy->policydb;
13491b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1350d97bd23cSOndrej Mosnacek 
135112b29f34SStephen Smalley 	if (force)
1352d97bd23cSOndrej Mosnacek 		entry = sidtab_search_entry_force(sidtab, sid);
135312b29f34SStephen Smalley 	else
1354d97bd23cSOndrej Mosnacek 		entry = sidtab_search_entry(sidtab, sid);
1355d97bd23cSOndrej Mosnacek 	if (!entry) {
1356b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1357744ba35eSEric Paris 			__func__, sid);
13581da177e4SLinus Torvalds 		rc = -EINVAL;
13591da177e4SLinus Torvalds 		goto out_unlock;
13601da177e4SLinus Torvalds 	}
1361d97bd23cSOndrej Mosnacek 	if (only_invalid && !entry->context.len)
1362d97bd23cSOndrej Mosnacek 		goto out_unlock;
1363d97bd23cSOndrej Mosnacek 
1364d97bd23cSOndrej Mosnacek 	rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
1365aa8e712cSStephen Smalley 				    scontext_len);
1366d97bd23cSOndrej Mosnacek 
13671da177e4SLinus Torvalds out_unlock:
13681b8b31a2SStephen Smalley 	rcu_read_unlock();
13691da177e4SLinus Torvalds 	return rc;
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds }
13721da177e4SLinus Torvalds 
137312b29f34SStephen Smalley /**
137412b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
137512b29f34SStephen Smalley  * @sid: security identifier, SID
137612b29f34SStephen Smalley  * @scontext: security context
137712b29f34SStephen Smalley  * @scontext_len: length in bytes
137812b29f34SStephen Smalley  *
137912b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
138012b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
138112b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
138212b29f34SStephen Smalley  */
security_sid_to_context(u32 sid,char ** scontext,u32 * scontext_len)1383e67b7985SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
13841da177e4SLinus Torvalds {
1385e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1386fede1483SOndrej Mosnacek 					    scontext_len, 0, 0);
138712b29f34SStephen Smalley }
138812b29f34SStephen Smalley 
security_sid_to_context_force(u32 sid,char ** scontext,u32 * scontext_len)1389e67b7985SStephen Smalley int security_sid_to_context_force(u32 sid,
1390aa8e712cSStephen Smalley 				  char **scontext, u32 *scontext_len)
139112b29f34SStephen Smalley {
1392e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1393fede1483SOndrej Mosnacek 					    scontext_len, 1, 0);
1394fede1483SOndrej Mosnacek }
1395fede1483SOndrej Mosnacek 
1396fede1483SOndrej Mosnacek /**
1397fede1483SOndrej Mosnacek  * security_sid_to_context_inval - Obtain a context for a given SID if it
1398fede1483SOndrej Mosnacek  *                                 is invalid.
1399fede1483SOndrej Mosnacek  * @sid: security identifier, SID
1400fede1483SOndrej Mosnacek  * @scontext: security context
1401fede1483SOndrej Mosnacek  * @scontext_len: length in bytes
1402fede1483SOndrej Mosnacek  *
1403fede1483SOndrej Mosnacek  * Write the string representation of the context associated with @sid
1404fede1483SOndrej Mosnacek  * into a dynamically allocated string of the correct size, but only if the
1405fede1483SOndrej Mosnacek  * context is invalid in the current policy.  Set @scontext to point to
1406fede1483SOndrej Mosnacek  * this string (or NULL if the context is valid) and set @scontext_len to
1407fede1483SOndrej Mosnacek  * the length of the string (or 0 if the context is valid).
1408fede1483SOndrej Mosnacek  */
security_sid_to_context_inval(u32 sid,char ** scontext,u32 * scontext_len)1409e67b7985SStephen Smalley int security_sid_to_context_inval(u32 sid,
1410fede1483SOndrej Mosnacek 				  char **scontext, u32 *scontext_len)
1411fede1483SOndrej Mosnacek {
1412e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1413fede1483SOndrej Mosnacek 					    scontext_len, 1, 1);
141412b29f34SStephen Smalley }
141512b29f34SStephen Smalley 
14169a59daa0SStephen Smalley /*
14179a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
14189a59daa0SStephen Smalley  */
string_to_context_struct(struct policydb * pol,struct sidtab * sidtabp,char * scontext,struct context * ctx,u32 def_sid)141912b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
142012b29f34SStephen Smalley 				    struct sidtab *sidtabp,
14219a59daa0SStephen Smalley 				    char *scontext,
142212b29f34SStephen Smalley 				    struct context *ctx,
14239a59daa0SStephen Smalley 				    u32 def_sid)
142412b29f34SStephen Smalley {
14251da177e4SLinus Torvalds 	struct role_datum *role;
14261da177e4SLinus Torvalds 	struct type_datum *typdatum;
14271da177e4SLinus Torvalds 	struct user_datum *usrdatum;
14281da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
14291da177e4SLinus Torvalds 	int rc = 0;
14301da177e4SLinus Torvalds 
143112b29f34SStephen Smalley 	context_init(ctx);
143212b29f34SStephen Smalley 
143312b29f34SStephen Smalley 	/* Parse the security context. */
143412b29f34SStephen Smalley 
143512b29f34SStephen Smalley 	rc = -EINVAL;
14360b3c2b3dSChristian Göttsche 	scontextp = scontext;
143712b29f34SStephen Smalley 
143812b29f34SStephen Smalley 	/* Extract the user. */
143912b29f34SStephen Smalley 	p = scontextp;
144012b29f34SStephen Smalley 	while (*p && *p != ':')
144112b29f34SStephen Smalley 		p++;
144212b29f34SStephen Smalley 
144312b29f34SStephen Smalley 	if (*p == 0)
144412b29f34SStephen Smalley 		goto out;
144512b29f34SStephen Smalley 
144612b29f34SStephen Smalley 	*p++ = 0;
144712b29f34SStephen Smalley 
1448237389e3SOndrej Mosnacek 	usrdatum = symtab_search(&pol->p_users, scontextp);
144912b29f34SStephen Smalley 	if (!usrdatum)
145012b29f34SStephen Smalley 		goto out;
145112b29f34SStephen Smalley 
145212b29f34SStephen Smalley 	ctx->user = usrdatum->value;
145312b29f34SStephen Smalley 
145412b29f34SStephen Smalley 	/* Extract role. */
145512b29f34SStephen Smalley 	scontextp = p;
145612b29f34SStephen Smalley 	while (*p && *p != ':')
145712b29f34SStephen Smalley 		p++;
145812b29f34SStephen Smalley 
145912b29f34SStephen Smalley 	if (*p == 0)
146012b29f34SStephen Smalley 		goto out;
146112b29f34SStephen Smalley 
146212b29f34SStephen Smalley 	*p++ = 0;
146312b29f34SStephen Smalley 
1464237389e3SOndrej Mosnacek 	role = symtab_search(&pol->p_roles, scontextp);
146512b29f34SStephen Smalley 	if (!role)
146612b29f34SStephen Smalley 		goto out;
146712b29f34SStephen Smalley 	ctx->role = role->value;
146812b29f34SStephen Smalley 
146912b29f34SStephen Smalley 	/* Extract type. */
147012b29f34SStephen Smalley 	scontextp = p;
147112b29f34SStephen Smalley 	while (*p && *p != ':')
147212b29f34SStephen Smalley 		p++;
147312b29f34SStephen Smalley 	oldc = *p;
147412b29f34SStephen Smalley 	*p++ = 0;
147512b29f34SStephen Smalley 
1476237389e3SOndrej Mosnacek 	typdatum = symtab_search(&pol->p_types, scontextp);
1477d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
147812b29f34SStephen Smalley 		goto out;
147912b29f34SStephen Smalley 
148012b29f34SStephen Smalley 	ctx->type = typdatum->value;
148112b29f34SStephen Smalley 
148295ffe194SJann Horn 	rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
148312b29f34SStephen Smalley 	if (rc)
148412b29f34SStephen Smalley 		goto out;
148512b29f34SStephen Smalley 
148612b29f34SStephen Smalley 	/* Check the validity of the new context. */
148795ffe194SJann Horn 	rc = -EINVAL;
14884b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
148912b29f34SStephen Smalley 		goto out;
149012b29f34SStephen Smalley 	rc = 0;
149112b29f34SStephen Smalley out:
14928e531af9SEric Paris 	if (rc)
14938e531af9SEric Paris 		context_destroy(ctx);
149412b29f34SStephen Smalley 	return rc;
149512b29f34SStephen Smalley }
149612b29f34SStephen Smalley 
security_context_to_sid_core(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags,int force)1497e67b7985SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
149812b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
149912b29f34SStephen Smalley 					int force)
150012b29f34SStephen Smalley {
15011b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1502aa8e712cSStephen Smalley 	struct policydb *policydb;
1503aa8e712cSStephen Smalley 	struct sidtab *sidtab;
15049a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
150512b29f34SStephen Smalley 	struct context context;
150612b29f34SStephen Smalley 	int rc = 0;
150712b29f34SStephen Smalley 
15082172fa70SStephen Smalley 	/* An empty security context is never valid. */
15092172fa70SStephen Smalley 	if (!scontext_len)
15102172fa70SStephen Smalley 		return -EINVAL;
15112172fa70SStephen Smalley 
1512ef28df55SPaul Moore 	/* Copy the string to allow changes and ensure a NUL terminator */
1513ef28df55SPaul Moore 	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1514ef28df55SPaul Moore 	if (!scontext2)
1515ef28df55SPaul Moore 		return -ENOMEM;
1516ef28df55SPaul Moore 
1517e67b7985SStephen Smalley 	if (!selinux_initialized()) {
1518c50e125dSChristian Göttsche 		u32 i;
15191da177e4SLinus Torvalds 
15201da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
1521e3e0b582SStephen Smalley 			const char *s = initial_sid_to_string[i];
1522e3e0b582SStephen Smalley 
1523e3e0b582SStephen Smalley 			if (s && !strcmp(s, scontext2)) {
15241da177e4SLinus Torvalds 				*sid = i;
1525ef28df55SPaul Moore 				goto out;
15261da177e4SLinus Torvalds 			}
15271da177e4SLinus Torvalds 		}
15281da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
1529ef28df55SPaul Moore 		goto out;
15301da177e4SLinus Torvalds 	}
15311da177e4SLinus Torvalds 	*sid = SECSID_NULL;
15321da177e4SLinus Torvalds 
15339a59daa0SStephen Smalley 	if (force) {
15349a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
15354b02b524SEric Paris 		rc = -ENOMEM;
15369a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
15374b02b524SEric Paris 		if (!str)
15384b02b524SEric Paris 			goto out;
15399a59daa0SStephen Smalley 	}
15409ad6e9cbSOndrej Mosnacek retry:
15411b8b31a2SStephen Smalley 	rcu_read_lock();
1542e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
15431b8b31a2SStephen Smalley 	policydb = &policy->policydb;
15441b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1545aa8e712cSStephen Smalley 	rc = string_to_context_struct(policydb, sidtab, scontext2,
154695ffe194SJann Horn 				      &context, def_sid);
154712b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
15489a59daa0SStephen Smalley 		context.str = str;
1549efe3de79SSachin Grover 		context.len = strlen(str) + 1;
15509a59daa0SStephen Smalley 		str = NULL;
155112b29f34SStephen Smalley 	} else if (rc)
15524b02b524SEric Paris 		goto out_unlock;
1553225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &context, sid);
15549ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
15559ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
15569ad6e9cbSOndrej Mosnacek 		if (context.str) {
15579ad6e9cbSOndrej Mosnacek 			str = context.str;
15589ad6e9cbSOndrej Mosnacek 			context.str = NULL;
15599ad6e9cbSOndrej Mosnacek 		}
15609ad6e9cbSOndrej Mosnacek 		context_destroy(&context);
15619ad6e9cbSOndrej Mosnacek 		goto retry;
15629ad6e9cbSOndrej Mosnacek 	}
15631da177e4SLinus Torvalds 	context_destroy(&context);
15644b02b524SEric Paris out_unlock:
15651b8b31a2SStephen Smalley 	rcu_read_unlock();
15664b02b524SEric Paris out:
15679a59daa0SStephen Smalley 	kfree(scontext2);
15689a59daa0SStephen Smalley 	kfree(str);
15691da177e4SLinus Torvalds 	return rc;
15701da177e4SLinus Torvalds }
15711da177e4SLinus Torvalds 
1572f5c1d5b2SJames Morris /**
1573f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1574f5c1d5b2SJames Morris  * @scontext: security context
1575f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1576f5c1d5b2SJames Morris  * @sid: security identifier, SID
157752a4c640SNikolay Aleksandrov  * @gfp: context for the allocation
1578f5c1d5b2SJames Morris  *
1579f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1580f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1581f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1582f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1583f5c1d5b2SJames Morris  */
security_context_to_sid(const char * scontext,u32 scontext_len,u32 * sid,gfp_t gfp)1584e67b7985SStephen Smalley int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
158552a4c640SNikolay Aleksandrov 			    gfp_t gfp)
1586f5c1d5b2SJames Morris {
1587e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
158852a4c640SNikolay Aleksandrov 					    sid, SECSID_NULL, gfp, 0);
1589f5c1d5b2SJames Morris }
1590f5c1d5b2SJames Morris 
security_context_str_to_sid(const char * scontext,u32 * sid,gfp_t gfp)1591e67b7985SStephen Smalley int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
159244be2f65SRasmus Villemoes {
1593e67b7985SStephen Smalley 	return security_context_to_sid(scontext, strlen(scontext),
1594aa8e712cSStephen Smalley 				       sid, gfp);
159544be2f65SRasmus Villemoes }
159644be2f65SRasmus Villemoes 
1597f5c1d5b2SJames Morris /**
1598f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1599f5c1d5b2SJames Morris  * falling back to specified default if needed.
1600f5c1d5b2SJames Morris  *
1601f5c1d5b2SJames Morris  * @scontext: security context
1602f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1603f5c1d5b2SJames Morris  * @sid: security identifier, SID
1604d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1605e9fd7292SPaul Moore  * @gfp_flags: the allocator get-free-page (GFP) flags
1606f5c1d5b2SJames Morris  *
1607f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1608f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1609f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1610f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1611f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
161212b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1613f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1614f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1615f5c1d5b2SJames Morris  */
security_context_to_sid_default(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags)1616e67b7985SStephen Smalley int security_context_to_sid_default(const char *scontext, u32 scontext_len,
16177bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1618f5c1d5b2SJames Morris {
1619e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
162012b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
162112b29f34SStephen Smalley }
162212b29f34SStephen Smalley 
security_context_to_sid_force(const char * scontext,u32 scontext_len,u32 * sid)1623e67b7985SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
162412b29f34SStephen Smalley 				  u32 *sid)
162512b29f34SStephen Smalley {
1626e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
162712b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1628f5c1d5b2SJames Morris }
1629f5c1d5b2SJames Morris 
compute_sid_handle_invalid_context(struct selinux_policy * policy,struct sidtab_entry * sentry,struct sidtab_entry * tentry,u16 tclass,struct context * newcontext)16301da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
16311b8b31a2SStephen Smalley 	struct selinux_policy *policy,
1632d97bd23cSOndrej Mosnacek 	struct sidtab_entry *sentry,
1633d97bd23cSOndrej Mosnacek 	struct sidtab_entry *tentry,
16341da177e4SLinus Torvalds 	u16 tclass,
16351da177e4SLinus Torvalds 	struct context *newcontext)
16361da177e4SLinus Torvalds {
16371b8b31a2SStephen Smalley 	struct policydb *policydb = &policy->policydb;
16381b8b31a2SStephen Smalley 	struct sidtab *sidtab = policy->sidtab;
16391da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
16401da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
1641ea74a685SRichard Guy Briggs 	struct audit_buffer *ab;
16421da177e4SLinus Torvalds 
1643d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
16441da177e4SLinus Torvalds 		goto out;
1645d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
16461da177e4SLinus Torvalds 		goto out;
1647aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
16481da177e4SLinus Torvalds 		goto out;
1649ea74a685SRichard Guy Briggs 	ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1650893c47d1SAustin Kim 	if (!ab)
1651893c47d1SAustin Kim 		goto out;
1652ea74a685SRichard Guy Briggs 	audit_log_format(ab,
1653ea74a685SRichard Guy Briggs 			 "op=security_compute_sid invalid_context=");
1654ea74a685SRichard Guy Briggs 	/* no need to record the NUL with untrusted strings */
1655ea74a685SRichard Guy Briggs 	audit_log_n_untrustedstring(ab, n, nlen - 1);
1656ea74a685SRichard Guy Briggs 	audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1657ea74a685SRichard Guy Briggs 			 s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1658ea74a685SRichard Guy Briggs 	audit_log_end(ab);
16591da177e4SLinus Torvalds out:
16601da177e4SLinus Torvalds 	kfree(s);
16611da177e4SLinus Torvalds 	kfree(t);
16621da177e4SLinus Torvalds 	kfree(n);
1663e67b7985SStephen Smalley 	if (!enforcing_enabled())
16641da177e4SLinus Torvalds 		return 0;
16651da177e4SLinus Torvalds 	return -EACCES;
16661da177e4SLinus Torvalds }
16671da177e4SLinus Torvalds 
filename_compute_type(struct policydb * policydb,struct context * newcontext,u32 stype,u32 ttype,u16 tclass,const char * objname)1668aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb,
1669aa8e712cSStephen Smalley 				  struct context *newcontext,
16702667991fSEric Paris 				  u32 stype, u32 ttype, u16 tclass,
1671f50a3ec9SKohei Kaigai 				  const char *objname)
1672652bb9b0SEric Paris {
1673c3a27611SOndrej Mosnacek 	struct filename_trans_key ft;
1674c3a27611SOndrej Mosnacek 	struct filename_trans_datum *datum;
167503a4c018SEric Paris 
167603a4c018SEric Paris 	/*
167703a4c018SEric Paris 	 * Most filename trans rules are going to live in specific directories
167803a4c018SEric Paris 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
167903a4c018SEric Paris 	 * if the ttype does not contain any rules.
168003a4c018SEric Paris 	 */
1681aa8e712cSStephen Smalley 	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1682652bb9b0SEric Paris 		return;
168303a4c018SEric Paris 
16842463c26dSEric Paris 	ft.ttype = ttype;
16852463c26dSEric Paris 	ft.tclass = tclass;
16862463c26dSEric Paris 	ft.name = objname;
16872463c26dSEric Paris 
168824def7bbSOndrej Mosnacek 	datum = policydb_filenametr_search(policydb, &ft);
1689c3a27611SOndrej Mosnacek 	while (datum) {
1690c3a27611SOndrej Mosnacek 		if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
1691c3a27611SOndrej Mosnacek 			newcontext->type = datum->otype;
1692c3a27611SOndrej Mosnacek 			return;
1693c3a27611SOndrej Mosnacek 		}
1694c3a27611SOndrej Mosnacek 		datum = datum->next;
1695c3a27611SOndrej Mosnacek 	}
1696652bb9b0SEric Paris }
1697652bb9b0SEric Paris 
security_compute_sid(u32 ssid,u32 tsid,u16 orig_tclass,u16 specified,const char * objname,u32 * out_sid,bool kern)1698e67b7985SStephen Smalley static int security_compute_sid(u32 ssid,
16991da177e4SLinus Torvalds 				u32 tsid,
1700c6d3aaa4SStephen Smalley 				u16 orig_tclass,
17017128578cSChristian Göttsche 				u16 specified,
1702f50a3ec9SKohei Kaigai 				const char *objname,
1703c6d3aaa4SStephen Smalley 				u32 *out_sid,
1704c6d3aaa4SStephen Smalley 				bool kern)
17051da177e4SLinus Torvalds {
17061b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1707aa8e712cSStephen Smalley 	struct policydb *policydb;
1708aa8e712cSStephen Smalley 	struct sidtab *sidtab;
17099ad6e9cbSOndrej Mosnacek 	struct class_datum *cladatum;
1710d97bd23cSOndrej Mosnacek 	struct context *scontext, *tcontext, newcontext;
1711d97bd23cSOndrej Mosnacek 	struct sidtab_entry *sentry, *tentry;
17121da177e4SLinus Torvalds 	struct avtab_key avkey;
171308a12b39SChristian Göttsche 	struct avtab_node *avnode, *node;
1714c6d3aaa4SStephen Smalley 	u16 tclass;
17151da177e4SLinus Torvalds 	int rc = 0;
17166f5317e7SHarry Ciao 	bool sock;
17171da177e4SLinus Torvalds 
1718e67b7985SStephen Smalley 	if (!selinux_initialized()) {
1719c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1720c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
17211da177e4SLinus Torvalds 			*out_sid = ssid;
17221da177e4SLinus Torvalds 			break;
17231da177e4SLinus Torvalds 		default:
17241da177e4SLinus Torvalds 			*out_sid = tsid;
17251da177e4SLinus Torvalds 			break;
17261da177e4SLinus Torvalds 		}
17271da177e4SLinus Torvalds 		goto out;
17281da177e4SLinus Torvalds 	}
17291da177e4SLinus Torvalds 
17309ad6e9cbSOndrej Mosnacek retry:
17319ad6e9cbSOndrej Mosnacek 	cladatum = NULL;
1732851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1733851f8a69SVenkat Yekkirala 
17341b8b31a2SStephen Smalley 	rcu_read_lock();
17351b8b31a2SStephen Smalley 
1736e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
17371da177e4SLinus Torvalds 
17386f5317e7SHarry Ciao 	if (kern) {
17391b8b31a2SStephen Smalley 		tclass = unmap_class(&policy->map, orig_tclass);
17406f5317e7SHarry Ciao 		sock = security_is_socket_class(orig_tclass);
17416f5317e7SHarry Ciao 	} else {
1742c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
17431b8b31a2SStephen Smalley 		sock = security_is_socket_class(map_class(&policy->map,
1744aa8e712cSStephen Smalley 							  tclass));
17456f5317e7SHarry Ciao 	}
1746c6d3aaa4SStephen Smalley 
17471b8b31a2SStephen Smalley 	policydb = &policy->policydb;
17481b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1749aa8e712cSStephen Smalley 
1750d97bd23cSOndrej Mosnacek 	sentry = sidtab_search_entry(sidtab, ssid);
1751d97bd23cSOndrej Mosnacek 	if (!sentry) {
1752b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1753744ba35eSEric Paris 		       __func__, ssid);
17541da177e4SLinus Torvalds 		rc = -EINVAL;
17551da177e4SLinus Torvalds 		goto out_unlock;
17561da177e4SLinus Torvalds 	}
1757d97bd23cSOndrej Mosnacek 	tentry = sidtab_search_entry(sidtab, tsid);
1758d97bd23cSOndrej Mosnacek 	if (!tentry) {
1759b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1760744ba35eSEric Paris 		       __func__, tsid);
17611da177e4SLinus Torvalds 		rc = -EINVAL;
17621da177e4SLinus Torvalds 		goto out_unlock;
17631da177e4SLinus Torvalds 	}
17641da177e4SLinus Torvalds 
1765d97bd23cSOndrej Mosnacek 	scontext = &sentry->context;
1766d97bd23cSOndrej Mosnacek 	tcontext = &tentry->context;
1767d97bd23cSOndrej Mosnacek 
1768aa8e712cSStephen Smalley 	if (tclass && tclass <= policydb->p_classes.nprim)
1769aa8e712cSStephen Smalley 		cladatum = policydb->class_val_to_struct[tclass - 1];
1770aa893269SEric Paris 
17711da177e4SLinus Torvalds 	/* Set the user identity. */
17721da177e4SLinus Torvalds 	switch (specified) {
17731da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
17741da177e4SLinus Torvalds 	case AVTAB_CHANGE:
1775aa893269SEric Paris 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1776aa893269SEric Paris 			newcontext.user = tcontext->user;
1777aa893269SEric Paris 		} else {
1778aa893269SEric Paris 			/* notice this gets both DEFAULT_SOURCE and unset */
17791da177e4SLinus Torvalds 			/* Use the process user identity. */
17801da177e4SLinus Torvalds 			newcontext.user = scontext->user;
1781aa893269SEric Paris 		}
17821da177e4SLinus Torvalds 		break;
17831da177e4SLinus Torvalds 	case AVTAB_MEMBER:
17841da177e4SLinus Torvalds 		/* Use the related object owner. */
17851da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
17861da177e4SLinus Torvalds 		break;
17871da177e4SLinus Torvalds 	}
17881da177e4SLinus Torvalds 
1789aa893269SEric Paris 	/* Set the role to default values. */
1790aa893269SEric Paris 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
17911da177e4SLinus Torvalds 		newcontext.role = scontext->role;
1792aa893269SEric Paris 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1793aa893269SEric Paris 		newcontext.role = tcontext->role;
1794aa893269SEric Paris 	} else {
17954b850396SZou Wei 		if ((tclass == policydb->process_class) || sock)
1796aa893269SEric Paris 			newcontext.role = scontext->role;
1797aa893269SEric Paris 		else
1798aa893269SEric Paris 			newcontext.role = OBJECT_R_VAL;
1799aa893269SEric Paris 	}
1800aa893269SEric Paris 
1801aa893269SEric Paris 	/* Set the type to default values. */
1802eed7795dSEric Paris 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1803eed7795dSEric Paris 		newcontext.type = scontext->type;
1804eed7795dSEric Paris 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1805eed7795dSEric Paris 		newcontext.type = tcontext->type;
1806eed7795dSEric Paris 	} else {
18074b850396SZou Wei 		if ((tclass == policydb->process_class) || sock) {
1808aa893269SEric Paris 			/* Use the type of process. */
18091da177e4SLinus Torvalds 			newcontext.type = scontext->type;
1810c6d3aaa4SStephen Smalley 		} else {
18111da177e4SLinus Torvalds 			/* Use the type of the related object. */
18121da177e4SLinus Torvalds 			newcontext.type = tcontext->type;
18131da177e4SLinus Torvalds 		}
1814eed7795dSEric Paris 	}
18151da177e4SLinus Torvalds 
18161da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
18171da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
18181da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
18191da177e4SLinus Torvalds 	avkey.target_class = tclass;
1820782ebb99SStephen Smalley 	avkey.specified = specified;
182108a12b39SChristian Göttsche 	avnode = avtab_search_node(&policydb->te_avtab, &avkey);
18221da177e4SLinus Torvalds 
18231da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
182408a12b39SChristian Göttsche 	if (!avnode) {
1825aa8e712cSStephen Smalley 		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1826dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1827782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
182808a12b39SChristian Göttsche 				avnode = node;
18291da177e4SLinus Torvalds 				break;
18301da177e4SLinus Torvalds 			}
18311da177e4SLinus Torvalds 		}
18321da177e4SLinus Torvalds 	}
18331da177e4SLinus Torvalds 
183408a12b39SChristian Göttsche 	if (avnode) {
18351da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
183608a12b39SChristian Göttsche 		newcontext.type = avnode->datum.u.data;
18371da177e4SLinus Torvalds 	}
18381da177e4SLinus Torvalds 
18394742600cSEric Paris 	/* if we have a objname this is a file trans check so check those rules */
1840f50a3ec9SKohei Kaigai 	if (objname)
1841aa8e712cSStephen Smalley 		filename_compute_type(policydb, &newcontext, scontext->type,
1842f50a3ec9SKohei Kaigai 				      tcontext->type, tclass, objname);
1843652bb9b0SEric Paris 
18441da177e4SLinus Torvalds 	/* Check for class-specific changes. */
18451da177e4SLinus Torvalds 	if (specified & AVTAB_TRANSITION) {
18461da177e4SLinus Torvalds 		/* Look for a role transition rule. */
1847e67b2ec9SOndrej Mosnacek 		struct role_trans_datum *rtd;
1848e67b2ec9SOndrej Mosnacek 		struct role_trans_key rtk = {
1849e67b2ec9SOndrej Mosnacek 			.role = scontext->role,
1850e67b2ec9SOndrej Mosnacek 			.type = tcontext->type,
1851e67b2ec9SOndrej Mosnacek 			.tclass = tclass,
1852e67b2ec9SOndrej Mosnacek 		};
1853e67b2ec9SOndrej Mosnacek 
185424def7bbSOndrej Mosnacek 		rtd = policydb_roletr_search(policydb, &rtk);
1855e67b2ec9SOndrej Mosnacek 		if (rtd)
1856e67b2ec9SOndrej Mosnacek 			newcontext.role = rtd->new_role;
18571da177e4SLinus Torvalds 	}
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	/* Set the MLS attributes.
18601da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
1861aa8e712cSStephen Smalley 	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
18626f5317e7SHarry Ciao 			     &newcontext, sock);
18631da177e4SLinus Torvalds 	if (rc)
18641da177e4SLinus Torvalds 		goto out_unlock;
18651da177e4SLinus Torvalds 
18661da177e4SLinus Torvalds 	/* Check the validity of the context. */
1867aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcontext)) {
1868e67b7985SStephen Smalley 		rc = compute_sid_handle_invalid_context(policy, sentry,
18691b8b31a2SStephen Smalley 							tentry, tclass,
18701b8b31a2SStephen Smalley 							&newcontext);
18711da177e4SLinus Torvalds 		if (rc)
18721da177e4SLinus Torvalds 			goto out_unlock;
18731da177e4SLinus Torvalds 	}
18741da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
1875225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
18769ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
18779ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
18789ad6e9cbSOndrej Mosnacek 		context_destroy(&newcontext);
18799ad6e9cbSOndrej Mosnacek 		goto retry;
18809ad6e9cbSOndrej Mosnacek 	}
18811da177e4SLinus Torvalds out_unlock:
18821b8b31a2SStephen Smalley 	rcu_read_unlock();
18831da177e4SLinus Torvalds 	context_destroy(&newcontext);
18841da177e4SLinus Torvalds out:
18851da177e4SLinus Torvalds 	return rc;
18861da177e4SLinus Torvalds }
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds /**
18891da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
18901da177e4SLinus Torvalds  * @ssid: source security identifier
18911da177e4SLinus Torvalds  * @tsid: target security identifier
18921da177e4SLinus Torvalds  * @tclass: target security class
1893e9fd7292SPaul Moore  * @qstr: object name
18941da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
18951da177e4SLinus Torvalds  *
18961da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
18971da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
18981da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18991da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
19001da177e4SLinus Torvalds  * computed successfully.
19011da177e4SLinus Torvalds  */
security_transition_sid(u32 ssid,u32 tsid,u16 tclass,const struct qstr * qstr,u32 * out_sid)1902e67b7985SStephen Smalley int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1903652bb9b0SEric Paris 			    const struct qstr *qstr, u32 *out_sid)
19041da177e4SLinus Torvalds {
1905e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1906aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1907f50a3ec9SKohei Kaigai 				    qstr ? qstr->name : NULL, out_sid, true);
1908c6d3aaa4SStephen Smalley }
1909c6d3aaa4SStephen Smalley 
security_transition_sid_user(u32 ssid,u32 tsid,u16 tclass,const char * objname,u32 * out_sid)1910e67b7985SStephen Smalley int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1911f50a3ec9SKohei Kaigai 				 const char *objname, u32 *out_sid)
1912c6d3aaa4SStephen Smalley {
1913e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1914aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1915f50a3ec9SKohei Kaigai 				    objname, out_sid, false);
19161da177e4SLinus Torvalds }
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds /**
19191da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
19201da177e4SLinus Torvalds  * @ssid: source security identifier
19211da177e4SLinus Torvalds  * @tsid: target security identifier
19221da177e4SLinus Torvalds  * @tclass: target security class
19231da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
19241da177e4SLinus Torvalds  *
19251da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
19261da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
19271da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19281da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
19291da177e4SLinus Torvalds  * computed successfully.
19301da177e4SLinus Torvalds  */
security_member_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1931e67b7985SStephen Smalley int security_member_sid(u32 ssid,
19321da177e4SLinus Torvalds 			u32 tsid,
19331da177e4SLinus Torvalds 			u16 tclass,
19341da177e4SLinus Torvalds 			u32 *out_sid)
19351da177e4SLinus Torvalds {
1936e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1937aa8e712cSStephen Smalley 				    AVTAB_MEMBER, NULL,
1938652bb9b0SEric Paris 				    out_sid, false);
19391da177e4SLinus Torvalds }
19401da177e4SLinus Torvalds 
19411da177e4SLinus Torvalds /**
19421da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
19431da177e4SLinus Torvalds  * @ssid: source security identifier
19441da177e4SLinus Torvalds  * @tsid: target security identifier
19451da177e4SLinus Torvalds  * @tclass: target security class
19461da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
19471da177e4SLinus Torvalds  *
19481da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
19491da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
19501da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19511da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
19521da177e4SLinus Torvalds  * computed successfully.
19531da177e4SLinus Torvalds  */
security_change_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1954e67b7985SStephen Smalley int security_change_sid(u32 ssid,
19551da177e4SLinus Torvalds 			u32 tsid,
19561da177e4SLinus Torvalds 			u16 tclass,
19571da177e4SLinus Torvalds 			u32 *out_sid)
19581da177e4SLinus Torvalds {
1959e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1960652bb9b0SEric Paris 				    out_sid, false);
1961b94c7e67SChad Sellers }
1962b94c7e67SChad Sellers 
convert_context_handle_invalid_context(struct policydb * policydb,struct context * context)1963aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context(
19641b8b31a2SStephen Smalley 	struct policydb *policydb,
1965aa8e712cSStephen Smalley 	struct context *context)
19661da177e4SLinus Torvalds {
19671da177e4SLinus Torvalds 	char *s;
19681da177e4SLinus Torvalds 	u32 len;
19691da177e4SLinus Torvalds 
1970e67b7985SStephen Smalley 	if (enforcing_enabled())
19714b02b524SEric Paris 		return -EINVAL;
19724b02b524SEric Paris 
1973aa8e712cSStephen Smalley 	if (!context_struct_to_string(policydb, context, &s, &len)) {
1974b54c85c1Speter enderborg 		pr_warn("SELinux:  Context %s would be invalid if enforcing\n",
1975b54c85c1Speter enderborg 			s);
19761da177e4SLinus Torvalds 		kfree(s);
19771da177e4SLinus Torvalds 	}
19784b02b524SEric Paris 	return 0;
19791da177e4SLinus Torvalds }
19801da177e4SLinus Torvalds 
1981048be156SPaul Moore /**
1982048be156SPaul Moore  * services_convert_context - Convert a security context across policies.
1983048be156SPaul Moore  * @args: populated convert_context_args struct
1984048be156SPaul Moore  * @oldc: original context
1985048be156SPaul Moore  * @newc: converted context
198657888f7bSLinus Torvalds  * @gfp_flags: allocation flags
1987048be156SPaul Moore  *
1988048be156SPaul Moore  * Convert the values in the security context structure @oldc from the values
1989048be156SPaul Moore  * specified in the policy @args->oldp to the values specified in the policy
1990048be156SPaul Moore  * @args->newp, storing the new context in @newc, and verifying that the
1991048be156SPaul Moore  * context is valid under the new policy.
19921da177e4SLinus Torvalds  */
services_convert_context(struct convert_context_args * args,struct context * oldc,struct context * newc,gfp_t gfp_flags)1993048be156SPaul Moore int services_convert_context(struct convert_context_args *args,
199457888f7bSLinus Torvalds 			     struct context *oldc, struct context *newc,
1995abe3c631SGONG, Ruiqi 			     gfp_t gfp_flags)
19961da177e4SLinus Torvalds {
19970719aaf5SGuido Trentalancia 	struct ocontext *oc;
19981da177e4SLinus Torvalds 	struct role_datum *role;
19991da177e4SLinus Torvalds 	struct type_datum *typdatum;
20001da177e4SLinus Torvalds 	struct user_datum *usrdatum;
20011da177e4SLinus Torvalds 	char *s;
20021da177e4SLinus Torvalds 	u32 len;
200324ed7fdaSOndrej Mosnacek 	int rc;
20041da177e4SLinus Torvalds 
2005ee1a84fdSOndrej Mosnacek 	if (oldc->str) {
2006abe3c631SGONG, Ruiqi 		s = kstrdup(oldc->str, gfp_flags);
20074b02b524SEric Paris 		if (!s)
2008ee1a84fdSOndrej Mosnacek 			return -ENOMEM;
20094b02b524SEric Paris 
2010048be156SPaul Moore 		rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
2011ee1a84fdSOndrej Mosnacek 		if (rc == -EINVAL) {
20122a524393SOndrej Mosnacek 			/*
20132a524393SOndrej Mosnacek 			 * Retain string representation for later mapping.
20142a524393SOndrej Mosnacek 			 *
20152a524393SOndrej Mosnacek 			 * IMPORTANT: We need to copy the contents of oldc->str
20162a524393SOndrej Mosnacek 			 * back into s again because string_to_context_struct()
20172a524393SOndrej Mosnacek 			 * may have garbled it.
20182a524393SOndrej Mosnacek 			 */
20192a524393SOndrej Mosnacek 			memcpy(s, oldc->str, oldc->len);
2020ee1a84fdSOndrej Mosnacek 			context_init(newc);
2021ee1a84fdSOndrej Mosnacek 			newc->str = s;
2022ee1a84fdSOndrej Mosnacek 			newc->len = oldc->len;
2023ee1a84fdSOndrej Mosnacek 			return 0;
2024ee1a84fdSOndrej Mosnacek 		}
2025ee1a84fdSOndrej Mosnacek 		kfree(s);
2026ee1a84fdSOndrej Mosnacek 		if (rc) {
202712b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
2028b54c85c1Speter enderborg 			pr_err("SELinux:   Unable to map context %s, rc = %d.\n",
2029ee1a84fdSOndrej Mosnacek 			       oldc->str, -rc);
2030ee1a84fdSOndrej Mosnacek 			return rc;
203112b29f34SStephen Smalley 		}
2032ee1a84fdSOndrej Mosnacek 		pr_info("SELinux:  Context %s became valid (mapped).\n",
2033ee1a84fdSOndrej Mosnacek 			oldc->str);
2034ee1a84fdSOndrej Mosnacek 		return 0;
203512b29f34SStephen Smalley 	}
203612b29f34SStephen Smalley 
2037ee1a84fdSOndrej Mosnacek 	context_init(newc);
20381da177e4SLinus Torvalds 
20391da177e4SLinus Torvalds 	/* Convert the user. */
2040237389e3SOndrej Mosnacek 	usrdatum = symtab_search(&args->newp->p_users,
2041048be156SPaul Moore 				 sym_name(args->oldp, SYM_USERS, oldc->user - 1));
20425d55a345SEric Paris 	if (!usrdatum)
20431da177e4SLinus Torvalds 		goto bad;
2044ee1a84fdSOndrej Mosnacek 	newc->user = usrdatum->value;
20451da177e4SLinus Torvalds 
20461da177e4SLinus Torvalds 	/* Convert the role. */
2047237389e3SOndrej Mosnacek 	role = symtab_search(&args->newp->p_roles,
2048ee1a84fdSOndrej Mosnacek 			     sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
20495d55a345SEric Paris 	if (!role)
20501da177e4SLinus Torvalds 		goto bad;
2051ee1a84fdSOndrej Mosnacek 	newc->role = role->value;
20521da177e4SLinus Torvalds 
20531da177e4SLinus Torvalds 	/* Convert the type. */
2054237389e3SOndrej Mosnacek 	typdatum = symtab_search(&args->newp->p_types,
2055048be156SPaul Moore 				 sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
20565d55a345SEric Paris 	if (!typdatum)
20571da177e4SLinus Torvalds 		goto bad;
2058ee1a84fdSOndrej Mosnacek 	newc->type = typdatum->value;
20591da177e4SLinus Torvalds 
20600719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
20610719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2062ee1a84fdSOndrej Mosnacek 		rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
20631da177e4SLinus Torvalds 		if (rc)
20641da177e4SLinus Torvalds 			goto bad;
20650719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
20660719aaf5SGuido Trentalancia 		/*
20670719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
20680719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
20690719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
20700719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
20710719aaf5SGuido Trentalancia 		 * initial SIDs.
20720719aaf5SGuido Trentalancia 		 */
20730719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
20740719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
20750719aaf5SGuido Trentalancia 			oc = oc->next;
20760719aaf5SGuido Trentalancia 		if (!oc) {
2077b54c85c1Speter enderborg 			pr_err("SELinux:  unable to look up"
20780719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
20790719aaf5SGuido Trentalancia 			goto bad;
20800719aaf5SGuido Trentalancia 		}
2081ee1a84fdSOndrej Mosnacek 		rc = mls_range_set(newc, &oc->context[0].range);
20820719aaf5SGuido Trentalancia 		if (rc)
20830719aaf5SGuido Trentalancia 			goto bad;
20840719aaf5SGuido Trentalancia 	}
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 	/* Check the validity of the new context. */
2087ee1a84fdSOndrej Mosnacek 	if (!policydb_context_isvalid(args->newp, newc)) {
2088e67b7985SStephen Smalley 		rc = convert_context_handle_invalid_context(args->oldp, oldc);
20891da177e4SLinus Torvalds 		if (rc)
20901da177e4SLinus Torvalds 			goto bad;
20911da177e4SLinus Torvalds 	}
20921da177e4SLinus Torvalds 
2093ee1a84fdSOndrej Mosnacek 	return 0;
20941da177e4SLinus Torvalds bad:
209512b29f34SStephen Smalley 	/* Map old representation to string and save it. */
2096ee1a84fdSOndrej Mosnacek 	rc = context_struct_to_string(args->oldp, oldc, &s, &len);
20974b02b524SEric Paris 	if (rc)
20984b02b524SEric Paris 		return rc;
2099ee1a84fdSOndrej Mosnacek 	context_destroy(newc);
2100ee1a84fdSOndrej Mosnacek 	newc->str = s;
2101ee1a84fdSOndrej Mosnacek 	newc->len = len;
2102b54c85c1Speter enderborg 	pr_info("SELinux:  Context %s became invalid (unmapped).\n",
2103ee1a84fdSOndrej Mosnacek 		newc->str);
2104ee1a84fdSOndrej Mosnacek 	return 0;
21051da177e4SLinus Torvalds }
21061da177e4SLinus Torvalds 
security_load_policycaps(struct selinux_policy * policy)2107e67b7985SStephen Smalley static void security_load_policycaps(struct selinux_policy *policy)
21083bb56b25SPaul Moore {
210946169802SStephen Smalley 	struct policydb *p;
21104dc2fce3SStephen Smalley 	unsigned int i;
21114dc2fce3SStephen Smalley 	struct ebitmap_node *node;
21124dc2fce3SStephen Smalley 
21131b8b31a2SStephen Smalley 	p = &policy->policydb;
211446169802SStephen Smalley 
2115e67b7985SStephen Smalley 	for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
2116e67b7985SStephen Smalley 		WRITE_ONCE(selinux_state.policycap[i],
2117e8ba53d0SStephen Smalley 			ebitmap_get_bit(&p->policycaps, i));
21184dc2fce3SStephen Smalley 
21194dc2fce3SStephen Smalley 	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
21204dc2fce3SStephen Smalley 		pr_info("SELinux:  policy capability %s=%d\n",
21214dc2fce3SStephen Smalley 			selinux_policycap_names[i],
2122aa8e712cSStephen Smalley 			ebitmap_get_bit(&p->policycaps, i));
21234dc2fce3SStephen Smalley 
2124aa8e712cSStephen Smalley 	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
21254dc2fce3SStephen Smalley 		if (i >= ARRAY_SIZE(selinux_policycap_names))
21264dc2fce3SStephen Smalley 			pr_info("SELinux:  unknown policy capability %u\n",
21274dc2fce3SStephen Smalley 				i);
21284dc2fce3SStephen Smalley 	}
21293bb56b25SPaul Moore }
21303bb56b25SPaul Moore 
21311b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
21321b8b31a2SStephen Smalley 				struct selinux_policy *newpolicy);
21331da177e4SLinus Torvalds 
selinux_policy_free(struct selinux_policy * policy)213446169802SStephen Smalley static void selinux_policy_free(struct selinux_policy *policy)
213546169802SStephen Smalley {
213646169802SStephen Smalley 	if (!policy)
213746169802SStephen Smalley 		return;
213846169802SStephen Smalley 
2139c7c556f1SStephen Smalley 	sidtab_destroy(policy->sidtab);
214046169802SStephen Smalley 	kfree(policy->map.mapping);
21410256b0aaSDan Carpenter 	policydb_destroy(&policy->policydb);
21420256b0aaSDan Carpenter 	kfree(policy->sidtab);
214346169802SStephen Smalley 	kfree(policy);
214446169802SStephen Smalley }
214546169802SStephen Smalley 
selinux_policy_cond_free(struct selinux_policy * policy)21461b8b31a2SStephen Smalley static void selinux_policy_cond_free(struct selinux_policy *policy)
21471b8b31a2SStephen Smalley {
21481b8b31a2SStephen Smalley 	cond_policydb_destroy_dup(&policy->policydb);
21491b8b31a2SStephen Smalley 	kfree(policy);
21501b8b31a2SStephen Smalley }
21511b8b31a2SStephen Smalley 
selinux_policy_cancel(struct selinux_load_state * load_state)2152e67b7985SStephen Smalley void selinux_policy_cancel(struct selinux_load_state *load_state)
215302a52c5cSStephen Smalley {
2154e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
21551b8b31a2SStephen Smalley 	struct selinux_policy *oldpolicy;
21561b8b31a2SStephen Smalley 
21579ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
21589ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
21591b8b31a2SStephen Smalley 
21601b8b31a2SStephen Smalley 	sidtab_cancel_convert(oldpolicy->sidtab);
21616406887aSOndrej Mosnacek 	selinux_policy_free(load_state->policy);
21626406887aSOndrej Mosnacek 	kfree(load_state->convert_data);
216302a52c5cSStephen Smalley }
216402a52c5cSStephen Smalley 
selinux_notify_policy_change(u32 seqno)2165e67b7985SStephen Smalley static void selinux_notify_policy_change(u32 seqno)
2166c7c556f1SStephen Smalley {
2167c7c556f1SStephen Smalley 	/* Flush external caches and notify userspace of policy load */
2168e67b7985SStephen Smalley 	avc_ss_reset(seqno);
2169c7c556f1SStephen Smalley 	selnl_notify_policyload(seqno);
2170e67b7985SStephen Smalley 	selinux_status_update_policyload(seqno);
2171c7c556f1SStephen Smalley 	selinux_netlbl_cache_invalidate();
2172c7c556f1SStephen Smalley 	selinux_xfrm_notify_policyload();
2173e67b7985SStephen Smalley 	selinux_ima_measure_state_locked();
2174c7c556f1SStephen Smalley }
2175c7c556f1SStephen Smalley 
selinux_policy_commit(struct selinux_load_state * load_state)2176e67b7985SStephen Smalley void selinux_policy_commit(struct selinux_load_state *load_state)
217746169802SStephen Smalley {
2178e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
21796406887aSOndrej Mosnacek 	struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
21809ad6e9cbSOndrej Mosnacek 	unsigned long flags;
218146169802SStephen Smalley 	u32 seqno;
218246169802SStephen Smalley 
21839ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
21849ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
218546169802SStephen Smalley 
218646169802SStephen Smalley 	/* If switching between different policy types, log MLS status */
218746169802SStephen Smalley 	if (oldpolicy) {
218846169802SStephen Smalley 		if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
218946169802SStephen Smalley 			pr_info("SELinux: Disabling MLS support...\n");
219046169802SStephen Smalley 		else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
219146169802SStephen Smalley 			pr_info("SELinux: Enabling MLS support...\n");
219246169802SStephen Smalley 	}
219346169802SStephen Smalley 
21941b8b31a2SStephen Smalley 	/* Set latest granting seqno for new policy. */
21951b8b31a2SStephen Smalley 	if (oldpolicy)
21961b8b31a2SStephen Smalley 		newpolicy->latest_granting = oldpolicy->latest_granting + 1;
21971b8b31a2SStephen Smalley 	else
21981b8b31a2SStephen Smalley 		newpolicy->latest_granting = 1;
21991b8b31a2SStephen Smalley 	seqno = newpolicy->latest_granting;
22001b8b31a2SStephen Smalley 
220146169802SStephen Smalley 	/* Install the new policy. */
22029ad6e9cbSOndrej Mosnacek 	if (oldpolicy) {
22039ad6e9cbSOndrej Mosnacek 		sidtab_freeze_begin(oldpolicy->sidtab, &flags);
22041b8b31a2SStephen Smalley 		rcu_assign_pointer(state->policy, newpolicy);
22059ad6e9cbSOndrej Mosnacek 		sidtab_freeze_end(oldpolicy->sidtab, &flags);
22069ad6e9cbSOndrej Mosnacek 	} else {
22079ad6e9cbSOndrej Mosnacek 		rcu_assign_pointer(state->policy, newpolicy);
22089ad6e9cbSOndrej Mosnacek 	}
220946169802SStephen Smalley 
221046169802SStephen Smalley 	/* Load the policycaps from the new policy */
2211e67b7985SStephen Smalley 	security_load_policycaps(newpolicy);
221246169802SStephen Smalley 
2213e67b7985SStephen Smalley 	if (!selinux_initialized()) {
221446169802SStephen Smalley 		/*
221546169802SStephen Smalley 		 * After first policy load, the security server is
221646169802SStephen Smalley 		 * marked as initialized and ready to handle requests and
221746169802SStephen Smalley 		 * any objects created prior to policy load are then labeled.
221846169802SStephen Smalley 		 */
2219e67b7985SStephen Smalley 		selinux_mark_initialized();
222046169802SStephen Smalley 		selinux_complete_init();
222146169802SStephen Smalley 	}
222246169802SStephen Smalley 
222346169802SStephen Smalley 	/* Free the old policy */
22241b8b31a2SStephen Smalley 	synchronize_rcu();
222546169802SStephen Smalley 	selinux_policy_free(oldpolicy);
22266406887aSOndrej Mosnacek 	kfree(load_state->convert_data);
222746169802SStephen Smalley 
2228c7c556f1SStephen Smalley 	/* Notify others of the policy change */
2229e67b7985SStephen Smalley 	selinux_notify_policy_change(seqno);
223046169802SStephen Smalley }
223146169802SStephen Smalley 
22321da177e4SLinus Torvalds /**
22331da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
22341da177e4SLinus Torvalds  * @data: binary policy data
22351da177e4SLinus Torvalds  * @len: length of data in bytes
2236e9fd7292SPaul Moore  * @load_state: policy load state
22371da177e4SLinus Torvalds  *
22381da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
22391da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
22401da177e4SLinus Torvalds  * This function will flush the access vector cache after
22411da177e4SLinus Torvalds  * loading the new policy.
22421da177e4SLinus Torvalds  */
security_load_policy(void * data,size_t len,struct selinux_load_state * load_state)2243e67b7985SStephen Smalley int security_load_policy(void *data, size_t len,
22446406887aSOndrej Mosnacek 			 struct selinux_load_state *load_state)
22451da177e4SLinus Torvalds {
2246e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
22471b8b31a2SStephen Smalley 	struct selinux_policy *newpolicy, *oldpolicy;
22486406887aSOndrej Mosnacek 	struct selinux_policy_convert_data *convert_data;
22491da177e4SLinus Torvalds 	int rc = 0;
22501da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
22511da177e4SLinus Torvalds 
225246169802SStephen Smalley 	newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
225346169802SStephen Smalley 	if (!newpolicy)
2254dd89b9d9SOndrej Mosnacek 		return -ENOMEM;
2255aa8e712cSStephen Smalley 
2256c7c556f1SStephen Smalley 	newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
22570256b0aaSDan Carpenter 	if (!newpolicy->sidtab) {
22580256b0aaSDan Carpenter 		rc = -ENOMEM;
22590256b0aaSDan Carpenter 		goto err_policy;
22600256b0aaSDan Carpenter 	}
2261c7c556f1SStephen Smalley 
226246169802SStephen Smalley 	rc = policydb_read(&newpolicy->policydb, fp);
2263a2000050SEric Paris 	if (rc)
22640256b0aaSDan Carpenter 		goto err_sidtab;
2265b94c7e67SChad Sellers 
226646169802SStephen Smalley 	newpolicy->policydb.len = len;
226746169802SStephen Smalley 	rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
226846169802SStephen Smalley 				&newpolicy->map);
226946169802SStephen Smalley 	if (rc)
22700256b0aaSDan Carpenter 		goto err_policydb;
227146169802SStephen Smalley 
2272c7c556f1SStephen Smalley 	rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
227346169802SStephen Smalley 	if (rc) {
227446169802SStephen Smalley 		pr_err("SELinux:  unable to load the initial SIDs\n");
22750256b0aaSDan Carpenter 		goto err_mapping;
227646169802SStephen Smalley 	}
227746169802SStephen Smalley 
2278e67b7985SStephen Smalley 	if (!selinux_initialized()) {
227946169802SStephen Smalley 		/* First policy load, so no need to preserve state from old policy */
22806406887aSOndrej Mosnacek 		load_state->policy = newpolicy;
22816406887aSOndrej Mosnacek 		load_state->convert_data = NULL;
228246169802SStephen Smalley 		return 0;
228346169802SStephen Smalley 	}
228446169802SStephen Smalley 
22859ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
22869ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
22871b8b31a2SStephen Smalley 
228846169802SStephen Smalley 	/* Preserve active boolean values from the old policy */
22891b8b31a2SStephen Smalley 	rc = security_preserve_bools(oldpolicy, newpolicy);
2290e900a7d9SStephen Smalley 	if (rc) {
2291b54c85c1Speter enderborg 		pr_err("SELinux:  unable to preserve booleans\n");
22920256b0aaSDan Carpenter 		goto err_free_isids;
2293e900a7d9SStephen Smalley 	}
2294e900a7d9SStephen Smalley 
2295048be156SPaul Moore 	/*
2296048be156SPaul Moore 	 * Convert the internal representations of contexts
2297048be156SPaul Moore 	 * in the new SID table.
2298048be156SPaul Moore 	 */
2299048be156SPaul Moore 
23006406887aSOndrej Mosnacek 	convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
23016406887aSOndrej Mosnacek 	if (!convert_data) {
23026406887aSOndrej Mosnacek 		rc = -ENOMEM;
23036406887aSOndrej Mosnacek 		goto err_free_isids;
23046406887aSOndrej Mosnacek 	}
23056406887aSOndrej Mosnacek 
23066406887aSOndrej Mosnacek 	convert_data->args.oldp = &oldpolicy->policydb;
23076406887aSOndrej Mosnacek 	convert_data->args.newp = &newpolicy->policydb;
2308ee1a84fdSOndrej Mosnacek 
23096406887aSOndrej Mosnacek 	convert_data->sidtab_params.args = &convert_data->args;
23106406887aSOndrej Mosnacek 	convert_data->sidtab_params.target = newpolicy->sidtab;
2311ee1a84fdSOndrej Mosnacek 
23126406887aSOndrej Mosnacek 	rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
23130719aaf5SGuido Trentalancia 	if (rc) {
2314b54c85c1Speter enderborg 		pr_err("SELinux:  unable to convert the internal"
23150719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
23160719aaf5SGuido Trentalancia 			" table\n");
23176406887aSOndrej Mosnacek 		goto err_free_convert_data;
23180719aaf5SGuido Trentalancia 	}
23191da177e4SLinus Torvalds 
23206406887aSOndrej Mosnacek 	load_state->policy = newpolicy;
23216406887aSOndrej Mosnacek 	load_state->convert_data = convert_data;
232246169802SStephen Smalley 	return 0;
23230256b0aaSDan Carpenter 
23246406887aSOndrej Mosnacek err_free_convert_data:
23256406887aSOndrej Mosnacek 	kfree(convert_data);
23260256b0aaSDan Carpenter err_free_isids:
23270256b0aaSDan Carpenter 	sidtab_destroy(newpolicy->sidtab);
23280256b0aaSDan Carpenter err_mapping:
23290256b0aaSDan Carpenter 	kfree(newpolicy->map.mapping);
23300256b0aaSDan Carpenter err_policydb:
23310256b0aaSDan Carpenter 	policydb_destroy(&newpolicy->policydb);
23320256b0aaSDan Carpenter err_sidtab:
23330256b0aaSDan Carpenter 	kfree(newpolicy->sidtab);
23340256b0aaSDan Carpenter err_policy:
23350256b0aaSDan Carpenter 	kfree(newpolicy);
23360256b0aaSDan Carpenter 
2337b5495b42STim Gardner 	return rc;
23381da177e4SLinus Torvalds }
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds /**
2341cbfcd13bSOndrej Mosnacek  * ocontext_to_sid - Helper to safely get sid for an ocontext
2342cbfcd13bSOndrej Mosnacek  * @sidtab: SID table
2343cbfcd13bSOndrej Mosnacek  * @c: ocontext structure
2344cbfcd13bSOndrej Mosnacek  * @index: index of the context entry (0 or 1)
2345cbfcd13bSOndrej Mosnacek  * @out_sid: pointer to the resulting SID value
2346cbfcd13bSOndrej Mosnacek  *
2347cbfcd13bSOndrej Mosnacek  * For all ocontexts except OCON_ISID the SID fields are populated
2348cbfcd13bSOndrej Mosnacek  * on-demand when needed. Since updating the SID value is an SMP-sensitive
2349cbfcd13bSOndrej Mosnacek  * operation, this helper must be used to do that safely.
2350cbfcd13bSOndrej Mosnacek  *
2351cbfcd13bSOndrej Mosnacek  * WARNING: This function may return -ESTALE, indicating that the caller
2352cbfcd13bSOndrej Mosnacek  * must retry the operation after re-acquiring the policy pointer!
2353cbfcd13bSOndrej Mosnacek  */
ocontext_to_sid(struct sidtab * sidtab,struct ocontext * c,size_t index,u32 * out_sid)2354cbfcd13bSOndrej Mosnacek static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
2355cbfcd13bSOndrej Mosnacek 			   size_t index, u32 *out_sid)
2356cbfcd13bSOndrej Mosnacek {
2357cbfcd13bSOndrej Mosnacek 	int rc;
2358cbfcd13bSOndrej Mosnacek 	u32 sid;
2359cbfcd13bSOndrej Mosnacek 
2360cbfcd13bSOndrej Mosnacek 	/* Ensure the associated sidtab entry is visible to this thread. */
2361cbfcd13bSOndrej Mosnacek 	sid = smp_load_acquire(&c->sid[index]);
2362cbfcd13bSOndrej Mosnacek 	if (!sid) {
2363cbfcd13bSOndrej Mosnacek 		rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
2364cbfcd13bSOndrej Mosnacek 		if (rc)
2365cbfcd13bSOndrej Mosnacek 			return rc;
2366cbfcd13bSOndrej Mosnacek 
2367cbfcd13bSOndrej Mosnacek 		/*
2368cbfcd13bSOndrej Mosnacek 		 * Ensure the new sidtab entry is visible to other threads
2369cbfcd13bSOndrej Mosnacek 		 * when they see the SID.
2370cbfcd13bSOndrej Mosnacek 		 */
2371cbfcd13bSOndrej Mosnacek 		smp_store_release(&c->sid[index], sid);
2372cbfcd13bSOndrej Mosnacek 	}
2373cbfcd13bSOndrej Mosnacek 	*out_sid = sid;
2374cbfcd13bSOndrej Mosnacek 	return 0;
2375cbfcd13bSOndrej Mosnacek }
2376cbfcd13bSOndrej Mosnacek 
2377cbfcd13bSOndrej Mosnacek /**
23781da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
23791da177e4SLinus Torvalds  * @protocol: protocol number
23801da177e4SLinus Torvalds  * @port: port number
23811da177e4SLinus Torvalds  * @out_sid: security identifier
23821da177e4SLinus Torvalds  */
security_port_sid(u8 protocol,u16 port,u32 * out_sid)2383e67b7985SStephen Smalley int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
23841da177e4SLinus Torvalds {
23851b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2386aa8e712cSStephen Smalley 	struct policydb *policydb;
2387225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
23881da177e4SLinus Torvalds 	struct ocontext *c;
23899ad6e9cbSOndrej Mosnacek 	int rc;
23901da177e4SLinus Torvalds 
2391e67b7985SStephen Smalley 	if (!selinux_initialized()) {
239237ea433cSStephen Smalley 		*out_sid = SECINITSID_PORT;
239337ea433cSStephen Smalley 		return 0;
239437ea433cSStephen Smalley 	}
239537ea433cSStephen Smalley 
23969ad6e9cbSOndrej Mosnacek retry:
23979ad6e9cbSOndrej Mosnacek 	rc = 0;
23981b8b31a2SStephen Smalley 	rcu_read_lock();
2399e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
24001b8b31a2SStephen Smalley 	policydb = &policy->policydb;
24011b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2402aa8e712cSStephen Smalley 
2403aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_PORT];
24041da177e4SLinus Torvalds 	while (c) {
24051da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
24061da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
24071da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
24081da177e4SLinus Torvalds 			break;
24091da177e4SLinus Torvalds 		c = c->next;
24101da177e4SLinus Torvalds 	}
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	if (c) {
2413cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24149ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
24159ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
24169ad6e9cbSOndrej Mosnacek 			goto retry;
24179ad6e9cbSOndrej Mosnacek 		}
24181da177e4SLinus Torvalds 		if (rc)
24191da177e4SLinus Torvalds 			goto out;
24201da177e4SLinus Torvalds 	} else {
24211da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
24221da177e4SLinus Torvalds 	}
24231da177e4SLinus Torvalds 
24241da177e4SLinus Torvalds out:
24251b8b31a2SStephen Smalley 	rcu_read_unlock();
24261da177e4SLinus Torvalds 	return rc;
24271da177e4SLinus Torvalds }
24281da177e4SLinus Torvalds 
24291da177e4SLinus Torvalds /**
2430d0a83314SYang Li  * security_ib_pkey_sid - Obtain the SID for a pkey.
2431cfc4d882SDaniel Jurgens  * @subnet_prefix: Subnet Prefix
2432cfc4d882SDaniel Jurgens  * @pkey_num: pkey number
2433cfc4d882SDaniel Jurgens  * @out_sid: security identifier
2434cfc4d882SDaniel Jurgens  */
security_ib_pkey_sid(u64 subnet_prefix,u16 pkey_num,u32 * out_sid)2435e67b7985SStephen Smalley int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2436cfc4d882SDaniel Jurgens {
24371b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2438aa8e712cSStephen Smalley 	struct policydb *policydb;
2439225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
2440cfc4d882SDaniel Jurgens 	struct ocontext *c;
24419ad6e9cbSOndrej Mosnacek 	int rc;
2442cfc4d882SDaniel Jurgens 
2443e67b7985SStephen Smalley 	if (!selinux_initialized()) {
244437ea433cSStephen Smalley 		*out_sid = SECINITSID_UNLABELED;
244537ea433cSStephen Smalley 		return 0;
244637ea433cSStephen Smalley 	}
244737ea433cSStephen Smalley 
24489ad6e9cbSOndrej Mosnacek retry:
24499ad6e9cbSOndrej Mosnacek 	rc = 0;
24501b8b31a2SStephen Smalley 	rcu_read_lock();
2451e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
24521b8b31a2SStephen Smalley 	policydb = &policy->policydb;
24531b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2454aa8e712cSStephen Smalley 
2455aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBPKEY];
2456cfc4d882SDaniel Jurgens 	while (c) {
2457cfc4d882SDaniel Jurgens 		if (c->u.ibpkey.low_pkey <= pkey_num &&
2458cfc4d882SDaniel Jurgens 		    c->u.ibpkey.high_pkey >= pkey_num &&
2459cfc4d882SDaniel Jurgens 		    c->u.ibpkey.subnet_prefix == subnet_prefix)
2460cfc4d882SDaniel Jurgens 			break;
2461cfc4d882SDaniel Jurgens 
2462cfc4d882SDaniel Jurgens 		c = c->next;
2463cfc4d882SDaniel Jurgens 	}
2464cfc4d882SDaniel Jurgens 
2465cfc4d882SDaniel Jurgens 	if (c) {
2466cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24679ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
24689ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
24699ad6e9cbSOndrej Mosnacek 			goto retry;
24709ad6e9cbSOndrej Mosnacek 		}
2471cfc4d882SDaniel Jurgens 		if (rc)
2472cfc4d882SDaniel Jurgens 			goto out;
2473cfc4d882SDaniel Jurgens 	} else
2474cfc4d882SDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2475cfc4d882SDaniel Jurgens 
2476cfc4d882SDaniel Jurgens out:
24771b8b31a2SStephen Smalley 	rcu_read_unlock();
2478cfc4d882SDaniel Jurgens 	return rc;
2479cfc4d882SDaniel Jurgens }
2480cfc4d882SDaniel Jurgens 
2481cfc4d882SDaniel Jurgens /**
2482ab861dfcSDaniel Jurgens  * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2483ab861dfcSDaniel Jurgens  * @dev_name: device name
2484e9fd7292SPaul Moore  * @port_num: port number
2485ab861dfcSDaniel Jurgens  * @out_sid: security identifier
2486ab861dfcSDaniel Jurgens  */
security_ib_endport_sid(const char * dev_name,u8 port_num,u32 * out_sid)2487e67b7985SStephen Smalley int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
2488ab861dfcSDaniel Jurgens {
24891b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2490aa8e712cSStephen Smalley 	struct policydb *policydb;
2491225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
2492ab861dfcSDaniel Jurgens 	struct ocontext *c;
24939ad6e9cbSOndrej Mosnacek 	int rc;
2494ab861dfcSDaniel Jurgens 
2495e67b7985SStephen Smalley 	if (!selinux_initialized()) {
249637ea433cSStephen Smalley 		*out_sid = SECINITSID_UNLABELED;
249737ea433cSStephen Smalley 		return 0;
249837ea433cSStephen Smalley 	}
249937ea433cSStephen Smalley 
25009ad6e9cbSOndrej Mosnacek retry:
25019ad6e9cbSOndrej Mosnacek 	rc = 0;
25021b8b31a2SStephen Smalley 	rcu_read_lock();
2503e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
25041b8b31a2SStephen Smalley 	policydb = &policy->policydb;
25051b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2506aa8e712cSStephen Smalley 
2507aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBENDPORT];
2508ab861dfcSDaniel Jurgens 	while (c) {
2509ab861dfcSDaniel Jurgens 		if (c->u.ibendport.port == port_num &&
2510ab861dfcSDaniel Jurgens 		    !strncmp(c->u.ibendport.dev_name,
2511ab861dfcSDaniel Jurgens 			     dev_name,
2512ab861dfcSDaniel Jurgens 			     IB_DEVICE_NAME_MAX))
2513ab861dfcSDaniel Jurgens 			break;
2514ab861dfcSDaniel Jurgens 
2515ab861dfcSDaniel Jurgens 		c = c->next;
2516ab861dfcSDaniel Jurgens 	}
2517ab861dfcSDaniel Jurgens 
2518ab861dfcSDaniel Jurgens 	if (c) {
2519cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
25209ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
25219ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
25229ad6e9cbSOndrej Mosnacek 			goto retry;
25239ad6e9cbSOndrej Mosnacek 		}
2524ab861dfcSDaniel Jurgens 		if (rc)
2525ab861dfcSDaniel Jurgens 			goto out;
2526ab861dfcSDaniel Jurgens 	} else
2527ab861dfcSDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2528ab861dfcSDaniel Jurgens 
2529ab861dfcSDaniel Jurgens out:
25301b8b31a2SStephen Smalley 	rcu_read_unlock();
2531ab861dfcSDaniel Jurgens 	return rc;
2532ab861dfcSDaniel Jurgens }
2533ab861dfcSDaniel Jurgens 
2534ab861dfcSDaniel Jurgens /**
25351da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
25361da177e4SLinus Torvalds  * @name: interface name
25371da177e4SLinus Torvalds  * @if_sid: interface SID
25381da177e4SLinus Torvalds  */
security_netif_sid(char * name,u32 * if_sid)2539e67b7985SStephen Smalley int security_netif_sid(char *name, u32 *if_sid)
25401da177e4SLinus Torvalds {
25411b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2542aa8e712cSStephen Smalley 	struct policydb *policydb;
2543225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
25449ad6e9cbSOndrej Mosnacek 	int rc;
25451da177e4SLinus Torvalds 	struct ocontext *c;
25461da177e4SLinus Torvalds 
2547e67b7985SStephen Smalley 	if (!selinux_initialized()) {
254837ea433cSStephen Smalley 		*if_sid = SECINITSID_NETIF;
254937ea433cSStephen Smalley 		return 0;
255037ea433cSStephen Smalley 	}
255137ea433cSStephen Smalley 
25529ad6e9cbSOndrej Mosnacek retry:
25539ad6e9cbSOndrej Mosnacek 	rc = 0;
25541b8b31a2SStephen Smalley 	rcu_read_lock();
2555e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
25561b8b31a2SStephen Smalley 	policydb = &policy->policydb;
25571b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2558aa8e712cSStephen Smalley 
2559aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_NETIF];
25601da177e4SLinus Torvalds 	while (c) {
25611da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
25621da177e4SLinus Torvalds 			break;
25631da177e4SLinus Torvalds 		c = c->next;
25641da177e4SLinus Torvalds 	}
25651da177e4SLinus Torvalds 
25661da177e4SLinus Torvalds 	if (c) {
2567cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, if_sid);
25689ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
25699ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
25709ad6e9cbSOndrej Mosnacek 			goto retry;
25719ad6e9cbSOndrej Mosnacek 		}
25721da177e4SLinus Torvalds 		if (rc)
25731da177e4SLinus Torvalds 			goto out;
2574e8bfdb9dSPaul Moore 	} else
25751da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
25761da177e4SLinus Torvalds 
25771da177e4SLinus Torvalds out:
25781b8b31a2SStephen Smalley 	rcu_read_unlock();
25791da177e4SLinus Torvalds 	return rc;
25801da177e4SLinus Torvalds }
25811da177e4SLinus Torvalds 
match_ipv6_addrmask(u32 * input,u32 * addr,u32 * mask)25821da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
25831da177e4SLinus Torvalds {
25841da177e4SLinus Torvalds 	int i, fail = 0;
25851da177e4SLinus Torvalds 
25861da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
25871da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
25881da177e4SLinus Torvalds 			fail = 1;
25891da177e4SLinus Torvalds 			break;
25901da177e4SLinus Torvalds 		}
25911da177e4SLinus Torvalds 
25921da177e4SLinus Torvalds 	return !fail;
25931da177e4SLinus Torvalds }
25941da177e4SLinus Torvalds 
25951da177e4SLinus Torvalds /**
25961da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
25971da177e4SLinus Torvalds  * @domain: communication domain aka address family
25981da177e4SLinus Torvalds  * @addrp: address
25991da177e4SLinus Torvalds  * @addrlen: address length in bytes
26001da177e4SLinus Torvalds  * @out_sid: security identifier
26011da177e4SLinus Torvalds  */
security_node_sid(u16 domain,void * addrp,u32 addrlen,u32 * out_sid)2602e67b7985SStephen Smalley int security_node_sid(u16 domain,
26031da177e4SLinus Torvalds 		      void *addrp,
26041da177e4SLinus Torvalds 		      u32 addrlen,
26051da177e4SLinus Torvalds 		      u32 *out_sid)
26061da177e4SLinus Torvalds {
26071b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2608aa8e712cSStephen Smalley 	struct policydb *policydb;
2609225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
26104b02b524SEric Paris 	int rc;
26111da177e4SLinus Torvalds 	struct ocontext *c;
26121da177e4SLinus Torvalds 
2613e67b7985SStephen Smalley 	if (!selinux_initialized()) {
261437ea433cSStephen Smalley 		*out_sid = SECINITSID_NODE;
261537ea433cSStephen Smalley 		return 0;
261637ea433cSStephen Smalley 	}
261737ea433cSStephen Smalley 
26189ad6e9cbSOndrej Mosnacek retry:
26191b8b31a2SStephen Smalley 	rcu_read_lock();
2620e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
26211b8b31a2SStephen Smalley 	policydb = &policy->policydb;
26221b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
26231da177e4SLinus Torvalds 
26241da177e4SLinus Torvalds 	switch (domain) {
26251da177e4SLinus Torvalds 	case AF_INET: {
26261da177e4SLinus Torvalds 		u32 addr;
26271da177e4SLinus Torvalds 
26281da177e4SLinus Torvalds 		rc = -EINVAL;
26294b02b524SEric Paris 		if (addrlen != sizeof(u32))
26301da177e4SLinus Torvalds 			goto out;
26311da177e4SLinus Torvalds 
26321da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
26331da177e4SLinus Torvalds 
2634aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE];
26351da177e4SLinus Torvalds 		while (c) {
26361da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
26371da177e4SLinus Torvalds 				break;
26381da177e4SLinus Torvalds 			c = c->next;
26391da177e4SLinus Torvalds 		}
26401da177e4SLinus Torvalds 		break;
26411da177e4SLinus Torvalds 	}
26421da177e4SLinus Torvalds 
26431da177e4SLinus Torvalds 	case AF_INET6:
26441da177e4SLinus Torvalds 		rc = -EINVAL;
26454b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
26461da177e4SLinus Torvalds 			goto out;
2647aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE6];
26481da177e4SLinus Torvalds 		while (c) {
26491da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
26501da177e4SLinus Torvalds 						c->u.node6.mask))
26511da177e4SLinus Torvalds 				break;
26521da177e4SLinus Torvalds 			c = c->next;
26531da177e4SLinus Torvalds 		}
26541da177e4SLinus Torvalds 		break;
26551da177e4SLinus Torvalds 
26561da177e4SLinus Torvalds 	default:
26574b02b524SEric Paris 		rc = 0;
26581da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
26591da177e4SLinus Torvalds 		goto out;
26601da177e4SLinus Torvalds 	}
26611da177e4SLinus Torvalds 
26621da177e4SLinus Torvalds 	if (c) {
2663cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
26649ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
26659ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
26669ad6e9cbSOndrej Mosnacek 			goto retry;
26679ad6e9cbSOndrej Mosnacek 		}
26681da177e4SLinus Torvalds 		if (rc)
26691da177e4SLinus Torvalds 			goto out;
26701da177e4SLinus Torvalds 	} else {
26711da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
26721da177e4SLinus Torvalds 	}
26731da177e4SLinus Torvalds 
26744b02b524SEric Paris 	rc = 0;
26751da177e4SLinus Torvalds out:
26761b8b31a2SStephen Smalley 	rcu_read_unlock();
26771da177e4SLinus Torvalds 	return rc;
26781da177e4SLinus Torvalds }
26791da177e4SLinus Torvalds 
26801da177e4SLinus Torvalds #define SIDS_NEL 25
26811da177e4SLinus Torvalds 
26821da177e4SLinus Torvalds /**
26831da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
26841da177e4SLinus Torvalds  * @fromsid: starting SID
26851da177e4SLinus Torvalds  * @username: username
26861da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
26871da177e4SLinus Torvalds  * @nel: number of elements in @sids
26881da177e4SLinus Torvalds  *
26891da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
26901da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
26911da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
26921da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
26931da177e4SLinus Torvalds  * number of elements in the array.
26941da177e4SLinus Torvalds  */
26951da177e4SLinus Torvalds 
security_get_user_sids(u32 fromsid,char * username,u32 ** sids,u32 * nel)2696e67b7985SStephen Smalley int security_get_user_sids(u32 fromsid,
26971da177e4SLinus Torvalds 			   char *username,
26981da177e4SLinus Torvalds 			   u32 **sids,
26991da177e4SLinus Torvalds 			   u32 *nel)
27001da177e4SLinus Torvalds {
27011b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2702aa8e712cSStephen Smalley 	struct policydb *policydb;
2703aa8e712cSStephen Smalley 	struct sidtab *sidtab;
27041da177e4SLinus Torvalds 	struct context *fromcon, usercon;
27052c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
27069ad6e9cbSOndrej Mosnacek 	u32 i, j, mynel, maxnel = SIDS_NEL;
27071da177e4SLinus Torvalds 	struct user_datum *user;
27081da177e4SLinus Torvalds 	struct role_datum *role;
2709782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
27109ad6e9cbSOndrej Mosnacek 	int rc;
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds 	*sids = NULL;
27131da177e4SLinus Torvalds 	*nel = 0;
27142c3c05dbSStephen Smalley 
2715e67b7985SStephen Smalley 	if (!selinux_initialized())
27169ad6e9cbSOndrej Mosnacek 		return 0;
27171da177e4SLinus Torvalds 
27189ad6e9cbSOndrej Mosnacek 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
27199ad6e9cbSOndrej Mosnacek 	if (!mysids)
27209ad6e9cbSOndrej Mosnacek 		return -ENOMEM;
27219ad6e9cbSOndrej Mosnacek 
27229ad6e9cbSOndrej Mosnacek retry:
27239ad6e9cbSOndrej Mosnacek 	mynel = 0;
27241b8b31a2SStephen Smalley 	rcu_read_lock();
2725e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
27261b8b31a2SStephen Smalley 	policydb = &policy->policydb;
27271b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
27281da177e4SLinus Torvalds 
272912b29f34SStephen Smalley 	context_init(&usercon);
273012b29f34SStephen Smalley 
27314b02b524SEric Paris 	rc = -EINVAL;
2732aa8e712cSStephen Smalley 	fromcon = sidtab_search(sidtab, fromsid);
27334b02b524SEric Paris 	if (!fromcon)
27341da177e4SLinus Torvalds 		goto out_unlock;
27351da177e4SLinus Torvalds 
27361da177e4SLinus Torvalds 	rc = -EINVAL;
2737237389e3SOndrej Mosnacek 	user = symtab_search(&policydb->p_users, username);
27384b02b524SEric Paris 	if (!user)
27391da177e4SLinus Torvalds 		goto out_unlock;
27404b02b524SEric Paris 
27411da177e4SLinus Torvalds 	usercon.user = user->value;
27421da177e4SLinus Torvalds 
27439fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2744aa8e712cSStephen Smalley 		role = policydb->role_val_to_struct[i];
27451da177e4SLinus Torvalds 		usercon.role = i + 1;
27469fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
27471da177e4SLinus Torvalds 			usercon.type = j + 1;
27481da177e4SLinus Torvalds 
2749aa8e712cSStephen Smalley 			if (mls_setup_user_range(policydb, fromcon, user,
2750aa8e712cSStephen Smalley 						 &usercon))
27511da177e4SLinus Torvalds 				continue;
27521da177e4SLinus Torvalds 
2753225621c9SOndrej Mosnacek 			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
27549ad6e9cbSOndrej Mosnacek 			if (rc == -ESTALE) {
27559ad6e9cbSOndrej Mosnacek 				rcu_read_unlock();
27569ad6e9cbSOndrej Mosnacek 				goto retry;
27579ad6e9cbSOndrej Mosnacek 			}
27582c3c05dbSStephen Smalley 			if (rc)
27591da177e4SLinus Torvalds 				goto out_unlock;
27601da177e4SLinus Torvalds 			if (mynel < maxnel) {
27611da177e4SLinus Torvalds 				mysids[mynel++] = sid;
27621da177e4SLinus Torvalds 			} else {
27634b02b524SEric Paris 				rc = -ENOMEM;
27641da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
276589d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
27664b02b524SEric Paris 				if (!mysids2)
27671da177e4SLinus Torvalds 					goto out_unlock;
27681da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
27691da177e4SLinus Torvalds 				kfree(mysids);
27701da177e4SLinus Torvalds 				mysids = mysids2;
27711da177e4SLinus Torvalds 				mysids[mynel++] = sid;
27721da177e4SLinus Torvalds 			}
27731da177e4SLinus Torvalds 		}
27741da177e4SLinus Torvalds 	}
27754b02b524SEric Paris 	rc = 0;
27761da177e4SLinus Torvalds out_unlock:
27771b8b31a2SStephen Smalley 	rcu_read_unlock();
27782c3c05dbSStephen Smalley 	if (rc || !mynel) {
27792c3c05dbSStephen Smalley 		kfree(mysids);
27809ad6e9cbSOndrej Mosnacek 		return rc;
27812c3c05dbSStephen Smalley 	}
27822c3c05dbSStephen Smalley 
27834b02b524SEric Paris 	rc = -ENOMEM;
27842c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
27852c3c05dbSStephen Smalley 	if (!mysids2) {
27862c3c05dbSStephen Smalley 		kfree(mysids);
27879ad6e9cbSOndrej Mosnacek 		return rc;
27882c3c05dbSStephen Smalley 	}
27892c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
2790f01e1af4SLinus Torvalds 		struct av_decision dummy_avd;
2791e67b7985SStephen Smalley 		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2792c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
27932c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
2794f01e1af4SLinus Torvalds 					  &dummy_avd);
27952c3c05dbSStephen Smalley 		if (!rc)
27962c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
27972c3c05dbSStephen Smalley 		cond_resched();
27982c3c05dbSStephen Smalley 	}
27992c3c05dbSStephen Smalley 	kfree(mysids);
28002c3c05dbSStephen Smalley 	*sids = mysids2;
28012c3c05dbSStephen Smalley 	*nel = j;
28029ad6e9cbSOndrej Mosnacek 	return 0;
28031da177e4SLinus Torvalds }
28041da177e4SLinus Torvalds 
28051da177e4SLinus Torvalds /**
2806f31e7994SWaiman Long  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
2807e9fd7292SPaul Moore  * @policy: policy
28081da177e4SLinus Torvalds  * @fstype: filesystem type
28091da177e4SLinus Torvalds  * @path: path from root of mount
2810e9fd7292SPaul Moore  * @orig_sclass: file security class
28111da177e4SLinus Torvalds  * @sid: SID for path
28121da177e4SLinus Torvalds  *
28131da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
28141da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
28151da177e4SLinus Torvalds  * transition SIDs or task SIDs.
28169ad6e9cbSOndrej Mosnacek  *
28179ad6e9cbSOndrej Mosnacek  * WARNING: This function may return -ESTALE, indicating that the caller
28189ad6e9cbSOndrej Mosnacek  * must retry the operation after re-acquiring the policy pointer!
28191da177e4SLinus Torvalds  */
__security_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)282002a52c5cSStephen Smalley static inline int __security_genfs_sid(struct selinux_policy *policy,
2821aa8e712cSStephen Smalley 				       const char *fstype,
282208df4905SChristian Göttsche 				       const char *path,
2823c6d3aaa4SStephen Smalley 				       u16 orig_sclass,
28241da177e4SLinus Torvalds 				       u32 *sid)
28251da177e4SLinus Torvalds {
282602a52c5cSStephen Smalley 	struct policydb *policydb = &policy->policydb;
2827c7c556f1SStephen Smalley 	struct sidtab *sidtab = policy->sidtab;
2828c6d3aaa4SStephen Smalley 	u16 sclass;
28291da177e4SLinus Torvalds 	struct genfs *genfs;
28301da177e4SLinus Torvalds 	struct ocontext *c;
2831cbfcd13bSOndrej Mosnacek 	int cmp = 0;
28321da177e4SLinus Torvalds 
2833b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2834b1aa5301SStephen Smalley 		path++;
2835b1aa5301SStephen Smalley 
283602a52c5cSStephen Smalley 	sclass = unmap_class(&policy->map, orig_sclass);
28374b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2838c6d3aaa4SStephen Smalley 
2839aa8e712cSStephen Smalley 	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
28401da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
28411da177e4SLinus Torvalds 		if (cmp <= 0)
28421da177e4SLinus Torvalds 			break;
28431da177e4SLinus Torvalds 	}
28441da177e4SLinus Torvalds 
28454b02b524SEric Paris 	if (!genfs || cmp)
2846cbfcd13bSOndrej Mosnacek 		return -ENOENT;
28471da177e4SLinus Torvalds 
28481da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
2849c50e125dSChristian Göttsche 		size_t len = strlen(c->u.name);
28501da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
28511da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
28521da177e4SLinus Torvalds 			break;
28531da177e4SLinus Torvalds 	}
28541da177e4SLinus Torvalds 
28554b02b524SEric Paris 	if (!c)
2856cbfcd13bSOndrej Mosnacek 		return -ENOENT;
28571da177e4SLinus Torvalds 
2858cbfcd13bSOndrej Mosnacek 	return ocontext_to_sid(sidtab, c, 0, sid);
28591da177e4SLinus Torvalds }
28601da177e4SLinus Torvalds 
28611da177e4SLinus Torvalds /**
2862f31e7994SWaiman Long  * security_genfs_sid - Obtain a SID for a file in a filesystem
2863f31e7994SWaiman Long  * @fstype: filesystem type
2864f31e7994SWaiman Long  * @path: path from root of mount
2865e9fd7292SPaul Moore  * @orig_sclass: file security class
2866f31e7994SWaiman Long  * @sid: SID for path
2867f31e7994SWaiman Long  *
2868f31e7994SWaiman Long  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2869f31e7994SWaiman Long  * it afterward.
2870f31e7994SWaiman Long  */
security_genfs_sid(const char * fstype,const char * path,u16 orig_sclass,u32 * sid)2871e67b7985SStephen Smalley int security_genfs_sid(const char *fstype,
287208df4905SChristian Göttsche 		       const char *path,
2873f31e7994SWaiman Long 		       u16 orig_sclass,
2874f31e7994SWaiman Long 		       u32 *sid)
2875f31e7994SWaiman Long {
28761b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2877f31e7994SWaiman Long 	int retval;
2878f31e7994SWaiman Long 
2879e67b7985SStephen Smalley 	if (!selinux_initialized()) {
288037ea433cSStephen Smalley 		*sid = SECINITSID_UNLABELED;
288137ea433cSStephen Smalley 		return 0;
288237ea433cSStephen Smalley 	}
288337ea433cSStephen Smalley 
28849ad6e9cbSOndrej Mosnacek 	do {
28851b8b31a2SStephen Smalley 		rcu_read_lock();
2886e67b7985SStephen Smalley 		policy = rcu_dereference(selinux_state.policy);
28879ad6e9cbSOndrej Mosnacek 		retval = __security_genfs_sid(policy, fstype, path,
28889ad6e9cbSOndrej Mosnacek 					      orig_sclass, sid);
28891b8b31a2SStephen Smalley 		rcu_read_unlock();
28909ad6e9cbSOndrej Mosnacek 	} while (retval == -ESTALE);
2891f31e7994SWaiman Long 	return retval;
2892f31e7994SWaiman Long }
2893f31e7994SWaiman Long 
selinux_policy_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)289402a52c5cSStephen Smalley int selinux_policy_genfs_sid(struct selinux_policy *policy,
289502a52c5cSStephen Smalley 			const char *fstype,
289608df4905SChristian Göttsche 			const char *path,
289702a52c5cSStephen Smalley 			u16 orig_sclass,
289802a52c5cSStephen Smalley 			u32 *sid)
289902a52c5cSStephen Smalley {
290002a52c5cSStephen Smalley 	/* no lock required, policy is not yet accessible by other threads */
290102a52c5cSStephen Smalley 	return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
290202a52c5cSStephen Smalley }
290302a52c5cSStephen Smalley 
2904f31e7994SWaiman Long /**
29051da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
2906a64c54cfSEric Paris  * @sb: superblock in question
29071da177e4SLinus Torvalds  */
security_fs_use(struct super_block * sb)2908e67b7985SStephen Smalley int security_fs_use(struct super_block *sb)
29091da177e4SLinus Torvalds {
29101b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2911aa8e712cSStephen Smalley 	struct policydb *policydb;
2912225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
29139ad6e9cbSOndrej Mosnacek 	int rc;
29141da177e4SLinus Torvalds 	struct ocontext *c;
29151aea7808SCasey Schaufler 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
2916a64c54cfSEric Paris 	const char *fstype = sb->s_type->name;
29171da177e4SLinus Torvalds 
2918e67b7985SStephen Smalley 	if (!selinux_initialized()) {
291937ea433cSStephen Smalley 		sbsec->behavior = SECURITY_FS_USE_NONE;
292037ea433cSStephen Smalley 		sbsec->sid = SECINITSID_UNLABELED;
292137ea433cSStephen Smalley 		return 0;
292237ea433cSStephen Smalley 	}
292337ea433cSStephen Smalley 
29249ad6e9cbSOndrej Mosnacek retry:
29251b8b31a2SStephen Smalley 	rcu_read_lock();
2926e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
29271b8b31a2SStephen Smalley 	policydb = &policy->policydb;
29281b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2929aa8e712cSStephen Smalley 
2930aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_FSUSE];
29314d546f81SPaul Moore 	while (c) {
29324d546f81SPaul Moore 		if (strcmp(fstype, c->u.name) == 0)
29331da177e4SLinus Torvalds 			break;
29344d546f81SPaul Moore 		c = c->next;
29351da177e4SLinus Torvalds 	}
29361da177e4SLinus Torvalds 
29371da177e4SLinus Torvalds 	if (c) {
2938a64c54cfSEric Paris 		sbsec->behavior = c->v.behavior;
2939cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
29409ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
29419ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
29429ad6e9cbSOndrej Mosnacek 			goto retry;
29439ad6e9cbSOndrej Mosnacek 		}
29441da177e4SLinus Torvalds 		if (rc)
29451da177e4SLinus Torvalds 			goto out;
2946089be43eSJames Morris 	} else {
29471b8b31a2SStephen Smalley 		rc = __security_genfs_sid(policy, fstype, "/",
294802a52c5cSStephen Smalley 					SECCLASS_DIR, &sbsec->sid);
29499ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
29509ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
29519ad6e9cbSOndrej Mosnacek 			goto retry;
29529ad6e9cbSOndrej Mosnacek 		}
29531da177e4SLinus Torvalds 		if (rc) {
2954a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_NONE;
29551da177e4SLinus Torvalds 			rc = 0;
29561da177e4SLinus Torvalds 		} else {
2957a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_GENFS;
29581da177e4SLinus Torvalds 		}
2959089be43eSJames Morris 	}
29601da177e4SLinus Torvalds 
29611da177e4SLinus Torvalds out:
29621b8b31a2SStephen Smalley 	rcu_read_unlock();
29631da177e4SLinus Torvalds 	return rc;
29641da177e4SLinus Torvalds }
29651da177e4SLinus Torvalds 
security_get_bools(struct selinux_policy * policy,u32 * len,char *** names,int ** values)296602a52c5cSStephen Smalley int security_get_bools(struct selinux_policy *policy,
296760abd318SOndrej Mosnacek 		       u32 *len, char ***names, int **values)
29681da177e4SLinus Torvalds {
2969aa8e712cSStephen Smalley 	struct policydb *policydb;
297060abd318SOndrej Mosnacek 	u32 i;
297160abd318SOndrej Mosnacek 	int rc;
29721da177e4SLinus Torvalds 
297302a52c5cSStephen Smalley 	policydb = &policy->policydb;
2974aa8e712cSStephen Smalley 
29751da177e4SLinus Torvalds 	*names = NULL;
29761da177e4SLinus Torvalds 	*values = NULL;
29771da177e4SLinus Torvalds 
29781da177e4SLinus Torvalds 	rc = 0;
2979aa8e712cSStephen Smalley 	*len = policydb->p_bools.nprim;
29804b02b524SEric Paris 	if (!*len)
29811da177e4SLinus Torvalds 		goto out;
29821da177e4SLinus Torvalds 
29834b02b524SEric Paris 	rc = -ENOMEM;
2984e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
29851da177e4SLinus Torvalds 	if (!*names)
29861da177e4SLinus Torvalds 		goto err;
29871da177e4SLinus Torvalds 
29884b02b524SEric Paris 	rc = -ENOMEM;
2989e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
29901da177e4SLinus Torvalds 	if (!*values)
29911da177e4SLinus Torvalds 		goto err;
29921da177e4SLinus Torvalds 
29931da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
2994aa8e712cSStephen Smalley 		(*values)[i] = policydb->bool_val_to_struct[i]->state;
29954b02b524SEric Paris 
29964b02b524SEric Paris 		rc = -ENOMEM;
2997aa8e712cSStephen Smalley 		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
2998aa8e712cSStephen Smalley 				      GFP_ATOMIC);
29991da177e4SLinus Torvalds 		if (!(*names)[i])
30001da177e4SLinus Torvalds 			goto err;
30011da177e4SLinus Torvalds 	}
30021da177e4SLinus Torvalds 	rc = 0;
30031da177e4SLinus Torvalds out:
30041da177e4SLinus Torvalds 	return rc;
30051da177e4SLinus Torvalds err:
30061da177e4SLinus Torvalds 	if (*names) {
30071da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
30081da177e4SLinus Torvalds 			kfree((*names)[i]);
300965de5096STom Rix 		kfree(*names);
30101da177e4SLinus Torvalds 	}
30111da177e4SLinus Torvalds 	kfree(*values);
301265de5096STom Rix 	*len = 0;
301365de5096STom Rix 	*names = NULL;
301465de5096STom Rix 	*values = NULL;
30151da177e4SLinus Torvalds 	goto out;
30161da177e4SLinus Torvalds }
30171da177e4SLinus Torvalds 
30181da177e4SLinus Torvalds 
security_set_bools(u32 len,int * values)3019e67b7985SStephen Smalley int security_set_bools(u32 len, int *values)
30201da177e4SLinus Torvalds {
3021e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
3022c7c556f1SStephen Smalley 	struct selinux_policy *newpolicy, *oldpolicy;
302360abd318SOndrej Mosnacek 	int rc;
3024c7c556f1SStephen Smalley 	u32 i, seqno = 0;
30251da177e4SLinus Torvalds 
3026e67b7985SStephen Smalley 	if (!selinux_initialized())
302737ea433cSStephen Smalley 		return -EINVAL;
302837ea433cSStephen Smalley 
30299ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
30309ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
30311b8b31a2SStephen Smalley 
3032c7c556f1SStephen Smalley 	/* Consistency check on number of booleans, should never fail */
30331b8b31a2SStephen Smalley 	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
3034c7c556f1SStephen Smalley 		return -EINVAL;
30351da177e4SLinus Torvalds 
30361b8b31a2SStephen Smalley 	newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
3037c7c556f1SStephen Smalley 	if (!newpolicy)
3038c7c556f1SStephen Smalley 		return -ENOMEM;
30391da177e4SLinus Torvalds 
3040c7c556f1SStephen Smalley 	/*
3041c7c556f1SStephen Smalley 	 * Deep copy only the parts of the policydb that might be
3042c7c556f1SStephen Smalley 	 * modified as a result of changing booleans.
3043c7c556f1SStephen Smalley 	 */
3044c7c556f1SStephen Smalley 	rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
3045c7c556f1SStephen Smalley 	if (rc) {
3046c7c556f1SStephen Smalley 		kfree(newpolicy);
3047c7c556f1SStephen Smalley 		return -ENOMEM;
3048c7c556f1SStephen Smalley 	}
3049c7c556f1SStephen Smalley 
3050c7c556f1SStephen Smalley 	/* Update the boolean states in the copy */
30511da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
3052c7c556f1SStephen Smalley 		int new_state = !!values[i];
3053c7c556f1SStephen Smalley 		int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
3054c7c556f1SStephen Smalley 
3055c7c556f1SStephen Smalley 		if (new_state != old_state) {
3056cdfb6b34SRichard Guy Briggs 			audit_log(audit_context(), GFP_ATOMIC,
3057af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
30584746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
3059c7c556f1SStephen Smalley 				sym_name(&newpolicy->policydb, SYM_BOOLS, i),
3060c7c556f1SStephen Smalley 				new_state,
3061c7c556f1SStephen Smalley 				old_state,
3062581abc09SEric W. Biederman 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
30634746ec5bSEric Paris 				audit_get_sessionid(current));
3064c7c556f1SStephen Smalley 			newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
3065af601e46SSteve Grubb 		}
30661da177e4SLinus Torvalds 	}
30671da177e4SLinus Torvalds 
3068c7c556f1SStephen Smalley 	/* Re-evaluate the conditional rules in the copy */
3069c7c556f1SStephen Smalley 	evaluate_cond_nodes(&newpolicy->policydb);
30701da177e4SLinus Torvalds 
30711b8b31a2SStephen Smalley 	/* Set latest granting seqno for new policy */
30721b8b31a2SStephen Smalley 	newpolicy->latest_granting = oldpolicy->latest_granting + 1;
30731b8b31a2SStephen Smalley 	seqno = newpolicy->latest_granting;
30741b8b31a2SStephen Smalley 
3075c7c556f1SStephen Smalley 	/* Install the new policy */
30761b8b31a2SStephen Smalley 	rcu_assign_pointer(state->policy, newpolicy);
3077c7c556f1SStephen Smalley 
3078c7c556f1SStephen Smalley 	/*
3079c7c556f1SStephen Smalley 	 * Free the conditional portions of the old policydb
30801b8b31a2SStephen Smalley 	 * that were copied for the new policy, and the oldpolicy
30811b8b31a2SStephen Smalley 	 * structure itself but not what it references.
3082c7c556f1SStephen Smalley 	 */
30831b8b31a2SStephen Smalley 	synchronize_rcu();
30841b8b31a2SStephen Smalley 	selinux_policy_cond_free(oldpolicy);
3085c7c556f1SStephen Smalley 
3086c7c556f1SStephen Smalley 	/* Notify others of the policy change */
3087e67b7985SStephen Smalley 	selinux_notify_policy_change(seqno);
3088c7c556f1SStephen Smalley 	return 0;
30891da177e4SLinus Torvalds }
30901da177e4SLinus Torvalds 
security_get_bool_value(u32 index)3091e67b7985SStephen Smalley int security_get_bool_value(u32 index)
30921da177e4SLinus Torvalds {
30931b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3094aa8e712cSStephen Smalley 	struct policydb *policydb;
30954b02b524SEric Paris 	int rc;
309660abd318SOndrej Mosnacek 	u32 len;
30971da177e4SLinus Torvalds 
3098e67b7985SStephen Smalley 	if (!selinux_initialized())
309937ea433cSStephen Smalley 		return 0;
310037ea433cSStephen Smalley 
31011b8b31a2SStephen Smalley 	rcu_read_lock();
3102e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
31031b8b31a2SStephen Smalley 	policydb = &policy->policydb;
31041da177e4SLinus Torvalds 
31051da177e4SLinus Torvalds 	rc = -EFAULT;
3106aa8e712cSStephen Smalley 	len = policydb->p_bools.nprim;
31070fd71a62SPrarit Bhargava 	if (index >= len)
31081da177e4SLinus Torvalds 		goto out;
31091da177e4SLinus Torvalds 
3110aa8e712cSStephen Smalley 	rc = policydb->bool_val_to_struct[index]->state;
31111da177e4SLinus Torvalds out:
31121b8b31a2SStephen Smalley 	rcu_read_unlock();
31131da177e4SLinus Torvalds 	return rc;
31141da177e4SLinus Torvalds }
3115376bd9cbSDarrel Goeddel 
security_preserve_bools(struct selinux_policy * oldpolicy,struct selinux_policy * newpolicy)31161b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
31171b8b31a2SStephen Smalley 				struct selinux_policy *newpolicy)
3118e900a7d9SStephen Smalley {
311960abd318SOndrej Mosnacek 	int rc, *bvalues = NULL;
3120e900a7d9SStephen Smalley 	char **bnames = NULL;
3121e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
312260abd318SOndrej Mosnacek 	u32 i, nbools = 0;
3123e900a7d9SStephen Smalley 
31241b8b31a2SStephen Smalley 	rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
3125e900a7d9SStephen Smalley 	if (rc)
3126e900a7d9SStephen Smalley 		goto out;
3127e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
31281b8b31a2SStephen Smalley 		booldatum = symtab_search(&newpolicy->policydb.p_bools,
31291b8b31a2SStephen Smalley 					bnames[i]);
3130e900a7d9SStephen Smalley 		if (booldatum)
3131e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
3132e900a7d9SStephen Smalley 	}
31331b8b31a2SStephen Smalley 	evaluate_cond_nodes(&newpolicy->policydb);
3134e900a7d9SStephen Smalley 
3135e900a7d9SStephen Smalley out:
3136e900a7d9SStephen Smalley 	if (bnames) {
3137e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
3138e900a7d9SStephen Smalley 			kfree(bnames[i]);
3139e900a7d9SStephen Smalley 	}
3140e900a7d9SStephen Smalley 	kfree(bnames);
3141e900a7d9SStephen Smalley 	kfree(bvalues);
3142e900a7d9SStephen Smalley 	return rc;
3143e900a7d9SStephen Smalley }
3144e900a7d9SStephen Smalley 
314508554d6bSVenkat Yekkirala /*
314608554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
314708554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
314808554d6bSVenkat Yekkirala  */
security_sid_mls_copy(u32 sid,u32 mls_sid,u32 * new_sid)3149e67b7985SStephen Smalley int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
315008554d6bSVenkat Yekkirala {
31511b8b31a2SStephen Smalley 	struct selinux_policy *policy;
315246169802SStephen Smalley 	struct policydb *policydb;
315346169802SStephen Smalley 	struct sidtab *sidtab;
315408554d6bSVenkat Yekkirala 	struct context *context1;
315508554d6bSVenkat Yekkirala 	struct context *context2;
315608554d6bSVenkat Yekkirala 	struct context newcon;
315708554d6bSVenkat Yekkirala 	char *s;
315808554d6bSVenkat Yekkirala 	u32 len;
31594b02b524SEric Paris 	int rc;
316008554d6bSVenkat Yekkirala 
3161e67b7985SStephen Smalley 	if (!selinux_initialized()) {
316208554d6bSVenkat Yekkirala 		*new_sid = sid;
31639ad6e9cbSOndrej Mosnacek 		return 0;
316408554d6bSVenkat Yekkirala 	}
316508554d6bSVenkat Yekkirala 
31669ad6e9cbSOndrej Mosnacek retry:
31679ad6e9cbSOndrej Mosnacek 	rc = 0;
316808554d6bSVenkat Yekkirala 	context_init(&newcon);
316908554d6bSVenkat Yekkirala 
31701b8b31a2SStephen Smalley 	rcu_read_lock();
3171e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
31721b8b31a2SStephen Smalley 	policydb = &policy->policydb;
31731b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
317446169802SStephen Smalley 
317546169802SStephen Smalley 	if (!policydb->mls_enabled) {
317646169802SStephen Smalley 		*new_sid = sid;
317746169802SStephen Smalley 		goto out_unlock;
317846169802SStephen Smalley 	}
317946169802SStephen Smalley 
31804b02b524SEric Paris 	rc = -EINVAL;
3181aa8e712cSStephen Smalley 	context1 = sidtab_search(sidtab, sid);
318208554d6bSVenkat Yekkirala 	if (!context1) {
3183b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3184744ba35eSEric Paris 			__func__, sid);
318508554d6bSVenkat Yekkirala 		goto out_unlock;
318608554d6bSVenkat Yekkirala 	}
318708554d6bSVenkat Yekkirala 
31884b02b524SEric Paris 	rc = -EINVAL;
3189aa8e712cSStephen Smalley 	context2 = sidtab_search(sidtab, mls_sid);
319008554d6bSVenkat Yekkirala 	if (!context2) {
3191b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3192744ba35eSEric Paris 			__func__, mls_sid);
319308554d6bSVenkat Yekkirala 		goto out_unlock;
319408554d6bSVenkat Yekkirala 	}
319508554d6bSVenkat Yekkirala 
319608554d6bSVenkat Yekkirala 	newcon.user = context1->user;
319708554d6bSVenkat Yekkirala 	newcon.role = context1->role;
319808554d6bSVenkat Yekkirala 	newcon.type = context1->type;
31990efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
320008554d6bSVenkat Yekkirala 	if (rc)
320108554d6bSVenkat Yekkirala 		goto out_unlock;
320208554d6bSVenkat Yekkirala 
320308554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
3204aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcon)) {
3205e67b7985SStephen Smalley 		rc = convert_context_handle_invalid_context(policydb,
32061b8b31a2SStephen Smalley 							&newcon);
32074b02b524SEric Paris 		if (rc) {
3208aa8e712cSStephen Smalley 			if (!context_struct_to_string(policydb, &newcon, &s,
3209aa8e712cSStephen Smalley 						      &len)) {
3210ea74a685SRichard Guy Briggs 				struct audit_buffer *ab;
3211ea74a685SRichard Guy Briggs 
3212ea74a685SRichard Guy Briggs 				ab = audit_log_start(audit_context(),
3213ea74a685SRichard Guy Briggs 						     GFP_ATOMIC,
3214ea74a685SRichard Guy Briggs 						     AUDIT_SELINUX_ERR);
3215ea74a685SRichard Guy Briggs 				audit_log_format(ab,
3216ea74a685SRichard Guy Briggs 						 "op=security_sid_mls_copy invalid_context=");
3217ea74a685SRichard Guy Briggs 				/* don't record NUL with untrusted strings */
3218ea74a685SRichard Guy Briggs 				audit_log_n_untrustedstring(ab, s, len - 1);
3219ea74a685SRichard Guy Briggs 				audit_log_end(ab);
322008554d6bSVenkat Yekkirala 				kfree(s);
322108554d6bSVenkat Yekkirala 			}
32224b02b524SEric Paris 			goto out_unlock;
32234b02b524SEric Paris 		}
32244b02b524SEric Paris 	}
3225225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
32269ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
32279ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
32289ad6e9cbSOndrej Mosnacek 		context_destroy(&newcon);
32299ad6e9cbSOndrej Mosnacek 		goto retry;
32309ad6e9cbSOndrej Mosnacek 	}
323108554d6bSVenkat Yekkirala out_unlock:
32321b8b31a2SStephen Smalley 	rcu_read_unlock();
323308554d6bSVenkat Yekkirala 	context_destroy(&newcon);
323408554d6bSVenkat Yekkirala 	return rc;
323508554d6bSVenkat Yekkirala }
323608554d6bSVenkat Yekkirala 
3237220deb96SPaul Moore /**
3238220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3239220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
3240220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
3241220deb96SPaul Moore  * @xfrm_sid: XFRM SID
3242e9fd7292SPaul Moore  * @peer_sid: network peer sid
3243220deb96SPaul Moore  *
3244220deb96SPaul Moore  * Description:
3245220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3246220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
3247220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
3248220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
3249220deb96SPaul Moore  *
3250220deb96SPaul Moore  *                                 | function return |      @sid
3251220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
3252220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
3253220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
3254220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
3255220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
3256220deb96SPaul Moore  *
3257220deb96SPaul Moore  */
security_net_peersid_resolve(u32 nlbl_sid,u32 nlbl_type,u32 xfrm_sid,u32 * peer_sid)3258e67b7985SStephen Smalley int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
3259220deb96SPaul Moore 				 u32 xfrm_sid,
3260220deb96SPaul Moore 				 u32 *peer_sid)
3261220deb96SPaul Moore {
32621b8b31a2SStephen Smalley 	struct selinux_policy *policy;
326346169802SStephen Smalley 	struct policydb *policydb;
326446169802SStephen Smalley 	struct sidtab *sidtab;
3265220deb96SPaul Moore 	int rc;
3266220deb96SPaul Moore 	struct context *nlbl_ctx;
3267220deb96SPaul Moore 	struct context *xfrm_ctx;
3268220deb96SPaul Moore 
32694b02b524SEric Paris 	*peer_sid = SECSID_NULL;
32704b02b524SEric Paris 
3271220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
3272220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
3273220deb96SPaul Moore 	 * single or absent peer SID/label */
3274220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
3275220deb96SPaul Moore 		*peer_sid = nlbl_sid;
3276220deb96SPaul Moore 		return 0;
3277220deb96SPaul Moore 	}
3278220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3279220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3280220deb96SPaul Moore 	 * is present */
3281220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3282220deb96SPaul Moore 		*peer_sid = xfrm_sid;
3283220deb96SPaul Moore 		return 0;
3284220deb96SPaul Moore 	}
3285220deb96SPaul Moore 
3286e67b7985SStephen Smalley 	if (!selinux_initialized())
328737ea433cSStephen Smalley 		return 0;
328837ea433cSStephen Smalley 
32891b8b31a2SStephen Smalley 	rcu_read_lock();
3290e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
32911b8b31a2SStephen Smalley 	policydb = &policy->policydb;
32921b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
329346169802SStephen Smalley 
3294aa8e712cSStephen Smalley 	/*
3295aa8e712cSStephen Smalley 	 * We don't need to check initialized here since the only way both
3296220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3297aa8e712cSStephen Smalley 	 * security server was initialized and state->initialized was true.
3298aa8e712cSStephen Smalley 	 */
329946169802SStephen Smalley 	if (!policydb->mls_enabled) {
330046169802SStephen Smalley 		rc = 0;
330146169802SStephen Smalley 		goto out;
330246169802SStephen Smalley 	}
3303220deb96SPaul Moore 
33044b02b524SEric Paris 	rc = -EINVAL;
3305aa8e712cSStephen Smalley 	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3306220deb96SPaul Moore 	if (!nlbl_ctx) {
3307b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3308744ba35eSEric Paris 		       __func__, nlbl_sid);
33094b02b524SEric Paris 		goto out;
3310220deb96SPaul Moore 	}
33114b02b524SEric Paris 	rc = -EINVAL;
3312aa8e712cSStephen Smalley 	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3313220deb96SPaul Moore 	if (!xfrm_ctx) {
3314b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3315744ba35eSEric Paris 		       __func__, xfrm_sid);
33164b02b524SEric Paris 		goto out;
3317220deb96SPaul Moore 	}
3318220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
33194b02b524SEric Paris 	if (rc)
33204b02b524SEric Paris 		goto out;
3321220deb96SPaul Moore 
3322220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
3323220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
3324220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
3325220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
3326220deb96SPaul Moore 	 * expressive */
3327220deb96SPaul Moore 	*peer_sid = xfrm_sid;
33284b02b524SEric Paris out:
33291b8b31a2SStephen Smalley 	rcu_read_unlock();
3330220deb96SPaul Moore 	return rc;
3331220deb96SPaul Moore }
3332220deb96SPaul Moore 
get_classes_callback(void * k,void * d,void * args)333355fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
333455fcf09bSChristopher J. PeBenito {
333555fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
333655fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
3337c50e125dSChristian Göttsche 	u32 value = datum->value - 1;
333855fcf09bSChristopher J. PeBenito 
333955fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
334055fcf09bSChristopher J. PeBenito 	if (!classes[value])
334155fcf09bSChristopher J. PeBenito 		return -ENOMEM;
334255fcf09bSChristopher J. PeBenito 
334355fcf09bSChristopher J. PeBenito 	return 0;
334455fcf09bSChristopher J. PeBenito }
334555fcf09bSChristopher J. PeBenito 
security_get_classes(struct selinux_policy * policy,char *** classes,u32 * nclasses)334602a52c5cSStephen Smalley int security_get_classes(struct selinux_policy *policy,
3347c50e125dSChristian Göttsche 			 char ***classes, u32 *nclasses)
334855fcf09bSChristopher J. PeBenito {
334946169802SStephen Smalley 	struct policydb *policydb;
33504b02b524SEric Paris 	int rc;
335155fcf09bSChristopher J. PeBenito 
335202a52c5cSStephen Smalley 	policydb = &policy->policydb;
335346169802SStephen Smalley 
33544b02b524SEric Paris 	rc = -ENOMEM;
3355aa8e712cSStephen Smalley 	*nclasses = policydb->p_classes.nprim;
33569f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
335755fcf09bSChristopher J. PeBenito 	if (!*classes)
335855fcf09bSChristopher J. PeBenito 		goto out;
335955fcf09bSChristopher J. PeBenito 
336003414a49SOndrej Mosnacek 	rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
336155fcf09bSChristopher J. PeBenito 			 *classes);
33624b02b524SEric Paris 	if (rc) {
3363c50e125dSChristian Göttsche 		u32 i;
3364c50e125dSChristian Göttsche 
336555fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
336655fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
336755fcf09bSChristopher J. PeBenito 		kfree(*classes);
336855fcf09bSChristopher J. PeBenito 	}
336955fcf09bSChristopher J. PeBenito 
337055fcf09bSChristopher J. PeBenito out:
337155fcf09bSChristopher J. PeBenito 	return rc;
337255fcf09bSChristopher J. PeBenito }
337355fcf09bSChristopher J. PeBenito 
get_permissions_callback(void * k,void * d,void * args)337455fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
337555fcf09bSChristopher J. PeBenito {
337655fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
337755fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
3378c50e125dSChristian Göttsche 	u32 value = datum->value - 1;
337955fcf09bSChristopher J. PeBenito 
338055fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
338155fcf09bSChristopher J. PeBenito 	if (!perms[value])
338255fcf09bSChristopher J. PeBenito 		return -ENOMEM;
338355fcf09bSChristopher J. PeBenito 
338455fcf09bSChristopher J. PeBenito 	return 0;
338555fcf09bSChristopher J. PeBenito }
338655fcf09bSChristopher J. PeBenito 
security_get_permissions(struct selinux_policy * policy,const char * class,char *** perms,u32 * nperms)338702a52c5cSStephen Smalley int security_get_permissions(struct selinux_policy *policy,
3388c50e125dSChristian Göttsche 			     const char *class, char ***perms, u32 *nperms)
338955fcf09bSChristopher J. PeBenito {
339046169802SStephen Smalley 	struct policydb *policydb;
3391c50e125dSChristian Göttsche 	u32 i;
3392c50e125dSChristian Göttsche 	int rc;
339355fcf09bSChristopher J. PeBenito 	struct class_datum *match;
339455fcf09bSChristopher J. PeBenito 
339502a52c5cSStephen Smalley 	policydb = &policy->policydb;
339646169802SStephen Smalley 
33974b02b524SEric Paris 	rc = -EINVAL;
3398237389e3SOndrej Mosnacek 	match = symtab_search(&policydb->p_classes, class);
339955fcf09bSChristopher J. PeBenito 	if (!match) {
3400b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized class %s\n",
3401dd6f953aSHarvey Harrison 			__func__, class);
340255fcf09bSChristopher J. PeBenito 		goto out;
340355fcf09bSChristopher J. PeBenito 	}
340455fcf09bSChristopher J. PeBenito 
34054b02b524SEric Paris 	rc = -ENOMEM;
340655fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
34079f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
340855fcf09bSChristopher J. PeBenito 	if (!*perms)
340955fcf09bSChristopher J. PeBenito 		goto out;
341055fcf09bSChristopher J. PeBenito 
341155fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
341203414a49SOndrej Mosnacek 		rc = hashtab_map(&match->comdatum->permissions.table,
341355fcf09bSChristopher J. PeBenito 				 get_permissions_callback, *perms);
34144b02b524SEric Paris 		if (rc)
341555fcf09bSChristopher J. PeBenito 			goto err;
341655fcf09bSChristopher J. PeBenito 	}
341755fcf09bSChristopher J. PeBenito 
341803414a49SOndrej Mosnacek 	rc = hashtab_map(&match->permissions.table, get_permissions_callback,
341955fcf09bSChristopher J. PeBenito 			 *perms);
34204b02b524SEric Paris 	if (rc)
342155fcf09bSChristopher J. PeBenito 		goto err;
342255fcf09bSChristopher J. PeBenito 
342355fcf09bSChristopher J. PeBenito out:
342455fcf09bSChristopher J. PeBenito 	return rc;
342555fcf09bSChristopher J. PeBenito 
342655fcf09bSChristopher J. PeBenito err:
342755fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
342855fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
342955fcf09bSChristopher J. PeBenito 	kfree(*perms);
343055fcf09bSChristopher J. PeBenito 	return rc;
343155fcf09bSChristopher J. PeBenito }
343255fcf09bSChristopher J. PeBenito 
security_get_reject_unknown(void)3433e67b7985SStephen Smalley int security_get_reject_unknown(void)
34343f12070eSEric Paris {
34351b8b31a2SStephen Smalley 	struct selinux_policy *policy;
343646169802SStephen Smalley 	int value;
343746169802SStephen Smalley 
3438e67b7985SStephen Smalley 	if (!selinux_initialized())
343937ea433cSStephen Smalley 		return 0;
344037ea433cSStephen Smalley 
34411b8b31a2SStephen Smalley 	rcu_read_lock();
3442e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34431b8b31a2SStephen Smalley 	value = policy->policydb.reject_unknown;
34441b8b31a2SStephen Smalley 	rcu_read_unlock();
344546169802SStephen Smalley 	return value;
34463f12070eSEric Paris }
34473f12070eSEric Paris 
security_get_allow_unknown(void)3448e67b7985SStephen Smalley int security_get_allow_unknown(void)
34493f12070eSEric Paris {
34501b8b31a2SStephen Smalley 	struct selinux_policy *policy;
345146169802SStephen Smalley 	int value;
345246169802SStephen Smalley 
3453e67b7985SStephen Smalley 	if (!selinux_initialized())
345437ea433cSStephen Smalley 		return 0;
345537ea433cSStephen Smalley 
34561b8b31a2SStephen Smalley 	rcu_read_lock();
3457e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34581b8b31a2SStephen Smalley 	value = policy->policydb.allow_unknown;
34591b8b31a2SStephen Smalley 	rcu_read_unlock();
346046169802SStephen Smalley 	return value;
34613f12070eSEric Paris }
34623f12070eSEric Paris 
34633bb56b25SPaul Moore /**
34643bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
34653bb56b25SPaul Moore  * @req_cap: capability
34663bb56b25SPaul Moore  *
34673bb56b25SPaul Moore  * Description:
34683bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
34693bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
34703bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
34713bb56b25SPaul Moore  *
34723bb56b25SPaul Moore  */
security_policycap_supported(unsigned int req_cap)3473e67b7985SStephen Smalley int security_policycap_supported(unsigned int req_cap)
34743bb56b25SPaul Moore {
34751b8b31a2SStephen Smalley 	struct selinux_policy *policy;
34763bb56b25SPaul Moore 	int rc;
34773bb56b25SPaul Moore 
3478e67b7985SStephen Smalley 	if (!selinux_initialized())
347937ea433cSStephen Smalley 		return 0;
348037ea433cSStephen Smalley 
34811b8b31a2SStephen Smalley 	rcu_read_lock();
3482e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34831b8b31a2SStephen Smalley 	rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
34841b8b31a2SStephen Smalley 	rcu_read_unlock();
34853bb56b25SPaul Moore 
34863bb56b25SPaul Moore 	return rc;
34873bb56b25SPaul Moore }
34883bb56b25SPaul Moore 
3489376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3490376bd9cbSDarrel Goeddel 	u32 au_seqno;
3491376bd9cbSDarrel Goeddel 	struct context au_ctxt;
3492376bd9cbSDarrel Goeddel };
3493376bd9cbSDarrel Goeddel 
selinux_audit_rule_free(void * vrule)34949d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3495376bd9cbSDarrel Goeddel {
34969d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
34979d57a7f9SAhmed S. Darwish 
3498376bd9cbSDarrel Goeddel 	if (rule) {
3499376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
3500376bd9cbSDarrel Goeddel 		kfree(rule);
3501376bd9cbSDarrel Goeddel 	}
3502376bd9cbSDarrel Goeddel }
3503376bd9cbSDarrel Goeddel 
selinux_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule,gfp_t gfp)350428d0ecc5SGUO Zihua int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
350528d0ecc5SGUO Zihua 			    gfp_t gfp)
3506376bd9cbSDarrel Goeddel {
3507aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
35081b8b31a2SStephen Smalley 	struct selinux_policy *policy;
350946169802SStephen Smalley 	struct policydb *policydb;
3510376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
3511376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
3512376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
3513376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
35149d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3515376bd9cbSDarrel Goeddel 	int rc = 0;
3516376bd9cbSDarrel Goeddel 
3517376bd9cbSDarrel Goeddel 	*rule = NULL;
3518376bd9cbSDarrel Goeddel 
3519e67b7985SStephen Smalley 	if (!selinux_initialized())
35203ad40d64SSteve G 		return -EOPNOTSUPP;
3521376bd9cbSDarrel Goeddel 
3522376bd9cbSDarrel Goeddel 	switch (field) {
35233a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
35243a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
35253a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
35266e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
35276e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
35286e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3529376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
35305af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
3531376bd9cbSDarrel Goeddel 			return -EINVAL;
3532376bd9cbSDarrel Goeddel 		break;
35333a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
35343a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
35356e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
35366e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
353725985edcSLucas De Marchi 		/* we do not allow a range, indicated by the presence of '-' */
3538376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
3539376bd9cbSDarrel Goeddel 			return -EINVAL;
3540376bd9cbSDarrel Goeddel 		break;
3541376bd9cbSDarrel Goeddel 	default:
3542376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
3543376bd9cbSDarrel Goeddel 		return -EINVAL;
3544376bd9cbSDarrel Goeddel 	}
3545376bd9cbSDarrel Goeddel 
354628d0ecc5SGUO Zihua 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), gfp);
3547376bd9cbSDarrel Goeddel 	if (!tmprule)
3548376bd9cbSDarrel Goeddel 		return -ENOMEM;
3549376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
3550376bd9cbSDarrel Goeddel 
35511b8b31a2SStephen Smalley 	rcu_read_lock();
35521b8b31a2SStephen Smalley 	policy = rcu_dereference(state->policy);
35531b8b31a2SStephen Smalley 	policydb = &policy->policydb;
35541b8b31a2SStephen Smalley 	tmprule->au_seqno = policy->latest_granting;
3555376bd9cbSDarrel Goeddel 	switch (field) {
35563a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
35576e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3558237389e3SOndrej Mosnacek 		userdatum = symtab_search(&policydb->p_users, rulestr);
3559c52df19eSPaul Moore 		if (!userdatum) {
3560c52df19eSPaul Moore 			rc = -EINVAL;
3561c52df19eSPaul Moore 			goto err;
3562c52df19eSPaul Moore 		}
3563376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
3564376bd9cbSDarrel Goeddel 		break;
35653a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
35666e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3567237389e3SOndrej Mosnacek 		roledatum = symtab_search(&policydb->p_roles, rulestr);
3568c52df19eSPaul Moore 		if (!roledatum) {
3569c52df19eSPaul Moore 			rc = -EINVAL;
3570c52df19eSPaul Moore 			goto err;
3571c52df19eSPaul Moore 		}
3572376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
3573376bd9cbSDarrel Goeddel 		break;
35743a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
35756e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3576237389e3SOndrej Mosnacek 		typedatum = symtab_search(&policydb->p_types, rulestr);
3577c52df19eSPaul Moore 		if (!typedatum) {
3578c52df19eSPaul Moore 			rc = -EINVAL;
3579c52df19eSPaul Moore 			goto err;
3580c52df19eSPaul Moore 		}
3581376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
3582376bd9cbSDarrel Goeddel 		break;
35833a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
35843a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
35856e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
35866e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
3587aa8e712cSStephen Smalley 		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3588aa8e712cSStephen Smalley 				     GFP_ATOMIC);
35894b02b524SEric Paris 		if (rc)
3590c52df19eSPaul Moore 			goto err;
3591376bd9cbSDarrel Goeddel 		break;
3592376bd9cbSDarrel Goeddel 	}
35931b8b31a2SStephen Smalley 	rcu_read_unlock();
3594376bd9cbSDarrel Goeddel 
3595376bd9cbSDarrel Goeddel 	*rule = tmprule;
3596c52df19eSPaul Moore 	return 0;
3597376bd9cbSDarrel Goeddel 
3598c52df19eSPaul Moore err:
3599c52df19eSPaul Moore 	rcu_read_unlock();
3600c52df19eSPaul Moore 	selinux_audit_rule_free(tmprule);
3601c52df19eSPaul Moore 	*rule = NULL;
3602376bd9cbSDarrel Goeddel 	return rc;
3603376bd9cbSDarrel Goeddel }
3604376bd9cbSDarrel Goeddel 
36059d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
selinux_audit_rule_known(struct audit_krule * rule)36069d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
36079d57a7f9SAhmed S. Darwish {
3608c50e125dSChristian Göttsche 	u32 i;
36099d57a7f9SAhmed S. Darwish 
36109d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
36119d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
36129d57a7f9SAhmed S. Darwish 		switch (f->type) {
36139d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
36149d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
36159d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
36169d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
36179d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
36189d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
36199d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
36209d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
36219d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
36229d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
36239d57a7f9SAhmed S. Darwish 			return 1;
36249d57a7f9SAhmed S. Darwish 		}
36259d57a7f9SAhmed S. Darwish 	}
36269d57a7f9SAhmed S. Darwish 
36279d57a7f9SAhmed S. Darwish 	return 0;
36289d57a7f9SAhmed S. Darwish }
36299d57a7f9SAhmed S. Darwish 
selinux_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)363090462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3631376bd9cbSDarrel Goeddel {
3632aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
36331b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3634376bd9cbSDarrel Goeddel 	struct context *ctxt;
3635376bd9cbSDarrel Goeddel 	struct mls_level *level;
36369d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
3637376bd9cbSDarrel Goeddel 	int match = 0;
3638376bd9cbSDarrel Goeddel 
36399ad42a79SRichard Guy Briggs 	if (unlikely(!rule)) {
36409ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3641376bd9cbSDarrel Goeddel 		return -ENOENT;
3642376bd9cbSDarrel Goeddel 	}
3643376bd9cbSDarrel Goeddel 
3644e67b7985SStephen Smalley 	if (!selinux_initialized())
364537ea433cSStephen Smalley 		return 0;
364637ea433cSStephen Smalley 
36471b8b31a2SStephen Smalley 	rcu_read_lock();
3648376bd9cbSDarrel Goeddel 
36491b8b31a2SStephen Smalley 	policy = rcu_dereference(state->policy);
36501b8b31a2SStephen Smalley 
36511b8b31a2SStephen Smalley 	if (rule->au_seqno < policy->latest_granting) {
3652376bd9cbSDarrel Goeddel 		match = -ESTALE;
3653376bd9cbSDarrel Goeddel 		goto out;
3654376bd9cbSDarrel Goeddel 	}
3655376bd9cbSDarrel Goeddel 
36561b8b31a2SStephen Smalley 	ctxt = sidtab_search(policy->sidtab, sid);
36579ad42a79SRichard Guy Briggs 	if (unlikely(!ctxt)) {
36589ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
36599a2f44f0SStephen Smalley 			  sid);
3660376bd9cbSDarrel Goeddel 		match = -ENOENT;
3661376bd9cbSDarrel Goeddel 		goto out;
3662376bd9cbSDarrel Goeddel 	}
3663376bd9cbSDarrel Goeddel 
3664376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
3665376bd9cbSDarrel Goeddel 	   without a match */
3666376bd9cbSDarrel Goeddel 	switch (field) {
36673a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
36686e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3669376bd9cbSDarrel Goeddel 		switch (op) {
36705af75d8dSAl Viro 		case Audit_equal:
3671376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
3672376bd9cbSDarrel Goeddel 			break;
36735af75d8dSAl Viro 		case Audit_not_equal:
3674376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
3675376bd9cbSDarrel Goeddel 			break;
3676376bd9cbSDarrel Goeddel 		}
3677376bd9cbSDarrel Goeddel 		break;
36783a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
36796e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3680376bd9cbSDarrel Goeddel 		switch (op) {
36815af75d8dSAl Viro 		case Audit_equal:
3682376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
3683376bd9cbSDarrel Goeddel 			break;
36845af75d8dSAl Viro 		case Audit_not_equal:
3685376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
3686376bd9cbSDarrel Goeddel 			break;
3687376bd9cbSDarrel Goeddel 		}
3688376bd9cbSDarrel Goeddel 		break;
36893a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
36906e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3691376bd9cbSDarrel Goeddel 		switch (op) {
36925af75d8dSAl Viro 		case Audit_equal:
3693376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
3694376bd9cbSDarrel Goeddel 			break;
36955af75d8dSAl Viro 		case Audit_not_equal:
3696376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
3697376bd9cbSDarrel Goeddel 			break;
3698376bd9cbSDarrel Goeddel 		}
3699376bd9cbSDarrel Goeddel 		break;
37003a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
37013a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
37026e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
37036e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
37046e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
37056e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
3706376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3707376bd9cbSDarrel Goeddel 		switch (op) {
37085af75d8dSAl Viro 		case Audit_equal:
3709376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3710376bd9cbSDarrel Goeddel 					     level);
3711376bd9cbSDarrel Goeddel 			break;
37125af75d8dSAl Viro 		case Audit_not_equal:
3713376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3714376bd9cbSDarrel Goeddel 					      level);
3715376bd9cbSDarrel Goeddel 			break;
37165af75d8dSAl Viro 		case Audit_lt:
3717376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3718376bd9cbSDarrel Goeddel 					       level) &&
3719376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3720376bd9cbSDarrel Goeddel 					       level));
3721376bd9cbSDarrel Goeddel 			break;
37225af75d8dSAl Viro 		case Audit_le:
3723376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3724376bd9cbSDarrel Goeddel 					      level);
3725376bd9cbSDarrel Goeddel 			break;
37265af75d8dSAl Viro 		case Audit_gt:
3727376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
3728376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
3729376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
3730376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
3731376bd9cbSDarrel Goeddel 			break;
37325af75d8dSAl Viro 		case Audit_ge:
3733376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
3734376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
3735376bd9cbSDarrel Goeddel 			break;
3736376bd9cbSDarrel Goeddel 		}
3737376bd9cbSDarrel Goeddel 	}
3738376bd9cbSDarrel Goeddel 
3739376bd9cbSDarrel Goeddel out:
37401b8b31a2SStephen Smalley 	rcu_read_unlock();
3741376bd9cbSDarrel Goeddel 	return match;
3742376bd9cbSDarrel Goeddel }
3743376bd9cbSDarrel Goeddel 
aurule_avc_callback(u32 event)3744562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3745376bd9cbSDarrel Goeddel {
37463c797e51SOndrej Mosnacek 	if (event == AVC_CALLBACK_RESET)
37473c797e51SOndrej Mosnacek 		return audit_update_lsm_rules();
37483c797e51SOndrej Mosnacek 	return 0;
3749376bd9cbSDarrel Goeddel }
3750376bd9cbSDarrel Goeddel 
aurule_init(void)3751376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3752376bd9cbSDarrel Goeddel {
3753376bd9cbSDarrel Goeddel 	int err;
3754376bd9cbSDarrel Goeddel 
3755562c99f2SWanlong Gao 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3756376bd9cbSDarrel Goeddel 	if (err)
3757376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
3758376bd9cbSDarrel Goeddel 
3759376bd9cbSDarrel Goeddel 	return err;
3760376bd9cbSDarrel Goeddel }
3761376bd9cbSDarrel Goeddel __initcall(aurule_init);
3762376bd9cbSDarrel Goeddel 
37637420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
37647420ed23SVenkat Yekkirala /**
37655778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
37665778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
37675dbe1eb0SPaul Moore  * @sid: the SELinux SID
37687420ed23SVenkat Yekkirala  *
37697420ed23SVenkat Yekkirala  * Description:
37707420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
37715778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
37725778eabdSPaul Moore  * already been initialized.
37737420ed23SVenkat Yekkirala  *
37747420ed23SVenkat Yekkirala  */
security_netlbl_cache_add(struct netlbl_lsm_secattr * secattr,u32 sid)37755778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
37765dbe1eb0SPaul Moore 				      u32 sid)
37777420ed23SVenkat Yekkirala {
37785dbe1eb0SPaul Moore 	u32 *sid_cache;
37797420ed23SVenkat Yekkirala 
37805dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
37815dbe1eb0SPaul Moore 	if (sid_cache == NULL)
37825dbe1eb0SPaul Moore 		return;
37835778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
37845dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
37855dbe1eb0SPaul Moore 		kfree(sid_cache);
37865778eabdSPaul Moore 		return;
37870ec8abd7SJesper Juhl 	}
37887420ed23SVenkat Yekkirala 
37895dbe1eb0SPaul Moore 	*sid_cache = sid;
37905dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
37915dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
37925778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
37937420ed23SVenkat Yekkirala }
37947420ed23SVenkat Yekkirala 
37957420ed23SVenkat Yekkirala /**
37965778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
37977420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
37987420ed23SVenkat Yekkirala  * @sid: the SELinux SID
37997420ed23SVenkat Yekkirala  *
38007420ed23SVenkat Yekkirala  * Description:
38015778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
38027420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
380325985edcSLucas De Marchi  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
38045dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
38055dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
38065dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
38075dbe1eb0SPaul Moore  * failure.
38087420ed23SVenkat Yekkirala  *
38097420ed23SVenkat Yekkirala  */
security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr * secattr,u32 * sid)3810e67b7985SStephen Smalley int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
38117420ed23SVenkat Yekkirala 				   u32 *sid)
38127420ed23SVenkat Yekkirala {
38131b8b31a2SStephen Smalley 	struct selinux_policy *policy;
381446169802SStephen Smalley 	struct policydb *policydb;
381546169802SStephen Smalley 	struct sidtab *sidtab;
38167ae9f23cSEric Paris 	int rc;
38177420ed23SVenkat Yekkirala 	struct context *ctx;
38187420ed23SVenkat Yekkirala 	struct context ctx_new;
38195778eabdSPaul Moore 
3820e67b7985SStephen Smalley 	if (!selinux_initialized()) {
38215778eabdSPaul Moore 		*sid = SECSID_NULL;
38225778eabdSPaul Moore 		return 0;
38235778eabdSPaul Moore 	}
38247420ed23SVenkat Yekkirala 
38259ad6e9cbSOndrej Mosnacek retry:
38269ad6e9cbSOndrej Mosnacek 	rc = 0;
38271b8b31a2SStephen Smalley 	rcu_read_lock();
3828e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
38291b8b31a2SStephen Smalley 	policydb = &policy->policydb;
38301b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
383146169802SStephen Smalley 
38327ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
38335dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
38347ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
383516efd454SPaul Moore 		*sid = secattr->attr.secid;
38367ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
38377ae9f23cSEric Paris 		rc = -EIDRM;
3838aa8e712cSStephen Smalley 		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
38397420ed23SVenkat Yekkirala 		if (ctx == NULL)
38407ae9f23cSEric Paris 			goto out;
38417420ed23SVenkat Yekkirala 
384281990fbdSPaul Moore 		context_init(&ctx_new);
38437420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
38447420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
38457420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
3846aa8e712cSStephen Smalley 		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3847701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3848aa8e712cSStephen Smalley 			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
38497ae9f23cSEric Paris 			if (rc)
38507ae9f23cSEric Paris 				goto out;
38517420ed23SVenkat Yekkirala 		}
38527ae9f23cSEric Paris 		rc = -EIDRM;
38539ad6e9cbSOndrej Mosnacek 		if (!mls_context_isvalid(policydb, &ctx_new)) {
38549ad6e9cbSOndrej Mosnacek 			ebitmap_destroy(&ctx_new.range.level[0].cat);
38559ad6e9cbSOndrej Mosnacek 			goto out;
38569ad6e9cbSOndrej Mosnacek 		}
38577420ed23SVenkat Yekkirala 
3858225621c9SOndrej Mosnacek 		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
38599ad6e9cbSOndrej Mosnacek 		ebitmap_destroy(&ctx_new.range.level[0].cat);
38609ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
38619ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
38629ad6e9cbSOndrej Mosnacek 			goto retry;
38639ad6e9cbSOndrej Mosnacek 		}
38647ae9f23cSEric Paris 		if (rc)
38659ad6e9cbSOndrej Mosnacek 			goto out;
38667420ed23SVenkat Yekkirala 
38675dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
38687ae9f23cSEric Paris 	} else
3869388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
38707420ed23SVenkat Yekkirala 
38717ae9f23cSEric Paris out:
38721b8b31a2SStephen Smalley 	rcu_read_unlock();
38737420ed23SVenkat Yekkirala 	return rc;
38747420ed23SVenkat Yekkirala }
38757420ed23SVenkat Yekkirala 
38767420ed23SVenkat Yekkirala /**
38775778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
38785778eabdSPaul Moore  * @sid: the SELinux SID
38795778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
38807420ed23SVenkat Yekkirala  *
38817420ed23SVenkat Yekkirala  * Description:
38825778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
38835778eabdSPaul Moore  * Returns zero on success, negative values on failure.
38847420ed23SVenkat Yekkirala  *
38857420ed23SVenkat Yekkirala  */
security_netlbl_sid_to_secattr(u32 sid,struct netlbl_lsm_secattr * secattr)3886e67b7985SStephen Smalley int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
38877420ed23SVenkat Yekkirala {
38881b8b31a2SStephen Smalley 	struct selinux_policy *policy;
388946169802SStephen Smalley 	struct policydb *policydb;
389099d854d2SPaul Moore 	int rc;
38917420ed23SVenkat Yekkirala 	struct context *ctx;
38927420ed23SVenkat Yekkirala 
3893e67b7985SStephen Smalley 	if (!selinux_initialized())
38947420ed23SVenkat Yekkirala 		return 0;
38957420ed23SVenkat Yekkirala 
38961b8b31a2SStephen Smalley 	rcu_read_lock();
3897e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
38981b8b31a2SStephen Smalley 	policydb = &policy->policydb;
389946169802SStephen Smalley 
390099d854d2SPaul Moore 	rc = -ENOENT;
39011b8b31a2SStephen Smalley 	ctx = sidtab_search(policy->sidtab, sid);
39024b02b524SEric Paris 	if (ctx == NULL)
39034b02b524SEric Paris 		goto out;
39044b02b524SEric Paris 
39054b02b524SEric Paris 	rc = -ENOMEM;
3906aa8e712cSStephen Smalley 	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
39077420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
39084b02b524SEric Paris 	if (secattr->domain == NULL)
39094b02b524SEric Paris 		goto out;
39104b02b524SEric Paris 
39118d75899dSPaul Moore 	secattr->attr.secid = sid;
39128d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3913aa8e712cSStephen Smalley 	mls_export_netlbl_lvl(policydb, ctx, secattr);
3914aa8e712cSStephen Smalley 	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
39154b02b524SEric Paris out:
39161b8b31a2SStephen Smalley 	rcu_read_unlock();
3917f8687afeSPaul Moore 	return rc;
3918f8687afeSPaul Moore }
39197420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3920cee74f47SEric Paris 
3921cee74f47SEric Paris /**
3922fdd1ffe8SLakshmi Ramasubramanian  * __security_read_policy - read the policy.
3923fdd1ffe8SLakshmi Ramasubramanian  * @policy: SELinux policy
3924fdd1ffe8SLakshmi Ramasubramanian  * @data: binary policy data
3925fdd1ffe8SLakshmi Ramasubramanian  * @len: length of data in bytes
3926fdd1ffe8SLakshmi Ramasubramanian  *
3927fdd1ffe8SLakshmi Ramasubramanian  */
__security_read_policy(struct selinux_policy * policy,void * data,size_t * len)3928fdd1ffe8SLakshmi Ramasubramanian static int __security_read_policy(struct selinux_policy *policy,
3929fdd1ffe8SLakshmi Ramasubramanian 				  void *data, size_t *len)
3930fdd1ffe8SLakshmi Ramasubramanian {
3931fdd1ffe8SLakshmi Ramasubramanian 	int rc;
3932fdd1ffe8SLakshmi Ramasubramanian 	struct policy_file fp;
3933fdd1ffe8SLakshmi Ramasubramanian 
3934fdd1ffe8SLakshmi Ramasubramanian 	fp.data = data;
3935fdd1ffe8SLakshmi Ramasubramanian 	fp.len = *len;
3936fdd1ffe8SLakshmi Ramasubramanian 
3937fdd1ffe8SLakshmi Ramasubramanian 	rc = policydb_write(&policy->policydb, &fp);
3938fdd1ffe8SLakshmi Ramasubramanian 	if (rc)
3939fdd1ffe8SLakshmi Ramasubramanian 		return rc;
3940fdd1ffe8SLakshmi Ramasubramanian 
3941fdd1ffe8SLakshmi Ramasubramanian 	*len = (unsigned long)fp.data - (unsigned long)data;
3942fdd1ffe8SLakshmi Ramasubramanian 	return 0;
3943fdd1ffe8SLakshmi Ramasubramanian }
3944fdd1ffe8SLakshmi Ramasubramanian 
3945fdd1ffe8SLakshmi Ramasubramanian /**
3946cee74f47SEric Paris  * security_read_policy - read the policy.
3947cee74f47SEric Paris  * @data: binary policy data
3948cee74f47SEric Paris  * @len: length of data in bytes
3949cee74f47SEric Paris  *
3950cee74f47SEric Paris  */
security_read_policy(void ** data,size_t * len)3951e67b7985SStephen Smalley int security_read_policy(void **data, size_t *len)
3952cee74f47SEric Paris {
3953e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
39541b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3955cee74f47SEric Paris 
395666ccd256SOndrej Mosnacek 	policy = rcu_dereference_protected(
395766ccd256SOndrej Mosnacek 			state->policy, lockdep_is_held(&state->policy_mutex));
395866ccd256SOndrej Mosnacek 	if (!policy)
3959cee74f47SEric Paris 		return -EINVAL;
3960cee74f47SEric Paris 
396166ccd256SOndrej Mosnacek 	*len = policy->policydb.len;
3962845ca30fSEric Paris 	*data = vmalloc_user(*len);
3963cee74f47SEric Paris 	if (!*data)
3964cee74f47SEric Paris 		return -ENOMEM;
3965cee74f47SEric Paris 
3966fdd1ffe8SLakshmi Ramasubramanian 	return __security_read_policy(policy, *data, len);
3967fdd1ffe8SLakshmi Ramasubramanian }
3968cee74f47SEric Paris 
3969fdd1ffe8SLakshmi Ramasubramanian /**
3970fdd1ffe8SLakshmi Ramasubramanian  * security_read_state_kernel - read the policy.
3971fdd1ffe8SLakshmi Ramasubramanian  * @data: binary policy data
3972fdd1ffe8SLakshmi Ramasubramanian  * @len: length of data in bytes
3973fdd1ffe8SLakshmi Ramasubramanian  *
3974fdd1ffe8SLakshmi Ramasubramanian  * Allocates kernel memory for reading SELinux policy.
3975fdd1ffe8SLakshmi Ramasubramanian  * This function is for internal use only and should not
3976fdd1ffe8SLakshmi Ramasubramanian  * be used for returning data to user space.
3977fdd1ffe8SLakshmi Ramasubramanian  *
3978fdd1ffe8SLakshmi Ramasubramanian  * This function must be called with policy_mutex held.
3979fdd1ffe8SLakshmi Ramasubramanian  */
security_read_state_kernel(void ** data,size_t * len)3980e67b7985SStephen Smalley int security_read_state_kernel(void **data, size_t *len)
3981fdd1ffe8SLakshmi Ramasubramanian {
398273de1befSXiu Jianfeng 	int err;
3983e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
3984fdd1ffe8SLakshmi Ramasubramanian 	struct selinux_policy *policy;
3985cee74f47SEric Paris 
3986fdd1ffe8SLakshmi Ramasubramanian 	policy = rcu_dereference_protected(
3987fdd1ffe8SLakshmi Ramasubramanian 			state->policy, lockdep_is_held(&state->policy_mutex));
3988fdd1ffe8SLakshmi Ramasubramanian 	if (!policy)
3989fdd1ffe8SLakshmi Ramasubramanian 		return -EINVAL;
3990cee74f47SEric Paris 
3991fdd1ffe8SLakshmi Ramasubramanian 	*len = policy->policydb.len;
3992fdd1ffe8SLakshmi Ramasubramanian 	*data = vmalloc(*len);
3993fdd1ffe8SLakshmi Ramasubramanian 	if (!*data)
3994fdd1ffe8SLakshmi Ramasubramanian 		return -ENOMEM;
3995fdd1ffe8SLakshmi Ramasubramanian 
399673de1befSXiu Jianfeng 	err = __security_read_policy(policy, *data, len);
399773de1befSXiu Jianfeng 	if (err) {
399873de1befSXiu Jianfeng 		vfree(*data);
399973de1befSXiu Jianfeng 		*data = NULL;
400073de1befSXiu Jianfeng 		*len = 0;
400173de1befSXiu Jianfeng 	}
400273de1befSXiu Jianfeng 	return err;
4003cee74f47SEric Paris }
4004