xref: /openbmc/linux/security/selinux/ss/services.c (revision aa4b6051)
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])
210*aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
211aa8e712cSStephen Smalley 			if (allow_unknown && !mapping->perms[i])
212*aa4b6051SChristian 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])
218*aa4b6051SChristian 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])
223*aa4b6051SChristian Göttsche 				result |= (u32)1<<i;
224aa8e712cSStephen Smalley 			if (!allow_unknown && !mapping->perms[i])
225*aa4b6051SChristian 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++)
233*aa4b6051SChristian 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 {
959fa1aa143SJeff Vander Stoep 		BUG();
960fa1aa143SJeff Vander Stoep 	}
961fa1aa143SJeff Vander Stoep 
962fa1aa143SJeff Vander Stoep 	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
963fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_ALLOWED;
964fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
965fa1aa143SJeff Vander Stoep 			memset(xpermd->allowed->p, 0xff,
966fa1aa143SJeff Vander Stoep 					sizeof(xpermd->allowed->p));
967fa1aa143SJeff Vander Stoep 		}
968fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
969fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
970fa1aa143SJeff Vander Stoep 				xpermd->allowed->p[i] |=
971fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
972fa1aa143SJeff Vander Stoep 		}
973fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
974fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_AUDITALLOW;
975fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
976fa1aa143SJeff Vander Stoep 			memset(xpermd->auditallow->p, 0xff,
977fa1aa143SJeff Vander Stoep 					sizeof(xpermd->auditallow->p));
978fa1aa143SJeff Vander Stoep 		}
979fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
980fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
981fa1aa143SJeff Vander Stoep 				xpermd->auditallow->p[i] |=
982fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
983fa1aa143SJeff Vander Stoep 		}
984fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
985fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_DONTAUDIT;
986fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
987fa1aa143SJeff Vander Stoep 			memset(xpermd->dontaudit->p, 0xff,
988fa1aa143SJeff Vander Stoep 					sizeof(xpermd->dontaudit->p));
989fa1aa143SJeff Vander Stoep 		}
990fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
991fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
992fa1aa143SJeff Vander Stoep 				xpermd->dontaudit->p[i] |=
993fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
994fa1aa143SJeff Vander Stoep 		}
995fa1aa143SJeff Vander Stoep 	} else {
996fa1aa143SJeff Vander Stoep 		BUG();
997fa1aa143SJeff Vander Stoep 	}
998fa1aa143SJeff Vander Stoep }
999fa1aa143SJeff Vander Stoep 
security_compute_xperms_decision(u32 ssid,u32 tsid,u16 orig_tclass,u8 driver,struct extended_perms_decision * xpermd)1000e67b7985SStephen Smalley void security_compute_xperms_decision(u32 ssid,
1001fa1aa143SJeff Vander Stoep 				      u32 tsid,
1002fa1aa143SJeff Vander Stoep 				      u16 orig_tclass,
1003fa1aa143SJeff Vander Stoep 				      u8 driver,
1004fa1aa143SJeff Vander Stoep 				      struct extended_perms_decision *xpermd)
1005fa1aa143SJeff Vander Stoep {
10061b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1007aa8e712cSStephen Smalley 	struct policydb *policydb;
1008aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1009fa1aa143SJeff Vander Stoep 	u16 tclass;
1010fa1aa143SJeff Vander Stoep 	struct context *scontext, *tcontext;
1011fa1aa143SJeff Vander Stoep 	struct avtab_key avkey;
1012fa1aa143SJeff Vander Stoep 	struct avtab_node *node;
1013fa1aa143SJeff Vander Stoep 	struct ebitmap *sattr, *tattr;
1014fa1aa143SJeff Vander Stoep 	struct ebitmap_node *snode, *tnode;
1015fa1aa143SJeff Vander Stoep 	unsigned int i, j;
1016fa1aa143SJeff Vander Stoep 
1017fa1aa143SJeff Vander Stoep 	xpermd->driver = driver;
1018fa1aa143SJeff Vander Stoep 	xpermd->used = 0;
1019fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1020fa1aa143SJeff Vander Stoep 	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1021fa1aa143SJeff Vander Stoep 	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1022fa1aa143SJeff Vander Stoep 
10231b8b31a2SStephen Smalley 	rcu_read_lock();
1024e67b7985SStephen Smalley 	if (!selinux_initialized())
1025fa1aa143SJeff Vander Stoep 		goto allow;
1026fa1aa143SJeff Vander Stoep 
1027e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
10281b8b31a2SStephen Smalley 	policydb = &policy->policydb;
10291b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1030aa8e712cSStephen Smalley 
1031aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
1032fa1aa143SJeff Vander Stoep 	if (!scontext) {
1033b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1034fa1aa143SJeff Vander Stoep 		       __func__, ssid);
1035fa1aa143SJeff Vander Stoep 		goto out;
1036fa1aa143SJeff Vander Stoep 	}
1037fa1aa143SJeff Vander Stoep 
1038aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
1039fa1aa143SJeff Vander Stoep 	if (!tcontext) {
1040b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1041fa1aa143SJeff Vander Stoep 		       __func__, tsid);
1042fa1aa143SJeff Vander Stoep 		goto out;
1043fa1aa143SJeff Vander Stoep 	}
1044fa1aa143SJeff Vander Stoep 
10451b8b31a2SStephen Smalley 	tclass = unmap_class(&policy->map, orig_tclass);
1046fa1aa143SJeff Vander Stoep 	if (unlikely(orig_tclass && !tclass)) {
1047aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1048fa1aa143SJeff Vander Stoep 			goto allow;
1049fa1aa143SJeff Vander Stoep 		goto out;
1050fa1aa143SJeff Vander Stoep 	}
1051fa1aa143SJeff Vander Stoep 
1052fa1aa143SJeff Vander Stoep 
1053aa8e712cSStephen Smalley 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1054fa1aa143SJeff Vander Stoep 		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
1055fa1aa143SJeff Vander Stoep 		goto out;
1056fa1aa143SJeff Vander Stoep 	}
1057fa1aa143SJeff Vander Stoep 
1058fa1aa143SJeff Vander Stoep 	avkey.target_class = tclass;
1059fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_XPERMS;
1060acdf52d9SKent Overstreet 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
1061acdf52d9SKent Overstreet 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1062fa1aa143SJeff Vander Stoep 	ebitmap_for_each_positive_bit(sattr, snode, i) {
1063fa1aa143SJeff Vander Stoep 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1064fa1aa143SJeff Vander Stoep 			avkey.source_type = i + 1;
1065fa1aa143SJeff Vander Stoep 			avkey.target_type = j + 1;
1066aa8e712cSStephen Smalley 			for (node = avtab_search_node(&policydb->te_avtab,
1067aa8e712cSStephen Smalley 						      &avkey);
1068fa1aa143SJeff Vander Stoep 			     node;
1069fa1aa143SJeff Vander Stoep 			     node = avtab_search_node_next(node, avkey.specified))
1070fa1aa143SJeff Vander Stoep 				services_compute_xperms_decision(xpermd, node);
1071fa1aa143SJeff Vander Stoep 
1072aa8e712cSStephen Smalley 			cond_compute_xperms(&policydb->te_cond_avtab,
1073fa1aa143SJeff Vander Stoep 						&avkey, xpermd);
1074fa1aa143SJeff Vander Stoep 		}
1075fa1aa143SJeff Vander Stoep 	}
1076fa1aa143SJeff Vander Stoep out:
10771b8b31a2SStephen Smalley 	rcu_read_unlock();
1078fa1aa143SJeff Vander Stoep 	return;
1079fa1aa143SJeff Vander Stoep allow:
1080fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1081fa1aa143SJeff Vander Stoep 	goto out;
1082fa1aa143SJeff Vander Stoep }
1083c6d3aaa4SStephen Smalley 
10841da177e4SLinus Torvalds /**
10851da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
10861da177e4SLinus Torvalds  * @ssid: source security identifier
10871da177e4SLinus Torvalds  * @tsid: target security identifier
1088e9fd7292SPaul Moore  * @orig_tclass: target security class
10891da177e4SLinus Torvalds  * @avd: access vector decisions
1090fa1aa143SJeff Vander Stoep  * @xperms: extended permissions
10911da177e4SLinus Torvalds  *
10921da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
10931da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
10941da177e4SLinus Torvalds  */
security_compute_av(u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision * avd,struct extended_perms * xperms)1095e67b7985SStephen Smalley void security_compute_av(u32 ssid,
10961da177e4SLinus Torvalds 			 u32 tsid,
1097c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
1098fa1aa143SJeff Vander Stoep 			 struct av_decision *avd,
1099fa1aa143SJeff Vander Stoep 			 struct extended_perms *xperms)
1100c6d3aaa4SStephen Smalley {
11011b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1102aa8e712cSStephen Smalley 	struct policydb *policydb;
1103aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1104c6d3aaa4SStephen Smalley 	u16 tclass;
110519439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
1106c6d3aaa4SStephen Smalley 
11071b8b31a2SStephen Smalley 	rcu_read_lock();
1108e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
11091b8b31a2SStephen Smalley 	avd_init(policy, avd);
1110fa1aa143SJeff Vander Stoep 	xperms->len = 0;
1111e67b7985SStephen Smalley 	if (!selinux_initialized())
1112c6d3aaa4SStephen Smalley 		goto allow;
1113c6d3aaa4SStephen Smalley 
11141b8b31a2SStephen Smalley 	policydb = &policy->policydb;
11151b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1116aa8e712cSStephen Smalley 
1117aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
111819439d05SStephen Smalley 	if (!scontext) {
1119b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
112019439d05SStephen Smalley 		       __func__, ssid);
112119439d05SStephen Smalley 		goto out;
112219439d05SStephen Smalley 	}
112319439d05SStephen Smalley 
112419439d05SStephen Smalley 	/* permissive domain? */
1125aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
112619439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
112719439d05SStephen Smalley 
1128aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
112919439d05SStephen Smalley 	if (!tcontext) {
1130b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
113119439d05SStephen Smalley 		       __func__, tsid);
113219439d05SStephen Smalley 		goto out;
113319439d05SStephen Smalley 	}
113419439d05SStephen Smalley 
11351b8b31a2SStephen Smalley 	tclass = unmap_class(&policy->map, orig_tclass);
1136c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
1137aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
1138c6d3aaa4SStephen Smalley 			goto allow;
1139b7f3008aSStephen Smalley 		goto out;
1140c6d3aaa4SStephen Smalley 	}
1141aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1142aa8e712cSStephen Smalley 				  xperms);
11431b8b31a2SStephen Smalley 	map_decision(&policy->map, orig_tclass, avd,
1144aa8e712cSStephen Smalley 		     policydb->allow_unknown);
1145b7f3008aSStephen Smalley out:
11461b8b31a2SStephen Smalley 	rcu_read_unlock();
114719439d05SStephen Smalley 	return;
1148c6d3aaa4SStephen Smalley allow:
1149c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
1150b7f3008aSStephen Smalley 	goto out;
1151c6d3aaa4SStephen Smalley }
1152c6d3aaa4SStephen Smalley 
security_compute_av_user(u32 ssid,u32 tsid,u16 tclass,struct av_decision * avd)1153e67b7985SStephen Smalley void security_compute_av_user(u32 ssid,
1154c6d3aaa4SStephen Smalley 			      u32 tsid,
11551da177e4SLinus Torvalds 			      u16 tclass,
11561da177e4SLinus Torvalds 			      struct av_decision *avd)
11571da177e4SLinus Torvalds {
11581b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1159aa8e712cSStephen Smalley 	struct policydb *policydb;
1160aa8e712cSStephen Smalley 	struct sidtab *sidtab;
116119439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
11621da177e4SLinus Torvalds 
11631b8b31a2SStephen Smalley 	rcu_read_lock();
1164e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
11651b8b31a2SStephen Smalley 	avd_init(policy, avd);
1166e67b7985SStephen Smalley 	if (!selinux_initialized())
116719439d05SStephen Smalley 		goto allow;
116819439d05SStephen Smalley 
11691b8b31a2SStephen Smalley 	policydb = &policy->policydb;
11701b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1171aa8e712cSStephen Smalley 
1172aa8e712cSStephen Smalley 	scontext = sidtab_search(sidtab, ssid);
117319439d05SStephen Smalley 	if (!scontext) {
1174b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
117519439d05SStephen Smalley 		       __func__, ssid);
117619439d05SStephen Smalley 		goto out;
117719439d05SStephen Smalley 	}
117819439d05SStephen Smalley 
117919439d05SStephen Smalley 	/* permissive domain? */
1180aa8e712cSStephen Smalley 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
118119439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
118219439d05SStephen Smalley 
1183aa8e712cSStephen Smalley 	tcontext = sidtab_search(sidtab, tsid);
118419439d05SStephen Smalley 	if (!tcontext) {
1185b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
118619439d05SStephen Smalley 		       __func__, tsid);
118719439d05SStephen Smalley 		goto out;
118819439d05SStephen Smalley 	}
118919439d05SStephen Smalley 
119019439d05SStephen Smalley 	if (unlikely(!tclass)) {
1191aa8e712cSStephen Smalley 		if (policydb->allow_unknown)
119219439d05SStephen Smalley 			goto allow;
119319439d05SStephen Smalley 		goto out;
119419439d05SStephen Smalley 	}
119519439d05SStephen Smalley 
1196aa8e712cSStephen Smalley 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1197aa8e712cSStephen Smalley 				  NULL);
119819439d05SStephen Smalley  out:
11991b8b31a2SStephen Smalley 	rcu_read_unlock();
120019439d05SStephen Smalley 	return;
120119439d05SStephen Smalley allow:
120219439d05SStephen Smalley 	avd->allowed = 0xffffffff;
120319439d05SStephen Smalley 	goto out;
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds /*
12071da177e4SLinus Torvalds  * Write the security context string representation of
12081da177e4SLinus Torvalds  * the context structure `context' into a dynamically
12091da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
12101da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
12111da177e4SLinus Torvalds  * the length of the string.
12121da177e4SLinus Torvalds  */
context_struct_to_string(struct policydb * p,struct context * context,char ** scontext,u32 * scontext_len)1213aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p,
1214aa8e712cSStephen Smalley 				    struct context *context,
1215aa8e712cSStephen Smalley 				    char **scontext, u32 *scontext_len)
12161da177e4SLinus Torvalds {
12171da177e4SLinus Torvalds 	char *scontextp;
12181da177e4SLinus Torvalds 
1219d5630b9dSEric Paris 	if (scontext)
12201da177e4SLinus Torvalds 		*scontext = NULL;
12211da177e4SLinus Torvalds 	*scontext_len = 0;
12221da177e4SLinus Torvalds 
122312b29f34SStephen Smalley 	if (context->len) {
122412b29f34SStephen Smalley 		*scontext_len = context->len;
1225bb7081abSEric Paris 		if (scontext) {
122612b29f34SStephen Smalley 			*scontext = kstrdup(context->str, GFP_ATOMIC);
122712b29f34SStephen Smalley 			if (!(*scontext))
122812b29f34SStephen Smalley 				return -ENOMEM;
1229bb7081abSEric Paris 		}
123012b29f34SStephen Smalley 		return 0;
123112b29f34SStephen Smalley 	}
123212b29f34SStephen Smalley 
12331da177e4SLinus Torvalds 	/* Compute the size of the context. */
1234aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1235aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1236aa8e712cSStephen Smalley 	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1237aa8e712cSStephen Smalley 	*scontext_len += mls_compute_context_len(p, context);
12381da177e4SLinus Torvalds 
1239d5630b9dSEric Paris 	if (!scontext)
1240d5630b9dSEric Paris 		return 0;
1241d5630b9dSEric Paris 
12421da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
12431da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12445d55a345SEric Paris 	if (!scontextp)
12451da177e4SLinus Torvalds 		return -ENOMEM;
12461da177e4SLinus Torvalds 	*scontext = scontextp;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	/*
12491da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
12501da177e4SLinus Torvalds 	 */
12519529c788SRasmus Villemoes 	scontextp += sprintf(scontextp, "%s:%s:%s",
1252aa8e712cSStephen Smalley 		sym_name(p, SYM_USERS, context->user - 1),
1253aa8e712cSStephen Smalley 		sym_name(p, SYM_ROLES, context->role - 1),
1254aa8e712cSStephen Smalley 		sym_name(p, SYM_TYPES, context->type - 1));
12551da177e4SLinus Torvalds 
1256aa8e712cSStephen Smalley 	mls_sid_to_context(p, context, &scontextp);
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds 	*scontextp = 0;
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds 	return 0;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds 
sidtab_entry_to_string(struct policydb * p,struct sidtab * sidtab,struct sidtab_entry * entry,char ** scontext,u32 * scontext_len)1263d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *p,
1264d97bd23cSOndrej Mosnacek 				  struct sidtab *sidtab,
1265d97bd23cSOndrej Mosnacek 				  struct sidtab_entry *entry,
1266d97bd23cSOndrej Mosnacek 				  char **scontext, u32 *scontext_len)
1267d97bd23cSOndrej Mosnacek {
1268d97bd23cSOndrej Mosnacek 	int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
1269d97bd23cSOndrej Mosnacek 
1270d97bd23cSOndrej Mosnacek 	if (rc != -ENOENT)
1271d97bd23cSOndrej Mosnacek 		return rc;
1272d97bd23cSOndrej Mosnacek 
1273d97bd23cSOndrej Mosnacek 	rc = context_struct_to_string(p, &entry->context, scontext,
1274d97bd23cSOndrej Mosnacek 				      scontext_len);
1275d97bd23cSOndrej Mosnacek 	if (!rc && scontext)
1276d97bd23cSOndrej Mosnacek 		sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
1277d97bd23cSOndrej Mosnacek 	return rc;
1278d97bd23cSOndrej Mosnacek }
1279d97bd23cSOndrej Mosnacek 
12801da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12811da177e4SLinus Torvalds 
security_sidtab_hash_stats(char * page)1282e67b7985SStephen Smalley int security_sidtab_hash_stats(char *page)
128366f8e2f0SJeff Vander Stoep {
12841b8b31a2SStephen Smalley 	struct selinux_policy *policy;
128566f8e2f0SJeff Vander Stoep 	int rc;
128666f8e2f0SJeff Vander Stoep 
1287e67b7985SStephen Smalley 	if (!selinux_initialized()) {
128815b590a8SPaul Moore 		pr_err("SELinux: %s:  called before initial load_policy\n",
128915b590a8SPaul Moore 		       __func__);
129015b590a8SPaul Moore 		return -EINVAL;
129115b590a8SPaul Moore 	}
129215b590a8SPaul Moore 
12931b8b31a2SStephen Smalley 	rcu_read_lock();
1294e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
12951b8b31a2SStephen Smalley 	rc = sidtab_hash_stats(policy->sidtab, page);
12961b8b31a2SStephen Smalley 	rcu_read_unlock();
129766f8e2f0SJeff Vander Stoep 
129866f8e2f0SJeff Vander Stoep 	return rc;
129966f8e2f0SJeff Vander Stoep }
130066f8e2f0SJeff Vander Stoep 
security_get_initial_sid_context(u32 sid)1301f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1302f0ee2e46SJames Carter {
1303f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1304f0ee2e46SJames Carter 		return NULL;
1305f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1306f0ee2e46SJames Carter }
1307f0ee2e46SJames Carter 
security_sid_to_context_core(u32 sid,char ** scontext,u32 * scontext_len,int force,int only_invalid)1308e67b7985SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
1309fede1483SOndrej Mosnacek 					u32 *scontext_len, int force,
1310fede1483SOndrej Mosnacek 					int only_invalid)
13111da177e4SLinus Torvalds {
13121b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1313aa8e712cSStephen Smalley 	struct policydb *policydb;
1314aa8e712cSStephen Smalley 	struct sidtab *sidtab;
1315d97bd23cSOndrej Mosnacek 	struct sidtab_entry *entry;
13161da177e4SLinus Torvalds 	int rc = 0;
13171da177e4SLinus Torvalds 
1318d5630b9dSEric Paris 	if (scontext)
13194f4acf3aSStephen Smalley 		*scontext = NULL;
13204f4acf3aSStephen Smalley 	*scontext_len  = 0;
13214f4acf3aSStephen Smalley 
1322e67b7985SStephen Smalley 	if (!selinux_initialized()) {
13231da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
13241da177e4SLinus Torvalds 			char *scontextp;
1325e3e0b582SStephen Smalley 			const char *s = initial_sid_to_string[sid];
13261da177e4SLinus Torvalds 
1327e3e0b582SStephen Smalley 			if (!s)
1328e3e0b582SStephen Smalley 				return -EINVAL;
1329e3e0b582SStephen Smalley 			*scontext_len = strlen(s) + 1;
1330d5630b9dSEric Paris 			if (!scontext)
1331e3e0b582SStephen Smalley 				return 0;
1332e3e0b582SStephen Smalley 			scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
1333e3e0b582SStephen Smalley 			if (!scontextp)
1334e3e0b582SStephen Smalley 				return -ENOMEM;
13351da177e4SLinus Torvalds 			*scontext = scontextp;
1336e3e0b582SStephen Smalley 			return 0;
13371da177e4SLinus Torvalds 		}
1338b54c85c1Speter enderborg 		pr_err("SELinux: %s:  called before initial "
1339744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
1340e3e0b582SStephen Smalley 		return -EINVAL;
13411da177e4SLinus Torvalds 	}
13421b8b31a2SStephen Smalley 	rcu_read_lock();
1343e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
13441b8b31a2SStephen Smalley 	policydb = &policy->policydb;
13451b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1346d97bd23cSOndrej Mosnacek 
134712b29f34SStephen Smalley 	if (force)
1348d97bd23cSOndrej Mosnacek 		entry = sidtab_search_entry_force(sidtab, sid);
134912b29f34SStephen Smalley 	else
1350d97bd23cSOndrej Mosnacek 		entry = sidtab_search_entry(sidtab, sid);
1351d97bd23cSOndrej Mosnacek 	if (!entry) {
1352b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1353744ba35eSEric Paris 			__func__, sid);
13541da177e4SLinus Torvalds 		rc = -EINVAL;
13551da177e4SLinus Torvalds 		goto out_unlock;
13561da177e4SLinus Torvalds 	}
1357d97bd23cSOndrej Mosnacek 	if (only_invalid && !entry->context.len)
1358d97bd23cSOndrej Mosnacek 		goto out_unlock;
1359d97bd23cSOndrej Mosnacek 
1360d97bd23cSOndrej Mosnacek 	rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
1361aa8e712cSStephen Smalley 				    scontext_len);
1362d97bd23cSOndrej Mosnacek 
13631da177e4SLinus Torvalds out_unlock:
13641b8b31a2SStephen Smalley 	rcu_read_unlock();
13651da177e4SLinus Torvalds 	return rc;
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds 
136912b29f34SStephen Smalley /**
137012b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
137112b29f34SStephen Smalley  * @sid: security identifier, SID
137212b29f34SStephen Smalley  * @scontext: security context
137312b29f34SStephen Smalley  * @scontext_len: length in bytes
137412b29f34SStephen Smalley  *
137512b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
137612b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
137712b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
137812b29f34SStephen Smalley  */
security_sid_to_context(u32 sid,char ** scontext,u32 * scontext_len)1379e67b7985SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
13801da177e4SLinus Torvalds {
1381e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1382fede1483SOndrej Mosnacek 					    scontext_len, 0, 0);
138312b29f34SStephen Smalley }
138412b29f34SStephen Smalley 
security_sid_to_context_force(u32 sid,char ** scontext,u32 * scontext_len)1385e67b7985SStephen Smalley int security_sid_to_context_force(u32 sid,
1386aa8e712cSStephen Smalley 				  char **scontext, u32 *scontext_len)
138712b29f34SStephen Smalley {
1388e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1389fede1483SOndrej Mosnacek 					    scontext_len, 1, 0);
1390fede1483SOndrej Mosnacek }
1391fede1483SOndrej Mosnacek 
1392fede1483SOndrej Mosnacek /**
1393fede1483SOndrej Mosnacek  * security_sid_to_context_inval - Obtain a context for a given SID if it
1394fede1483SOndrej Mosnacek  *                                 is invalid.
1395fede1483SOndrej Mosnacek  * @sid: security identifier, SID
1396fede1483SOndrej Mosnacek  * @scontext: security context
1397fede1483SOndrej Mosnacek  * @scontext_len: length in bytes
1398fede1483SOndrej Mosnacek  *
1399fede1483SOndrej Mosnacek  * Write the string representation of the context associated with @sid
1400fede1483SOndrej Mosnacek  * into a dynamically allocated string of the correct size, but only if the
1401fede1483SOndrej Mosnacek  * context is invalid in the current policy.  Set @scontext to point to
1402fede1483SOndrej Mosnacek  * this string (or NULL if the context is valid) and set @scontext_len to
1403fede1483SOndrej Mosnacek  * the length of the string (or 0 if the context is valid).
1404fede1483SOndrej Mosnacek  */
security_sid_to_context_inval(u32 sid,char ** scontext,u32 * scontext_len)1405e67b7985SStephen Smalley int security_sid_to_context_inval(u32 sid,
1406fede1483SOndrej Mosnacek 				  char **scontext, u32 *scontext_len)
1407fede1483SOndrej Mosnacek {
1408e67b7985SStephen Smalley 	return security_sid_to_context_core(sid, scontext,
1409fede1483SOndrej Mosnacek 					    scontext_len, 1, 1);
141012b29f34SStephen Smalley }
141112b29f34SStephen Smalley 
14129a59daa0SStephen Smalley /*
14139a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
14149a59daa0SStephen Smalley  */
string_to_context_struct(struct policydb * pol,struct sidtab * sidtabp,char * scontext,struct context * ctx,u32 def_sid)141512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
141612b29f34SStephen Smalley 				    struct sidtab *sidtabp,
14179a59daa0SStephen Smalley 				    char *scontext,
141812b29f34SStephen Smalley 				    struct context *ctx,
14199a59daa0SStephen Smalley 				    u32 def_sid)
142012b29f34SStephen Smalley {
14211da177e4SLinus Torvalds 	struct role_datum *role;
14221da177e4SLinus Torvalds 	struct type_datum *typdatum;
14231da177e4SLinus Torvalds 	struct user_datum *usrdatum;
14241da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
14251da177e4SLinus Torvalds 	int rc = 0;
14261da177e4SLinus Torvalds 
142712b29f34SStephen Smalley 	context_init(ctx);
142812b29f34SStephen Smalley 
142912b29f34SStephen Smalley 	/* Parse the security context. */
143012b29f34SStephen Smalley 
143112b29f34SStephen Smalley 	rc = -EINVAL;
14320b3c2b3dSChristian Göttsche 	scontextp = scontext;
143312b29f34SStephen Smalley 
143412b29f34SStephen Smalley 	/* Extract the user. */
143512b29f34SStephen Smalley 	p = scontextp;
143612b29f34SStephen Smalley 	while (*p && *p != ':')
143712b29f34SStephen Smalley 		p++;
143812b29f34SStephen Smalley 
143912b29f34SStephen Smalley 	if (*p == 0)
144012b29f34SStephen Smalley 		goto out;
144112b29f34SStephen Smalley 
144212b29f34SStephen Smalley 	*p++ = 0;
144312b29f34SStephen Smalley 
1444237389e3SOndrej Mosnacek 	usrdatum = symtab_search(&pol->p_users, scontextp);
144512b29f34SStephen Smalley 	if (!usrdatum)
144612b29f34SStephen Smalley 		goto out;
144712b29f34SStephen Smalley 
144812b29f34SStephen Smalley 	ctx->user = usrdatum->value;
144912b29f34SStephen Smalley 
145012b29f34SStephen Smalley 	/* Extract role. */
145112b29f34SStephen Smalley 	scontextp = p;
145212b29f34SStephen Smalley 	while (*p && *p != ':')
145312b29f34SStephen Smalley 		p++;
145412b29f34SStephen Smalley 
145512b29f34SStephen Smalley 	if (*p == 0)
145612b29f34SStephen Smalley 		goto out;
145712b29f34SStephen Smalley 
145812b29f34SStephen Smalley 	*p++ = 0;
145912b29f34SStephen Smalley 
1460237389e3SOndrej Mosnacek 	role = symtab_search(&pol->p_roles, scontextp);
146112b29f34SStephen Smalley 	if (!role)
146212b29f34SStephen Smalley 		goto out;
146312b29f34SStephen Smalley 	ctx->role = role->value;
146412b29f34SStephen Smalley 
146512b29f34SStephen Smalley 	/* Extract type. */
146612b29f34SStephen Smalley 	scontextp = p;
146712b29f34SStephen Smalley 	while (*p && *p != ':')
146812b29f34SStephen Smalley 		p++;
146912b29f34SStephen Smalley 	oldc = *p;
147012b29f34SStephen Smalley 	*p++ = 0;
147112b29f34SStephen Smalley 
1472237389e3SOndrej Mosnacek 	typdatum = symtab_search(&pol->p_types, scontextp);
1473d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
147412b29f34SStephen Smalley 		goto out;
147512b29f34SStephen Smalley 
147612b29f34SStephen Smalley 	ctx->type = typdatum->value;
147712b29f34SStephen Smalley 
147895ffe194SJann Horn 	rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
147912b29f34SStephen Smalley 	if (rc)
148012b29f34SStephen Smalley 		goto out;
148112b29f34SStephen Smalley 
148212b29f34SStephen Smalley 	/* Check the validity of the new context. */
148395ffe194SJann Horn 	rc = -EINVAL;
14844b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
148512b29f34SStephen Smalley 		goto out;
148612b29f34SStephen Smalley 	rc = 0;
148712b29f34SStephen Smalley out:
14888e531af9SEric Paris 	if (rc)
14898e531af9SEric Paris 		context_destroy(ctx);
149012b29f34SStephen Smalley 	return rc;
149112b29f34SStephen Smalley }
149212b29f34SStephen Smalley 
security_context_to_sid_core(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags,int force)1493e67b7985SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
149412b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
149512b29f34SStephen Smalley 					int force)
149612b29f34SStephen Smalley {
14971b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1498aa8e712cSStephen Smalley 	struct policydb *policydb;
1499aa8e712cSStephen Smalley 	struct sidtab *sidtab;
15009a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
150112b29f34SStephen Smalley 	struct context context;
150212b29f34SStephen Smalley 	int rc = 0;
150312b29f34SStephen Smalley 
15042172fa70SStephen Smalley 	/* An empty security context is never valid. */
15052172fa70SStephen Smalley 	if (!scontext_len)
15062172fa70SStephen Smalley 		return -EINVAL;
15072172fa70SStephen Smalley 
1508ef28df55SPaul Moore 	/* Copy the string to allow changes and ensure a NUL terminator */
1509ef28df55SPaul Moore 	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1510ef28df55SPaul Moore 	if (!scontext2)
1511ef28df55SPaul Moore 		return -ENOMEM;
1512ef28df55SPaul Moore 
1513e67b7985SStephen Smalley 	if (!selinux_initialized()) {
1514c50e125dSChristian Göttsche 		u32 i;
15151da177e4SLinus Torvalds 
15161da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
1517e3e0b582SStephen Smalley 			const char *s = initial_sid_to_string[i];
1518e3e0b582SStephen Smalley 
1519e3e0b582SStephen Smalley 			if (s && !strcmp(s, scontext2)) {
15201da177e4SLinus Torvalds 				*sid = i;
1521ef28df55SPaul Moore 				goto out;
15221da177e4SLinus Torvalds 			}
15231da177e4SLinus Torvalds 		}
15241da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
1525ef28df55SPaul Moore 		goto out;
15261da177e4SLinus Torvalds 	}
15271da177e4SLinus Torvalds 	*sid = SECSID_NULL;
15281da177e4SLinus Torvalds 
15299a59daa0SStephen Smalley 	if (force) {
15309a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
15314b02b524SEric Paris 		rc = -ENOMEM;
15329a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
15334b02b524SEric Paris 		if (!str)
15344b02b524SEric Paris 			goto out;
15359a59daa0SStephen Smalley 	}
15369ad6e9cbSOndrej Mosnacek retry:
15371b8b31a2SStephen Smalley 	rcu_read_lock();
1538e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
15391b8b31a2SStephen Smalley 	policydb = &policy->policydb;
15401b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1541aa8e712cSStephen Smalley 	rc = string_to_context_struct(policydb, sidtab, scontext2,
154295ffe194SJann Horn 				      &context, def_sid);
154312b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
15449a59daa0SStephen Smalley 		context.str = str;
1545efe3de79SSachin Grover 		context.len = strlen(str) + 1;
15469a59daa0SStephen Smalley 		str = NULL;
154712b29f34SStephen Smalley 	} else if (rc)
15484b02b524SEric Paris 		goto out_unlock;
1549225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &context, sid);
15509ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
15519ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
15529ad6e9cbSOndrej Mosnacek 		if (context.str) {
15539ad6e9cbSOndrej Mosnacek 			str = context.str;
15549ad6e9cbSOndrej Mosnacek 			context.str = NULL;
15559ad6e9cbSOndrej Mosnacek 		}
15569ad6e9cbSOndrej Mosnacek 		context_destroy(&context);
15579ad6e9cbSOndrej Mosnacek 		goto retry;
15589ad6e9cbSOndrej Mosnacek 	}
15591da177e4SLinus Torvalds 	context_destroy(&context);
15604b02b524SEric Paris out_unlock:
15611b8b31a2SStephen Smalley 	rcu_read_unlock();
15624b02b524SEric Paris out:
15639a59daa0SStephen Smalley 	kfree(scontext2);
15649a59daa0SStephen Smalley 	kfree(str);
15651da177e4SLinus Torvalds 	return rc;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
1568f5c1d5b2SJames Morris /**
1569f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1570f5c1d5b2SJames Morris  * @scontext: security context
1571f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1572f5c1d5b2SJames Morris  * @sid: security identifier, SID
157352a4c640SNikolay Aleksandrov  * @gfp: context for the allocation
1574f5c1d5b2SJames Morris  *
1575f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1576f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1577f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1578f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1579f5c1d5b2SJames Morris  */
security_context_to_sid(const char * scontext,u32 scontext_len,u32 * sid,gfp_t gfp)1580e67b7985SStephen Smalley int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
158152a4c640SNikolay Aleksandrov 			    gfp_t gfp)
1582f5c1d5b2SJames Morris {
1583e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
158452a4c640SNikolay Aleksandrov 					    sid, SECSID_NULL, gfp, 0);
1585f5c1d5b2SJames Morris }
1586f5c1d5b2SJames Morris 
security_context_str_to_sid(const char * scontext,u32 * sid,gfp_t gfp)1587e67b7985SStephen Smalley int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
158844be2f65SRasmus Villemoes {
1589e67b7985SStephen Smalley 	return security_context_to_sid(scontext, strlen(scontext),
1590aa8e712cSStephen Smalley 				       sid, gfp);
159144be2f65SRasmus Villemoes }
159244be2f65SRasmus Villemoes 
1593f5c1d5b2SJames Morris /**
1594f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1595f5c1d5b2SJames Morris  * falling back to specified default if needed.
1596f5c1d5b2SJames Morris  *
1597f5c1d5b2SJames Morris  * @scontext: security context
1598f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1599f5c1d5b2SJames Morris  * @sid: security identifier, SID
1600d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1601e9fd7292SPaul Moore  * @gfp_flags: the allocator get-free-page (GFP) flags
1602f5c1d5b2SJames Morris  *
1603f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1604f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1605f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1606f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1607f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
160812b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1609f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1610f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1611f5c1d5b2SJames Morris  */
security_context_to_sid_default(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags)1612e67b7985SStephen Smalley int security_context_to_sid_default(const char *scontext, u32 scontext_len,
16137bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1614f5c1d5b2SJames Morris {
1615e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
161612b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
161712b29f34SStephen Smalley }
161812b29f34SStephen Smalley 
security_context_to_sid_force(const char * scontext,u32 scontext_len,u32 * sid)1619e67b7985SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
162012b29f34SStephen Smalley 				  u32 *sid)
162112b29f34SStephen Smalley {
1622e67b7985SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
162312b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1624f5c1d5b2SJames Morris }
1625f5c1d5b2SJames Morris 
compute_sid_handle_invalid_context(struct selinux_policy * policy,struct sidtab_entry * sentry,struct sidtab_entry * tentry,u16 tclass,struct context * newcontext)16261da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
16271b8b31a2SStephen Smalley 	struct selinux_policy *policy,
1628d97bd23cSOndrej Mosnacek 	struct sidtab_entry *sentry,
1629d97bd23cSOndrej Mosnacek 	struct sidtab_entry *tentry,
16301da177e4SLinus Torvalds 	u16 tclass,
16311da177e4SLinus Torvalds 	struct context *newcontext)
16321da177e4SLinus Torvalds {
16331b8b31a2SStephen Smalley 	struct policydb *policydb = &policy->policydb;
16341b8b31a2SStephen Smalley 	struct sidtab *sidtab = policy->sidtab;
16351da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
16361da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
1637ea74a685SRichard Guy Briggs 	struct audit_buffer *ab;
16381da177e4SLinus Torvalds 
1639d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
16401da177e4SLinus Torvalds 		goto out;
1641d97bd23cSOndrej Mosnacek 	if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
16421da177e4SLinus Torvalds 		goto out;
1643aa8e712cSStephen Smalley 	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
16441da177e4SLinus Torvalds 		goto out;
1645ea74a685SRichard Guy Briggs 	ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1646893c47d1SAustin Kim 	if (!ab)
1647893c47d1SAustin Kim 		goto out;
1648ea74a685SRichard Guy Briggs 	audit_log_format(ab,
1649ea74a685SRichard Guy Briggs 			 "op=security_compute_sid invalid_context=");
1650ea74a685SRichard Guy Briggs 	/* no need to record the NUL with untrusted strings */
1651ea74a685SRichard Guy Briggs 	audit_log_n_untrustedstring(ab, n, nlen - 1);
1652ea74a685SRichard Guy Briggs 	audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1653ea74a685SRichard Guy Briggs 			 s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1654ea74a685SRichard Guy Briggs 	audit_log_end(ab);
16551da177e4SLinus Torvalds out:
16561da177e4SLinus Torvalds 	kfree(s);
16571da177e4SLinus Torvalds 	kfree(t);
16581da177e4SLinus Torvalds 	kfree(n);
1659e67b7985SStephen Smalley 	if (!enforcing_enabled())
16601da177e4SLinus Torvalds 		return 0;
16611da177e4SLinus Torvalds 	return -EACCES;
16621da177e4SLinus Torvalds }
16631da177e4SLinus Torvalds 
filename_compute_type(struct policydb * policydb,struct context * newcontext,u32 stype,u32 ttype,u16 tclass,const char * objname)1664aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb,
1665aa8e712cSStephen Smalley 				  struct context *newcontext,
16662667991fSEric Paris 				  u32 stype, u32 ttype, u16 tclass,
1667f50a3ec9SKohei Kaigai 				  const char *objname)
1668652bb9b0SEric Paris {
1669c3a27611SOndrej Mosnacek 	struct filename_trans_key ft;
1670c3a27611SOndrej Mosnacek 	struct filename_trans_datum *datum;
167103a4c018SEric Paris 
167203a4c018SEric Paris 	/*
167303a4c018SEric Paris 	 * Most filename trans rules are going to live in specific directories
167403a4c018SEric Paris 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
167503a4c018SEric Paris 	 * if the ttype does not contain any rules.
167603a4c018SEric Paris 	 */
1677aa8e712cSStephen Smalley 	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1678652bb9b0SEric Paris 		return;
167903a4c018SEric Paris 
16802463c26dSEric Paris 	ft.ttype = ttype;
16812463c26dSEric Paris 	ft.tclass = tclass;
16822463c26dSEric Paris 	ft.name = objname;
16832463c26dSEric Paris 
168424def7bbSOndrej Mosnacek 	datum = policydb_filenametr_search(policydb, &ft);
1685c3a27611SOndrej Mosnacek 	while (datum) {
1686c3a27611SOndrej Mosnacek 		if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
1687c3a27611SOndrej Mosnacek 			newcontext->type = datum->otype;
1688c3a27611SOndrej Mosnacek 			return;
1689c3a27611SOndrej Mosnacek 		}
1690c3a27611SOndrej Mosnacek 		datum = datum->next;
1691c3a27611SOndrej Mosnacek 	}
1692652bb9b0SEric Paris }
1693652bb9b0SEric Paris 
security_compute_sid(u32 ssid,u32 tsid,u16 orig_tclass,u16 specified,const char * objname,u32 * out_sid,bool kern)1694e67b7985SStephen Smalley static int security_compute_sid(u32 ssid,
16951da177e4SLinus Torvalds 				u32 tsid,
1696c6d3aaa4SStephen Smalley 				u16 orig_tclass,
16977128578cSChristian Göttsche 				u16 specified,
1698f50a3ec9SKohei Kaigai 				const char *objname,
1699c6d3aaa4SStephen Smalley 				u32 *out_sid,
1700c6d3aaa4SStephen Smalley 				bool kern)
17011da177e4SLinus Torvalds {
17021b8b31a2SStephen Smalley 	struct selinux_policy *policy;
1703aa8e712cSStephen Smalley 	struct policydb *policydb;
1704aa8e712cSStephen Smalley 	struct sidtab *sidtab;
17059ad6e9cbSOndrej Mosnacek 	struct class_datum *cladatum;
1706d97bd23cSOndrej Mosnacek 	struct context *scontext, *tcontext, newcontext;
1707d97bd23cSOndrej Mosnacek 	struct sidtab_entry *sentry, *tentry;
17081da177e4SLinus Torvalds 	struct avtab_key avkey;
170908a12b39SChristian Göttsche 	struct avtab_node *avnode, *node;
1710c6d3aaa4SStephen Smalley 	u16 tclass;
17111da177e4SLinus Torvalds 	int rc = 0;
17126f5317e7SHarry Ciao 	bool sock;
17131da177e4SLinus Torvalds 
1714e67b7985SStephen Smalley 	if (!selinux_initialized()) {
1715c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1716c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
17171da177e4SLinus Torvalds 			*out_sid = ssid;
17181da177e4SLinus Torvalds 			break;
17191da177e4SLinus Torvalds 		default:
17201da177e4SLinus Torvalds 			*out_sid = tsid;
17211da177e4SLinus Torvalds 			break;
17221da177e4SLinus Torvalds 		}
17231da177e4SLinus Torvalds 		goto out;
17241da177e4SLinus Torvalds 	}
17251da177e4SLinus Torvalds 
17269ad6e9cbSOndrej Mosnacek retry:
17279ad6e9cbSOndrej Mosnacek 	cladatum = NULL;
1728851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1729851f8a69SVenkat Yekkirala 
17301b8b31a2SStephen Smalley 	rcu_read_lock();
17311b8b31a2SStephen Smalley 
1732e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
17331da177e4SLinus Torvalds 
17346f5317e7SHarry Ciao 	if (kern) {
17351b8b31a2SStephen Smalley 		tclass = unmap_class(&policy->map, orig_tclass);
17366f5317e7SHarry Ciao 		sock = security_is_socket_class(orig_tclass);
17376f5317e7SHarry Ciao 	} else {
1738c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
17391b8b31a2SStephen Smalley 		sock = security_is_socket_class(map_class(&policy->map,
1740aa8e712cSStephen Smalley 							  tclass));
17416f5317e7SHarry Ciao 	}
1742c6d3aaa4SStephen Smalley 
17431b8b31a2SStephen Smalley 	policydb = &policy->policydb;
17441b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
1745aa8e712cSStephen Smalley 
1746d97bd23cSOndrej Mosnacek 	sentry = sidtab_search_entry(sidtab, ssid);
1747d97bd23cSOndrej Mosnacek 	if (!sentry) {
1748b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1749744ba35eSEric Paris 		       __func__, ssid);
17501da177e4SLinus Torvalds 		rc = -EINVAL;
17511da177e4SLinus Torvalds 		goto out_unlock;
17521da177e4SLinus Torvalds 	}
1753d97bd23cSOndrej Mosnacek 	tentry = sidtab_search_entry(sidtab, tsid);
1754d97bd23cSOndrej Mosnacek 	if (!tentry) {
1755b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1756744ba35eSEric Paris 		       __func__, tsid);
17571da177e4SLinus Torvalds 		rc = -EINVAL;
17581da177e4SLinus Torvalds 		goto out_unlock;
17591da177e4SLinus Torvalds 	}
17601da177e4SLinus Torvalds 
1761d97bd23cSOndrej Mosnacek 	scontext = &sentry->context;
1762d97bd23cSOndrej Mosnacek 	tcontext = &tentry->context;
1763d97bd23cSOndrej Mosnacek 
1764aa8e712cSStephen Smalley 	if (tclass && tclass <= policydb->p_classes.nprim)
1765aa8e712cSStephen Smalley 		cladatum = policydb->class_val_to_struct[tclass - 1];
1766aa893269SEric Paris 
17671da177e4SLinus Torvalds 	/* Set the user identity. */
17681da177e4SLinus Torvalds 	switch (specified) {
17691da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
17701da177e4SLinus Torvalds 	case AVTAB_CHANGE:
1771aa893269SEric Paris 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1772aa893269SEric Paris 			newcontext.user = tcontext->user;
1773aa893269SEric Paris 		} else {
1774aa893269SEric Paris 			/* notice this gets both DEFAULT_SOURCE and unset */
17751da177e4SLinus Torvalds 			/* Use the process user identity. */
17761da177e4SLinus Torvalds 			newcontext.user = scontext->user;
1777aa893269SEric Paris 		}
17781da177e4SLinus Torvalds 		break;
17791da177e4SLinus Torvalds 	case AVTAB_MEMBER:
17801da177e4SLinus Torvalds 		/* Use the related object owner. */
17811da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
17821da177e4SLinus Torvalds 		break;
17831da177e4SLinus Torvalds 	}
17841da177e4SLinus Torvalds 
1785aa893269SEric Paris 	/* Set the role to default values. */
1786aa893269SEric Paris 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
17871da177e4SLinus Torvalds 		newcontext.role = scontext->role;
1788aa893269SEric Paris 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1789aa893269SEric Paris 		newcontext.role = tcontext->role;
1790aa893269SEric Paris 	} else {
17914b850396SZou Wei 		if ((tclass == policydb->process_class) || sock)
1792aa893269SEric Paris 			newcontext.role = scontext->role;
1793aa893269SEric Paris 		else
1794aa893269SEric Paris 			newcontext.role = OBJECT_R_VAL;
1795aa893269SEric Paris 	}
1796aa893269SEric Paris 
1797aa893269SEric Paris 	/* Set the type to default values. */
1798eed7795dSEric Paris 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1799eed7795dSEric Paris 		newcontext.type = scontext->type;
1800eed7795dSEric Paris 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1801eed7795dSEric Paris 		newcontext.type = tcontext->type;
1802eed7795dSEric Paris 	} else {
18034b850396SZou Wei 		if ((tclass == policydb->process_class) || sock) {
1804aa893269SEric Paris 			/* Use the type of process. */
18051da177e4SLinus Torvalds 			newcontext.type = scontext->type;
1806c6d3aaa4SStephen Smalley 		} else {
18071da177e4SLinus Torvalds 			/* Use the type of the related object. */
18081da177e4SLinus Torvalds 			newcontext.type = tcontext->type;
18091da177e4SLinus Torvalds 		}
1810eed7795dSEric Paris 	}
18111da177e4SLinus Torvalds 
18121da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
18131da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
18141da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
18151da177e4SLinus Torvalds 	avkey.target_class = tclass;
1816782ebb99SStephen Smalley 	avkey.specified = specified;
181708a12b39SChristian Göttsche 	avnode = avtab_search_node(&policydb->te_avtab, &avkey);
18181da177e4SLinus Torvalds 
18191da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
182008a12b39SChristian Göttsche 	if (!avnode) {
1821aa8e712cSStephen Smalley 		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1822dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1823782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
182408a12b39SChristian Göttsche 				avnode = node;
18251da177e4SLinus Torvalds 				break;
18261da177e4SLinus Torvalds 			}
18271da177e4SLinus Torvalds 		}
18281da177e4SLinus Torvalds 	}
18291da177e4SLinus Torvalds 
183008a12b39SChristian Göttsche 	if (avnode) {
18311da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
183208a12b39SChristian Göttsche 		newcontext.type = avnode->datum.u.data;
18331da177e4SLinus Torvalds 	}
18341da177e4SLinus Torvalds 
18354742600cSEric Paris 	/* if we have a objname this is a file trans check so check those rules */
1836f50a3ec9SKohei Kaigai 	if (objname)
1837aa8e712cSStephen Smalley 		filename_compute_type(policydb, &newcontext, scontext->type,
1838f50a3ec9SKohei Kaigai 				      tcontext->type, tclass, objname);
1839652bb9b0SEric Paris 
18401da177e4SLinus Torvalds 	/* Check for class-specific changes. */
18411da177e4SLinus Torvalds 	if (specified & AVTAB_TRANSITION) {
18421da177e4SLinus Torvalds 		/* Look for a role transition rule. */
1843e67b2ec9SOndrej Mosnacek 		struct role_trans_datum *rtd;
1844e67b2ec9SOndrej Mosnacek 		struct role_trans_key rtk = {
1845e67b2ec9SOndrej Mosnacek 			.role = scontext->role,
1846e67b2ec9SOndrej Mosnacek 			.type = tcontext->type,
1847e67b2ec9SOndrej Mosnacek 			.tclass = tclass,
1848e67b2ec9SOndrej Mosnacek 		};
1849e67b2ec9SOndrej Mosnacek 
185024def7bbSOndrej Mosnacek 		rtd = policydb_roletr_search(policydb, &rtk);
1851e67b2ec9SOndrej Mosnacek 		if (rtd)
1852e67b2ec9SOndrej Mosnacek 			newcontext.role = rtd->new_role;
18531da177e4SLinus Torvalds 	}
18541da177e4SLinus Torvalds 
18551da177e4SLinus Torvalds 	/* Set the MLS attributes.
18561da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
1857aa8e712cSStephen Smalley 	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
18586f5317e7SHarry Ciao 			     &newcontext, sock);
18591da177e4SLinus Torvalds 	if (rc)
18601da177e4SLinus Torvalds 		goto out_unlock;
18611da177e4SLinus Torvalds 
18621da177e4SLinus Torvalds 	/* Check the validity of the context. */
1863aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcontext)) {
1864e67b7985SStephen Smalley 		rc = compute_sid_handle_invalid_context(policy, sentry,
18651b8b31a2SStephen Smalley 							tentry, tclass,
18661b8b31a2SStephen Smalley 							&newcontext);
18671da177e4SLinus Torvalds 		if (rc)
18681da177e4SLinus Torvalds 			goto out_unlock;
18691da177e4SLinus Torvalds 	}
18701da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
1871225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
18729ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
18739ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
18749ad6e9cbSOndrej Mosnacek 		context_destroy(&newcontext);
18759ad6e9cbSOndrej Mosnacek 		goto retry;
18769ad6e9cbSOndrej Mosnacek 	}
18771da177e4SLinus Torvalds out_unlock:
18781b8b31a2SStephen Smalley 	rcu_read_unlock();
18791da177e4SLinus Torvalds 	context_destroy(&newcontext);
18801da177e4SLinus Torvalds out:
18811da177e4SLinus Torvalds 	return rc;
18821da177e4SLinus Torvalds }
18831da177e4SLinus Torvalds 
18841da177e4SLinus Torvalds /**
18851da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
18861da177e4SLinus Torvalds  * @ssid: source security identifier
18871da177e4SLinus Torvalds  * @tsid: target security identifier
18881da177e4SLinus Torvalds  * @tclass: target security class
1889e9fd7292SPaul Moore  * @qstr: object name
18901da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
18911da177e4SLinus Torvalds  *
18921da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
18931da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
18941da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18951da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
18961da177e4SLinus Torvalds  * computed successfully.
18971da177e4SLinus Torvalds  */
security_transition_sid(u32 ssid,u32 tsid,u16 tclass,const struct qstr * qstr,u32 * out_sid)1898e67b7985SStephen Smalley int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1899652bb9b0SEric Paris 			    const struct qstr *qstr, u32 *out_sid)
19001da177e4SLinus Torvalds {
1901e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1902aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1903f50a3ec9SKohei Kaigai 				    qstr ? qstr->name : NULL, out_sid, true);
1904c6d3aaa4SStephen Smalley }
1905c6d3aaa4SStephen Smalley 
security_transition_sid_user(u32 ssid,u32 tsid,u16 tclass,const char * objname,u32 * out_sid)1906e67b7985SStephen Smalley int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1907f50a3ec9SKohei Kaigai 				 const char *objname, u32 *out_sid)
1908c6d3aaa4SStephen Smalley {
1909e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1910aa8e712cSStephen Smalley 				    AVTAB_TRANSITION,
1911f50a3ec9SKohei Kaigai 				    objname, out_sid, false);
19121da177e4SLinus Torvalds }
19131da177e4SLinus Torvalds 
19141da177e4SLinus Torvalds /**
19151da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
19161da177e4SLinus Torvalds  * @ssid: source security identifier
19171da177e4SLinus Torvalds  * @tsid: target security identifier
19181da177e4SLinus Torvalds  * @tclass: target security class
19191da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
19201da177e4SLinus Torvalds  *
19211da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
19221da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
19231da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19241da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
19251da177e4SLinus Torvalds  * computed successfully.
19261da177e4SLinus Torvalds  */
security_member_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1927e67b7985SStephen Smalley int security_member_sid(u32 ssid,
19281da177e4SLinus Torvalds 			u32 tsid,
19291da177e4SLinus Torvalds 			u16 tclass,
19301da177e4SLinus Torvalds 			u32 *out_sid)
19311da177e4SLinus Torvalds {
1932e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass,
1933aa8e712cSStephen Smalley 				    AVTAB_MEMBER, NULL,
1934652bb9b0SEric Paris 				    out_sid, false);
19351da177e4SLinus Torvalds }
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds /**
19381da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
19391da177e4SLinus Torvalds  * @ssid: source security identifier
19401da177e4SLinus Torvalds  * @tsid: target security identifier
19411da177e4SLinus Torvalds  * @tclass: target security class
19421da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
19431da177e4SLinus Torvalds  *
19441da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
19451da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
19461da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19471da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
19481da177e4SLinus Torvalds  * computed successfully.
19491da177e4SLinus Torvalds  */
security_change_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1950e67b7985SStephen Smalley int security_change_sid(u32 ssid,
19511da177e4SLinus Torvalds 			u32 tsid,
19521da177e4SLinus Torvalds 			u16 tclass,
19531da177e4SLinus Torvalds 			u32 *out_sid)
19541da177e4SLinus Torvalds {
1955e67b7985SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1956652bb9b0SEric Paris 				    out_sid, false);
1957b94c7e67SChad Sellers }
1958b94c7e67SChad Sellers 
convert_context_handle_invalid_context(struct policydb * policydb,struct context * context)1959aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context(
19601b8b31a2SStephen Smalley 	struct policydb *policydb,
1961aa8e712cSStephen Smalley 	struct context *context)
19621da177e4SLinus Torvalds {
19631da177e4SLinus Torvalds 	char *s;
19641da177e4SLinus Torvalds 	u32 len;
19651da177e4SLinus Torvalds 
1966e67b7985SStephen Smalley 	if (enforcing_enabled())
19674b02b524SEric Paris 		return -EINVAL;
19684b02b524SEric Paris 
1969aa8e712cSStephen Smalley 	if (!context_struct_to_string(policydb, context, &s, &len)) {
1970b54c85c1Speter enderborg 		pr_warn("SELinux:  Context %s would be invalid if enforcing\n",
1971b54c85c1Speter enderborg 			s);
19721da177e4SLinus Torvalds 		kfree(s);
19731da177e4SLinus Torvalds 	}
19744b02b524SEric Paris 	return 0;
19751da177e4SLinus Torvalds }
19761da177e4SLinus Torvalds 
1977048be156SPaul Moore /**
1978048be156SPaul Moore  * services_convert_context - Convert a security context across policies.
1979048be156SPaul Moore  * @args: populated convert_context_args struct
1980048be156SPaul Moore  * @oldc: original context
1981048be156SPaul Moore  * @newc: converted context
198257888f7bSLinus Torvalds  * @gfp_flags: allocation flags
1983048be156SPaul Moore  *
1984048be156SPaul Moore  * Convert the values in the security context structure @oldc from the values
1985048be156SPaul Moore  * specified in the policy @args->oldp to the values specified in the policy
1986048be156SPaul Moore  * @args->newp, storing the new context in @newc, and verifying that the
1987048be156SPaul Moore  * context is valid under the new policy.
19881da177e4SLinus Torvalds  */
services_convert_context(struct convert_context_args * args,struct context * oldc,struct context * newc,gfp_t gfp_flags)1989048be156SPaul Moore int services_convert_context(struct convert_context_args *args,
199057888f7bSLinus Torvalds 			     struct context *oldc, struct context *newc,
1991abe3c631SGONG, Ruiqi 			     gfp_t gfp_flags)
19921da177e4SLinus Torvalds {
19930719aaf5SGuido Trentalancia 	struct ocontext *oc;
19941da177e4SLinus Torvalds 	struct role_datum *role;
19951da177e4SLinus Torvalds 	struct type_datum *typdatum;
19961da177e4SLinus Torvalds 	struct user_datum *usrdatum;
19971da177e4SLinus Torvalds 	char *s;
19981da177e4SLinus Torvalds 	u32 len;
199924ed7fdaSOndrej Mosnacek 	int rc;
20001da177e4SLinus Torvalds 
2001ee1a84fdSOndrej Mosnacek 	if (oldc->str) {
2002abe3c631SGONG, Ruiqi 		s = kstrdup(oldc->str, gfp_flags);
20034b02b524SEric Paris 		if (!s)
2004ee1a84fdSOndrej Mosnacek 			return -ENOMEM;
20054b02b524SEric Paris 
2006048be156SPaul Moore 		rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
2007ee1a84fdSOndrej Mosnacek 		if (rc == -EINVAL) {
20082a524393SOndrej Mosnacek 			/*
20092a524393SOndrej Mosnacek 			 * Retain string representation for later mapping.
20102a524393SOndrej Mosnacek 			 *
20112a524393SOndrej Mosnacek 			 * IMPORTANT: We need to copy the contents of oldc->str
20122a524393SOndrej Mosnacek 			 * back into s again because string_to_context_struct()
20132a524393SOndrej Mosnacek 			 * may have garbled it.
20142a524393SOndrej Mosnacek 			 */
20152a524393SOndrej Mosnacek 			memcpy(s, oldc->str, oldc->len);
2016ee1a84fdSOndrej Mosnacek 			context_init(newc);
2017ee1a84fdSOndrej Mosnacek 			newc->str = s;
2018ee1a84fdSOndrej Mosnacek 			newc->len = oldc->len;
2019ee1a84fdSOndrej Mosnacek 			return 0;
2020ee1a84fdSOndrej Mosnacek 		}
2021ee1a84fdSOndrej Mosnacek 		kfree(s);
2022ee1a84fdSOndrej Mosnacek 		if (rc) {
202312b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
2024b54c85c1Speter enderborg 			pr_err("SELinux:   Unable to map context %s, rc = %d.\n",
2025ee1a84fdSOndrej Mosnacek 			       oldc->str, -rc);
2026ee1a84fdSOndrej Mosnacek 			return rc;
202712b29f34SStephen Smalley 		}
2028ee1a84fdSOndrej Mosnacek 		pr_info("SELinux:  Context %s became valid (mapped).\n",
2029ee1a84fdSOndrej Mosnacek 			oldc->str);
2030ee1a84fdSOndrej Mosnacek 		return 0;
203112b29f34SStephen Smalley 	}
203212b29f34SStephen Smalley 
2033ee1a84fdSOndrej Mosnacek 	context_init(newc);
20341da177e4SLinus Torvalds 
20351da177e4SLinus Torvalds 	/* Convert the user. */
2036237389e3SOndrej Mosnacek 	usrdatum = symtab_search(&args->newp->p_users,
2037048be156SPaul Moore 				 sym_name(args->oldp, SYM_USERS, oldc->user - 1));
20385d55a345SEric Paris 	if (!usrdatum)
20391da177e4SLinus Torvalds 		goto bad;
2040ee1a84fdSOndrej Mosnacek 	newc->user = usrdatum->value;
20411da177e4SLinus Torvalds 
20421da177e4SLinus Torvalds 	/* Convert the role. */
2043237389e3SOndrej Mosnacek 	role = symtab_search(&args->newp->p_roles,
2044ee1a84fdSOndrej Mosnacek 			     sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
20455d55a345SEric Paris 	if (!role)
20461da177e4SLinus Torvalds 		goto bad;
2047ee1a84fdSOndrej Mosnacek 	newc->role = role->value;
20481da177e4SLinus Torvalds 
20491da177e4SLinus Torvalds 	/* Convert the type. */
2050237389e3SOndrej Mosnacek 	typdatum = symtab_search(&args->newp->p_types,
2051048be156SPaul Moore 				 sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
20525d55a345SEric Paris 	if (!typdatum)
20531da177e4SLinus Torvalds 		goto bad;
2054ee1a84fdSOndrej Mosnacek 	newc->type = typdatum->value;
20551da177e4SLinus Torvalds 
20560719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
20570719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2058ee1a84fdSOndrej Mosnacek 		rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
20591da177e4SLinus Torvalds 		if (rc)
20601da177e4SLinus Torvalds 			goto bad;
20610719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
20620719aaf5SGuido Trentalancia 		/*
20630719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
20640719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
20650719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
20660719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
20670719aaf5SGuido Trentalancia 		 * initial SIDs.
20680719aaf5SGuido Trentalancia 		 */
20690719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
20700719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
20710719aaf5SGuido Trentalancia 			oc = oc->next;
20720719aaf5SGuido Trentalancia 		if (!oc) {
2073b54c85c1Speter enderborg 			pr_err("SELinux:  unable to look up"
20740719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
20750719aaf5SGuido Trentalancia 			goto bad;
20760719aaf5SGuido Trentalancia 		}
2077ee1a84fdSOndrej Mosnacek 		rc = mls_range_set(newc, &oc->context[0].range);
20780719aaf5SGuido Trentalancia 		if (rc)
20790719aaf5SGuido Trentalancia 			goto bad;
20800719aaf5SGuido Trentalancia 	}
20811da177e4SLinus Torvalds 
20821da177e4SLinus Torvalds 	/* Check the validity of the new context. */
2083ee1a84fdSOndrej Mosnacek 	if (!policydb_context_isvalid(args->newp, newc)) {
2084e67b7985SStephen Smalley 		rc = convert_context_handle_invalid_context(args->oldp, oldc);
20851da177e4SLinus Torvalds 		if (rc)
20861da177e4SLinus Torvalds 			goto bad;
20871da177e4SLinus Torvalds 	}
20881da177e4SLinus Torvalds 
2089ee1a84fdSOndrej Mosnacek 	return 0;
20901da177e4SLinus Torvalds bad:
209112b29f34SStephen Smalley 	/* Map old representation to string and save it. */
2092ee1a84fdSOndrej Mosnacek 	rc = context_struct_to_string(args->oldp, oldc, &s, &len);
20934b02b524SEric Paris 	if (rc)
20944b02b524SEric Paris 		return rc;
2095ee1a84fdSOndrej Mosnacek 	context_destroy(newc);
2096ee1a84fdSOndrej Mosnacek 	newc->str = s;
2097ee1a84fdSOndrej Mosnacek 	newc->len = len;
2098b54c85c1Speter enderborg 	pr_info("SELinux:  Context %s became invalid (unmapped).\n",
2099ee1a84fdSOndrej Mosnacek 		newc->str);
2100ee1a84fdSOndrej Mosnacek 	return 0;
21011da177e4SLinus Torvalds }
21021da177e4SLinus Torvalds 
security_load_policycaps(struct selinux_policy * policy)2103e67b7985SStephen Smalley static void security_load_policycaps(struct selinux_policy *policy)
21043bb56b25SPaul Moore {
210546169802SStephen Smalley 	struct policydb *p;
21064dc2fce3SStephen Smalley 	unsigned int i;
21074dc2fce3SStephen Smalley 	struct ebitmap_node *node;
21084dc2fce3SStephen Smalley 
21091b8b31a2SStephen Smalley 	p = &policy->policydb;
211046169802SStephen Smalley 
2111e67b7985SStephen Smalley 	for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
2112e67b7985SStephen Smalley 		WRITE_ONCE(selinux_state.policycap[i],
2113e8ba53d0SStephen Smalley 			ebitmap_get_bit(&p->policycaps, i));
21144dc2fce3SStephen Smalley 
21154dc2fce3SStephen Smalley 	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
21164dc2fce3SStephen Smalley 		pr_info("SELinux:  policy capability %s=%d\n",
21174dc2fce3SStephen Smalley 			selinux_policycap_names[i],
2118aa8e712cSStephen Smalley 			ebitmap_get_bit(&p->policycaps, i));
21194dc2fce3SStephen Smalley 
2120aa8e712cSStephen Smalley 	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
21214dc2fce3SStephen Smalley 		if (i >= ARRAY_SIZE(selinux_policycap_names))
21224dc2fce3SStephen Smalley 			pr_info("SELinux:  unknown policy capability %u\n",
21234dc2fce3SStephen Smalley 				i);
21244dc2fce3SStephen Smalley 	}
21253bb56b25SPaul Moore }
21263bb56b25SPaul Moore 
21271b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
21281b8b31a2SStephen Smalley 				struct selinux_policy *newpolicy);
21291da177e4SLinus Torvalds 
selinux_policy_free(struct selinux_policy * policy)213046169802SStephen Smalley static void selinux_policy_free(struct selinux_policy *policy)
213146169802SStephen Smalley {
213246169802SStephen Smalley 	if (!policy)
213346169802SStephen Smalley 		return;
213446169802SStephen Smalley 
2135c7c556f1SStephen Smalley 	sidtab_destroy(policy->sidtab);
213646169802SStephen Smalley 	kfree(policy->map.mapping);
21370256b0aaSDan Carpenter 	policydb_destroy(&policy->policydb);
21380256b0aaSDan Carpenter 	kfree(policy->sidtab);
213946169802SStephen Smalley 	kfree(policy);
214046169802SStephen Smalley }
214146169802SStephen Smalley 
selinux_policy_cond_free(struct selinux_policy * policy)21421b8b31a2SStephen Smalley static void selinux_policy_cond_free(struct selinux_policy *policy)
21431b8b31a2SStephen Smalley {
21441b8b31a2SStephen Smalley 	cond_policydb_destroy_dup(&policy->policydb);
21451b8b31a2SStephen Smalley 	kfree(policy);
21461b8b31a2SStephen Smalley }
21471b8b31a2SStephen Smalley 
selinux_policy_cancel(struct selinux_load_state * load_state)2148e67b7985SStephen Smalley void selinux_policy_cancel(struct selinux_load_state *load_state)
214902a52c5cSStephen Smalley {
2150e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
21511b8b31a2SStephen Smalley 	struct selinux_policy *oldpolicy;
21521b8b31a2SStephen Smalley 
21539ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
21549ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
21551b8b31a2SStephen Smalley 
21561b8b31a2SStephen Smalley 	sidtab_cancel_convert(oldpolicy->sidtab);
21576406887aSOndrej Mosnacek 	selinux_policy_free(load_state->policy);
21586406887aSOndrej Mosnacek 	kfree(load_state->convert_data);
215902a52c5cSStephen Smalley }
216002a52c5cSStephen Smalley 
selinux_notify_policy_change(u32 seqno)2161e67b7985SStephen Smalley static void selinux_notify_policy_change(u32 seqno)
2162c7c556f1SStephen Smalley {
2163c7c556f1SStephen Smalley 	/* Flush external caches and notify userspace of policy load */
2164e67b7985SStephen Smalley 	avc_ss_reset(seqno);
2165c7c556f1SStephen Smalley 	selnl_notify_policyload(seqno);
2166e67b7985SStephen Smalley 	selinux_status_update_policyload(seqno);
2167c7c556f1SStephen Smalley 	selinux_netlbl_cache_invalidate();
2168c7c556f1SStephen Smalley 	selinux_xfrm_notify_policyload();
2169e67b7985SStephen Smalley 	selinux_ima_measure_state_locked();
2170c7c556f1SStephen Smalley }
2171c7c556f1SStephen Smalley 
selinux_policy_commit(struct selinux_load_state * load_state)2172e67b7985SStephen Smalley void selinux_policy_commit(struct selinux_load_state *load_state)
217346169802SStephen Smalley {
2174e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
21756406887aSOndrej Mosnacek 	struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
21769ad6e9cbSOndrej Mosnacek 	unsigned long flags;
217746169802SStephen Smalley 	u32 seqno;
217846169802SStephen Smalley 
21799ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
21809ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
218146169802SStephen Smalley 
218246169802SStephen Smalley 	/* If switching between different policy types, log MLS status */
218346169802SStephen Smalley 	if (oldpolicy) {
218446169802SStephen Smalley 		if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
218546169802SStephen Smalley 			pr_info("SELinux: Disabling MLS support...\n");
218646169802SStephen Smalley 		else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
218746169802SStephen Smalley 			pr_info("SELinux: Enabling MLS support...\n");
218846169802SStephen Smalley 	}
218946169802SStephen Smalley 
21901b8b31a2SStephen Smalley 	/* Set latest granting seqno for new policy. */
21911b8b31a2SStephen Smalley 	if (oldpolicy)
21921b8b31a2SStephen Smalley 		newpolicy->latest_granting = oldpolicy->latest_granting + 1;
21931b8b31a2SStephen Smalley 	else
21941b8b31a2SStephen Smalley 		newpolicy->latest_granting = 1;
21951b8b31a2SStephen Smalley 	seqno = newpolicy->latest_granting;
21961b8b31a2SStephen Smalley 
219746169802SStephen Smalley 	/* Install the new policy. */
21989ad6e9cbSOndrej Mosnacek 	if (oldpolicy) {
21999ad6e9cbSOndrej Mosnacek 		sidtab_freeze_begin(oldpolicy->sidtab, &flags);
22001b8b31a2SStephen Smalley 		rcu_assign_pointer(state->policy, newpolicy);
22019ad6e9cbSOndrej Mosnacek 		sidtab_freeze_end(oldpolicy->sidtab, &flags);
22029ad6e9cbSOndrej Mosnacek 	} else {
22039ad6e9cbSOndrej Mosnacek 		rcu_assign_pointer(state->policy, newpolicy);
22049ad6e9cbSOndrej Mosnacek 	}
220546169802SStephen Smalley 
220646169802SStephen Smalley 	/* Load the policycaps from the new policy */
2207e67b7985SStephen Smalley 	security_load_policycaps(newpolicy);
220846169802SStephen Smalley 
2209e67b7985SStephen Smalley 	if (!selinux_initialized()) {
221046169802SStephen Smalley 		/*
221146169802SStephen Smalley 		 * After first policy load, the security server is
221246169802SStephen Smalley 		 * marked as initialized and ready to handle requests and
221346169802SStephen Smalley 		 * any objects created prior to policy load are then labeled.
221446169802SStephen Smalley 		 */
2215e67b7985SStephen Smalley 		selinux_mark_initialized();
221646169802SStephen Smalley 		selinux_complete_init();
221746169802SStephen Smalley 	}
221846169802SStephen Smalley 
221946169802SStephen Smalley 	/* Free the old policy */
22201b8b31a2SStephen Smalley 	synchronize_rcu();
222146169802SStephen Smalley 	selinux_policy_free(oldpolicy);
22226406887aSOndrej Mosnacek 	kfree(load_state->convert_data);
222346169802SStephen Smalley 
2224c7c556f1SStephen Smalley 	/* Notify others of the policy change */
2225e67b7985SStephen Smalley 	selinux_notify_policy_change(seqno);
222646169802SStephen Smalley }
222746169802SStephen Smalley 
22281da177e4SLinus Torvalds /**
22291da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
22301da177e4SLinus Torvalds  * @data: binary policy data
22311da177e4SLinus Torvalds  * @len: length of data in bytes
2232e9fd7292SPaul Moore  * @load_state: policy load state
22331da177e4SLinus Torvalds  *
22341da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
22351da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
22361da177e4SLinus Torvalds  * This function will flush the access vector cache after
22371da177e4SLinus Torvalds  * loading the new policy.
22381da177e4SLinus Torvalds  */
security_load_policy(void * data,size_t len,struct selinux_load_state * load_state)2239e67b7985SStephen Smalley int security_load_policy(void *data, size_t len,
22406406887aSOndrej Mosnacek 			 struct selinux_load_state *load_state)
22411da177e4SLinus Torvalds {
2242e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
22431b8b31a2SStephen Smalley 	struct selinux_policy *newpolicy, *oldpolicy;
22446406887aSOndrej Mosnacek 	struct selinux_policy_convert_data *convert_data;
22451da177e4SLinus Torvalds 	int rc = 0;
22461da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
22471da177e4SLinus Torvalds 
224846169802SStephen Smalley 	newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
224946169802SStephen Smalley 	if (!newpolicy)
2250dd89b9d9SOndrej Mosnacek 		return -ENOMEM;
2251aa8e712cSStephen Smalley 
2252c7c556f1SStephen Smalley 	newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
22530256b0aaSDan Carpenter 	if (!newpolicy->sidtab) {
22540256b0aaSDan Carpenter 		rc = -ENOMEM;
22550256b0aaSDan Carpenter 		goto err_policy;
22560256b0aaSDan Carpenter 	}
2257c7c556f1SStephen Smalley 
225846169802SStephen Smalley 	rc = policydb_read(&newpolicy->policydb, fp);
2259a2000050SEric Paris 	if (rc)
22600256b0aaSDan Carpenter 		goto err_sidtab;
2261b94c7e67SChad Sellers 
226246169802SStephen Smalley 	newpolicy->policydb.len = len;
226346169802SStephen Smalley 	rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
226446169802SStephen Smalley 				&newpolicy->map);
226546169802SStephen Smalley 	if (rc)
22660256b0aaSDan Carpenter 		goto err_policydb;
226746169802SStephen Smalley 
2268c7c556f1SStephen Smalley 	rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
226946169802SStephen Smalley 	if (rc) {
227046169802SStephen Smalley 		pr_err("SELinux:  unable to load the initial SIDs\n");
22710256b0aaSDan Carpenter 		goto err_mapping;
227246169802SStephen Smalley 	}
227346169802SStephen Smalley 
2274e67b7985SStephen Smalley 	if (!selinux_initialized()) {
227546169802SStephen Smalley 		/* First policy load, so no need to preserve state from old policy */
22766406887aSOndrej Mosnacek 		load_state->policy = newpolicy;
22776406887aSOndrej Mosnacek 		load_state->convert_data = NULL;
227846169802SStephen Smalley 		return 0;
227946169802SStephen Smalley 	}
228046169802SStephen Smalley 
22819ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
22829ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
22831b8b31a2SStephen Smalley 
228446169802SStephen Smalley 	/* Preserve active boolean values from the old policy */
22851b8b31a2SStephen Smalley 	rc = security_preserve_bools(oldpolicy, newpolicy);
2286e900a7d9SStephen Smalley 	if (rc) {
2287b54c85c1Speter enderborg 		pr_err("SELinux:  unable to preserve booleans\n");
22880256b0aaSDan Carpenter 		goto err_free_isids;
2289e900a7d9SStephen Smalley 	}
2290e900a7d9SStephen Smalley 
2291048be156SPaul Moore 	/*
2292048be156SPaul Moore 	 * Convert the internal representations of contexts
2293048be156SPaul Moore 	 * in the new SID table.
2294048be156SPaul Moore 	 */
2295048be156SPaul Moore 
22966406887aSOndrej Mosnacek 	convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
22976406887aSOndrej Mosnacek 	if (!convert_data) {
22986406887aSOndrej Mosnacek 		rc = -ENOMEM;
22996406887aSOndrej Mosnacek 		goto err_free_isids;
23006406887aSOndrej Mosnacek 	}
23016406887aSOndrej Mosnacek 
23026406887aSOndrej Mosnacek 	convert_data->args.oldp = &oldpolicy->policydb;
23036406887aSOndrej Mosnacek 	convert_data->args.newp = &newpolicy->policydb;
2304ee1a84fdSOndrej Mosnacek 
23056406887aSOndrej Mosnacek 	convert_data->sidtab_params.args = &convert_data->args;
23066406887aSOndrej Mosnacek 	convert_data->sidtab_params.target = newpolicy->sidtab;
2307ee1a84fdSOndrej Mosnacek 
23086406887aSOndrej Mosnacek 	rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
23090719aaf5SGuido Trentalancia 	if (rc) {
2310b54c85c1Speter enderborg 		pr_err("SELinux:  unable to convert the internal"
23110719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
23120719aaf5SGuido Trentalancia 			" table\n");
23136406887aSOndrej Mosnacek 		goto err_free_convert_data;
23140719aaf5SGuido Trentalancia 	}
23151da177e4SLinus Torvalds 
23166406887aSOndrej Mosnacek 	load_state->policy = newpolicy;
23176406887aSOndrej Mosnacek 	load_state->convert_data = convert_data;
231846169802SStephen Smalley 	return 0;
23190256b0aaSDan Carpenter 
23206406887aSOndrej Mosnacek err_free_convert_data:
23216406887aSOndrej Mosnacek 	kfree(convert_data);
23220256b0aaSDan Carpenter err_free_isids:
23230256b0aaSDan Carpenter 	sidtab_destroy(newpolicy->sidtab);
23240256b0aaSDan Carpenter err_mapping:
23250256b0aaSDan Carpenter 	kfree(newpolicy->map.mapping);
23260256b0aaSDan Carpenter err_policydb:
23270256b0aaSDan Carpenter 	policydb_destroy(&newpolicy->policydb);
23280256b0aaSDan Carpenter err_sidtab:
23290256b0aaSDan Carpenter 	kfree(newpolicy->sidtab);
23300256b0aaSDan Carpenter err_policy:
23310256b0aaSDan Carpenter 	kfree(newpolicy);
23320256b0aaSDan Carpenter 
2333b5495b42STim Gardner 	return rc;
23341da177e4SLinus Torvalds }
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds /**
2337cbfcd13bSOndrej Mosnacek  * ocontext_to_sid - Helper to safely get sid for an ocontext
2338cbfcd13bSOndrej Mosnacek  * @sidtab: SID table
2339cbfcd13bSOndrej Mosnacek  * @c: ocontext structure
2340cbfcd13bSOndrej Mosnacek  * @index: index of the context entry (0 or 1)
2341cbfcd13bSOndrej Mosnacek  * @out_sid: pointer to the resulting SID value
2342cbfcd13bSOndrej Mosnacek  *
2343cbfcd13bSOndrej Mosnacek  * For all ocontexts except OCON_ISID the SID fields are populated
2344cbfcd13bSOndrej Mosnacek  * on-demand when needed. Since updating the SID value is an SMP-sensitive
2345cbfcd13bSOndrej Mosnacek  * operation, this helper must be used to do that safely.
2346cbfcd13bSOndrej Mosnacek  *
2347cbfcd13bSOndrej Mosnacek  * WARNING: This function may return -ESTALE, indicating that the caller
2348cbfcd13bSOndrej Mosnacek  * must retry the operation after re-acquiring the policy pointer!
2349cbfcd13bSOndrej Mosnacek  */
ocontext_to_sid(struct sidtab * sidtab,struct ocontext * c,size_t index,u32 * out_sid)2350cbfcd13bSOndrej Mosnacek static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
2351cbfcd13bSOndrej Mosnacek 			   size_t index, u32 *out_sid)
2352cbfcd13bSOndrej Mosnacek {
2353cbfcd13bSOndrej Mosnacek 	int rc;
2354cbfcd13bSOndrej Mosnacek 	u32 sid;
2355cbfcd13bSOndrej Mosnacek 
2356cbfcd13bSOndrej Mosnacek 	/* Ensure the associated sidtab entry is visible to this thread. */
2357cbfcd13bSOndrej Mosnacek 	sid = smp_load_acquire(&c->sid[index]);
2358cbfcd13bSOndrej Mosnacek 	if (!sid) {
2359cbfcd13bSOndrej Mosnacek 		rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
2360cbfcd13bSOndrej Mosnacek 		if (rc)
2361cbfcd13bSOndrej Mosnacek 			return rc;
2362cbfcd13bSOndrej Mosnacek 
2363cbfcd13bSOndrej Mosnacek 		/*
2364cbfcd13bSOndrej Mosnacek 		 * Ensure the new sidtab entry is visible to other threads
2365cbfcd13bSOndrej Mosnacek 		 * when they see the SID.
2366cbfcd13bSOndrej Mosnacek 		 */
2367cbfcd13bSOndrej Mosnacek 		smp_store_release(&c->sid[index], sid);
2368cbfcd13bSOndrej Mosnacek 	}
2369cbfcd13bSOndrej Mosnacek 	*out_sid = sid;
2370cbfcd13bSOndrej Mosnacek 	return 0;
2371cbfcd13bSOndrej Mosnacek }
2372cbfcd13bSOndrej Mosnacek 
2373cbfcd13bSOndrej Mosnacek /**
23741da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
23751da177e4SLinus Torvalds  * @protocol: protocol number
23761da177e4SLinus Torvalds  * @port: port number
23771da177e4SLinus Torvalds  * @out_sid: security identifier
23781da177e4SLinus Torvalds  */
security_port_sid(u8 protocol,u16 port,u32 * out_sid)2379e67b7985SStephen Smalley int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
23801da177e4SLinus Torvalds {
23811b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2382aa8e712cSStephen Smalley 	struct policydb *policydb;
2383225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
23841da177e4SLinus Torvalds 	struct ocontext *c;
23859ad6e9cbSOndrej Mosnacek 	int rc;
23861da177e4SLinus Torvalds 
2387e67b7985SStephen Smalley 	if (!selinux_initialized()) {
238837ea433cSStephen Smalley 		*out_sid = SECINITSID_PORT;
238937ea433cSStephen Smalley 		return 0;
239037ea433cSStephen Smalley 	}
239137ea433cSStephen Smalley 
23929ad6e9cbSOndrej Mosnacek retry:
23939ad6e9cbSOndrej Mosnacek 	rc = 0;
23941b8b31a2SStephen Smalley 	rcu_read_lock();
2395e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
23961b8b31a2SStephen Smalley 	policydb = &policy->policydb;
23971b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2398aa8e712cSStephen Smalley 
2399aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_PORT];
24001da177e4SLinus Torvalds 	while (c) {
24011da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
24021da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
24031da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
24041da177e4SLinus Torvalds 			break;
24051da177e4SLinus Torvalds 		c = c->next;
24061da177e4SLinus Torvalds 	}
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds 	if (c) {
2409cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24109ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
24119ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
24129ad6e9cbSOndrej Mosnacek 			goto retry;
24139ad6e9cbSOndrej Mosnacek 		}
24141da177e4SLinus Torvalds 		if (rc)
24151da177e4SLinus Torvalds 			goto out;
24161da177e4SLinus Torvalds 	} else {
24171da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
24181da177e4SLinus Torvalds 	}
24191da177e4SLinus Torvalds 
24201da177e4SLinus Torvalds out:
24211b8b31a2SStephen Smalley 	rcu_read_unlock();
24221da177e4SLinus Torvalds 	return rc;
24231da177e4SLinus Torvalds }
24241da177e4SLinus Torvalds 
24251da177e4SLinus Torvalds /**
2426d0a83314SYang Li  * security_ib_pkey_sid - Obtain the SID for a pkey.
2427cfc4d882SDaniel Jurgens  * @subnet_prefix: Subnet Prefix
2428cfc4d882SDaniel Jurgens  * @pkey_num: pkey number
2429cfc4d882SDaniel Jurgens  * @out_sid: security identifier
2430cfc4d882SDaniel Jurgens  */
security_ib_pkey_sid(u64 subnet_prefix,u16 pkey_num,u32 * out_sid)2431e67b7985SStephen Smalley int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2432cfc4d882SDaniel Jurgens {
24331b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2434aa8e712cSStephen Smalley 	struct policydb *policydb;
2435225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
2436cfc4d882SDaniel Jurgens 	struct ocontext *c;
24379ad6e9cbSOndrej Mosnacek 	int rc;
2438cfc4d882SDaniel Jurgens 
2439e67b7985SStephen Smalley 	if (!selinux_initialized()) {
244037ea433cSStephen Smalley 		*out_sid = SECINITSID_UNLABELED;
244137ea433cSStephen Smalley 		return 0;
244237ea433cSStephen Smalley 	}
244337ea433cSStephen Smalley 
24449ad6e9cbSOndrej Mosnacek retry:
24459ad6e9cbSOndrej Mosnacek 	rc = 0;
24461b8b31a2SStephen Smalley 	rcu_read_lock();
2447e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
24481b8b31a2SStephen Smalley 	policydb = &policy->policydb;
24491b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2450aa8e712cSStephen Smalley 
2451aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBPKEY];
2452cfc4d882SDaniel Jurgens 	while (c) {
2453cfc4d882SDaniel Jurgens 		if (c->u.ibpkey.low_pkey <= pkey_num &&
2454cfc4d882SDaniel Jurgens 		    c->u.ibpkey.high_pkey >= pkey_num &&
2455cfc4d882SDaniel Jurgens 		    c->u.ibpkey.subnet_prefix == subnet_prefix)
2456cfc4d882SDaniel Jurgens 			break;
2457cfc4d882SDaniel Jurgens 
2458cfc4d882SDaniel Jurgens 		c = c->next;
2459cfc4d882SDaniel Jurgens 	}
2460cfc4d882SDaniel Jurgens 
2461cfc4d882SDaniel Jurgens 	if (c) {
2462cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24639ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
24649ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
24659ad6e9cbSOndrej Mosnacek 			goto retry;
24669ad6e9cbSOndrej Mosnacek 		}
2467cfc4d882SDaniel Jurgens 		if (rc)
2468cfc4d882SDaniel Jurgens 			goto out;
2469cfc4d882SDaniel Jurgens 	} else
2470cfc4d882SDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2471cfc4d882SDaniel Jurgens 
2472cfc4d882SDaniel Jurgens out:
24731b8b31a2SStephen Smalley 	rcu_read_unlock();
2474cfc4d882SDaniel Jurgens 	return rc;
2475cfc4d882SDaniel Jurgens }
2476cfc4d882SDaniel Jurgens 
2477cfc4d882SDaniel Jurgens /**
2478ab861dfcSDaniel Jurgens  * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2479ab861dfcSDaniel Jurgens  * @dev_name: device name
2480e9fd7292SPaul Moore  * @port_num: port number
2481ab861dfcSDaniel Jurgens  * @out_sid: security identifier
2482ab861dfcSDaniel Jurgens  */
security_ib_endport_sid(const char * dev_name,u8 port_num,u32 * out_sid)2483e67b7985SStephen Smalley int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
2484ab861dfcSDaniel Jurgens {
24851b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2486aa8e712cSStephen Smalley 	struct policydb *policydb;
2487225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
2488ab861dfcSDaniel Jurgens 	struct ocontext *c;
24899ad6e9cbSOndrej Mosnacek 	int rc;
2490ab861dfcSDaniel Jurgens 
2491e67b7985SStephen Smalley 	if (!selinux_initialized()) {
249237ea433cSStephen Smalley 		*out_sid = SECINITSID_UNLABELED;
249337ea433cSStephen Smalley 		return 0;
249437ea433cSStephen Smalley 	}
249537ea433cSStephen Smalley 
24969ad6e9cbSOndrej Mosnacek retry:
24979ad6e9cbSOndrej Mosnacek 	rc = 0;
24981b8b31a2SStephen Smalley 	rcu_read_lock();
2499e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
25001b8b31a2SStephen Smalley 	policydb = &policy->policydb;
25011b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2502aa8e712cSStephen Smalley 
2503aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_IBENDPORT];
2504ab861dfcSDaniel Jurgens 	while (c) {
2505ab861dfcSDaniel Jurgens 		if (c->u.ibendport.port == port_num &&
2506ab861dfcSDaniel Jurgens 		    !strncmp(c->u.ibendport.dev_name,
2507ab861dfcSDaniel Jurgens 			     dev_name,
2508ab861dfcSDaniel Jurgens 			     IB_DEVICE_NAME_MAX))
2509ab861dfcSDaniel Jurgens 			break;
2510ab861dfcSDaniel Jurgens 
2511ab861dfcSDaniel Jurgens 		c = c->next;
2512ab861dfcSDaniel Jurgens 	}
2513ab861dfcSDaniel Jurgens 
2514ab861dfcSDaniel Jurgens 	if (c) {
2515cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
25169ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
25179ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
25189ad6e9cbSOndrej Mosnacek 			goto retry;
25199ad6e9cbSOndrej Mosnacek 		}
2520ab861dfcSDaniel Jurgens 		if (rc)
2521ab861dfcSDaniel Jurgens 			goto out;
2522ab861dfcSDaniel Jurgens 	} else
2523ab861dfcSDaniel Jurgens 		*out_sid = SECINITSID_UNLABELED;
2524ab861dfcSDaniel Jurgens 
2525ab861dfcSDaniel Jurgens out:
25261b8b31a2SStephen Smalley 	rcu_read_unlock();
2527ab861dfcSDaniel Jurgens 	return rc;
2528ab861dfcSDaniel Jurgens }
2529ab861dfcSDaniel Jurgens 
2530ab861dfcSDaniel Jurgens /**
25311da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
25321da177e4SLinus Torvalds  * @name: interface name
25331da177e4SLinus Torvalds  * @if_sid: interface SID
25341da177e4SLinus Torvalds  */
security_netif_sid(char * name,u32 * if_sid)2535e67b7985SStephen Smalley int security_netif_sid(char *name, u32 *if_sid)
25361da177e4SLinus Torvalds {
25371b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2538aa8e712cSStephen Smalley 	struct policydb *policydb;
2539225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
25409ad6e9cbSOndrej Mosnacek 	int rc;
25411da177e4SLinus Torvalds 	struct ocontext *c;
25421da177e4SLinus Torvalds 
2543e67b7985SStephen Smalley 	if (!selinux_initialized()) {
254437ea433cSStephen Smalley 		*if_sid = SECINITSID_NETIF;
254537ea433cSStephen Smalley 		return 0;
254637ea433cSStephen Smalley 	}
254737ea433cSStephen Smalley 
25489ad6e9cbSOndrej Mosnacek retry:
25499ad6e9cbSOndrej Mosnacek 	rc = 0;
25501b8b31a2SStephen Smalley 	rcu_read_lock();
2551e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
25521b8b31a2SStephen Smalley 	policydb = &policy->policydb;
25531b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2554aa8e712cSStephen Smalley 
2555aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_NETIF];
25561da177e4SLinus Torvalds 	while (c) {
25571da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
25581da177e4SLinus Torvalds 			break;
25591da177e4SLinus Torvalds 		c = c->next;
25601da177e4SLinus Torvalds 	}
25611da177e4SLinus Torvalds 
25621da177e4SLinus Torvalds 	if (c) {
2563cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, if_sid);
25649ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
25659ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
25669ad6e9cbSOndrej Mosnacek 			goto retry;
25679ad6e9cbSOndrej Mosnacek 		}
25681da177e4SLinus Torvalds 		if (rc)
25691da177e4SLinus Torvalds 			goto out;
2570e8bfdb9dSPaul Moore 	} else
25711da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
25721da177e4SLinus Torvalds 
25731da177e4SLinus Torvalds out:
25741b8b31a2SStephen Smalley 	rcu_read_unlock();
25751da177e4SLinus Torvalds 	return rc;
25761da177e4SLinus Torvalds }
25771da177e4SLinus Torvalds 
match_ipv6_addrmask(u32 * input,u32 * addr,u32 * mask)25781da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
25791da177e4SLinus Torvalds {
25801da177e4SLinus Torvalds 	int i, fail = 0;
25811da177e4SLinus Torvalds 
25821da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
25831da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
25841da177e4SLinus Torvalds 			fail = 1;
25851da177e4SLinus Torvalds 			break;
25861da177e4SLinus Torvalds 		}
25871da177e4SLinus Torvalds 
25881da177e4SLinus Torvalds 	return !fail;
25891da177e4SLinus Torvalds }
25901da177e4SLinus Torvalds 
25911da177e4SLinus Torvalds /**
25921da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
25931da177e4SLinus Torvalds  * @domain: communication domain aka address family
25941da177e4SLinus Torvalds  * @addrp: address
25951da177e4SLinus Torvalds  * @addrlen: address length in bytes
25961da177e4SLinus Torvalds  * @out_sid: security identifier
25971da177e4SLinus Torvalds  */
security_node_sid(u16 domain,void * addrp,u32 addrlen,u32 * out_sid)2598e67b7985SStephen Smalley int security_node_sid(u16 domain,
25991da177e4SLinus Torvalds 		      void *addrp,
26001da177e4SLinus Torvalds 		      u32 addrlen,
26011da177e4SLinus Torvalds 		      u32 *out_sid)
26021da177e4SLinus Torvalds {
26031b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2604aa8e712cSStephen Smalley 	struct policydb *policydb;
2605225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
26064b02b524SEric Paris 	int rc;
26071da177e4SLinus Torvalds 	struct ocontext *c;
26081da177e4SLinus Torvalds 
2609e67b7985SStephen Smalley 	if (!selinux_initialized()) {
261037ea433cSStephen Smalley 		*out_sid = SECINITSID_NODE;
261137ea433cSStephen Smalley 		return 0;
261237ea433cSStephen Smalley 	}
261337ea433cSStephen Smalley 
26149ad6e9cbSOndrej Mosnacek retry:
26151b8b31a2SStephen Smalley 	rcu_read_lock();
2616e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
26171b8b31a2SStephen Smalley 	policydb = &policy->policydb;
26181b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
26191da177e4SLinus Torvalds 
26201da177e4SLinus Torvalds 	switch (domain) {
26211da177e4SLinus Torvalds 	case AF_INET: {
26221da177e4SLinus Torvalds 		u32 addr;
26231da177e4SLinus Torvalds 
26241da177e4SLinus Torvalds 		rc = -EINVAL;
26254b02b524SEric Paris 		if (addrlen != sizeof(u32))
26261da177e4SLinus Torvalds 			goto out;
26271da177e4SLinus Torvalds 
26281da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
26291da177e4SLinus Torvalds 
2630aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE];
26311da177e4SLinus Torvalds 		while (c) {
26321da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
26331da177e4SLinus Torvalds 				break;
26341da177e4SLinus Torvalds 			c = c->next;
26351da177e4SLinus Torvalds 		}
26361da177e4SLinus Torvalds 		break;
26371da177e4SLinus Torvalds 	}
26381da177e4SLinus Torvalds 
26391da177e4SLinus Torvalds 	case AF_INET6:
26401da177e4SLinus Torvalds 		rc = -EINVAL;
26414b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
26421da177e4SLinus Torvalds 			goto out;
2643aa8e712cSStephen Smalley 		c = policydb->ocontexts[OCON_NODE6];
26441da177e4SLinus Torvalds 		while (c) {
26451da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
26461da177e4SLinus Torvalds 						c->u.node6.mask))
26471da177e4SLinus Torvalds 				break;
26481da177e4SLinus Torvalds 			c = c->next;
26491da177e4SLinus Torvalds 		}
26501da177e4SLinus Torvalds 		break;
26511da177e4SLinus Torvalds 
26521da177e4SLinus Torvalds 	default:
26534b02b524SEric Paris 		rc = 0;
26541da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
26551da177e4SLinus Torvalds 		goto out;
26561da177e4SLinus Torvalds 	}
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds 	if (c) {
2659cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
26609ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
26619ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
26629ad6e9cbSOndrej Mosnacek 			goto retry;
26639ad6e9cbSOndrej Mosnacek 		}
26641da177e4SLinus Torvalds 		if (rc)
26651da177e4SLinus Torvalds 			goto out;
26661da177e4SLinus Torvalds 	} else {
26671da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
26681da177e4SLinus Torvalds 	}
26691da177e4SLinus Torvalds 
26704b02b524SEric Paris 	rc = 0;
26711da177e4SLinus Torvalds out:
26721b8b31a2SStephen Smalley 	rcu_read_unlock();
26731da177e4SLinus Torvalds 	return rc;
26741da177e4SLinus Torvalds }
26751da177e4SLinus Torvalds 
26761da177e4SLinus Torvalds #define SIDS_NEL 25
26771da177e4SLinus Torvalds 
26781da177e4SLinus Torvalds /**
26791da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
26801da177e4SLinus Torvalds  * @fromsid: starting SID
26811da177e4SLinus Torvalds  * @username: username
26821da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
26831da177e4SLinus Torvalds  * @nel: number of elements in @sids
26841da177e4SLinus Torvalds  *
26851da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
26861da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
26871da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
26881da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
26891da177e4SLinus Torvalds  * number of elements in the array.
26901da177e4SLinus Torvalds  */
26911da177e4SLinus Torvalds 
security_get_user_sids(u32 fromsid,char * username,u32 ** sids,u32 * nel)2692e67b7985SStephen Smalley int security_get_user_sids(u32 fromsid,
26931da177e4SLinus Torvalds 			   char *username,
26941da177e4SLinus Torvalds 			   u32 **sids,
26951da177e4SLinus Torvalds 			   u32 *nel)
26961da177e4SLinus Torvalds {
26971b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2698aa8e712cSStephen Smalley 	struct policydb *policydb;
2699aa8e712cSStephen Smalley 	struct sidtab *sidtab;
27001da177e4SLinus Torvalds 	struct context *fromcon, usercon;
27012c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
27029ad6e9cbSOndrej Mosnacek 	u32 i, j, mynel, maxnel = SIDS_NEL;
27031da177e4SLinus Torvalds 	struct user_datum *user;
27041da177e4SLinus Torvalds 	struct role_datum *role;
2705782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
27069ad6e9cbSOndrej Mosnacek 	int rc;
27071da177e4SLinus Torvalds 
27081da177e4SLinus Torvalds 	*sids = NULL;
27091da177e4SLinus Torvalds 	*nel = 0;
27102c3c05dbSStephen Smalley 
2711e67b7985SStephen Smalley 	if (!selinux_initialized())
27129ad6e9cbSOndrej Mosnacek 		return 0;
27131da177e4SLinus Torvalds 
27149ad6e9cbSOndrej Mosnacek 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
27159ad6e9cbSOndrej Mosnacek 	if (!mysids)
27169ad6e9cbSOndrej Mosnacek 		return -ENOMEM;
27179ad6e9cbSOndrej Mosnacek 
27189ad6e9cbSOndrej Mosnacek retry:
27199ad6e9cbSOndrej Mosnacek 	mynel = 0;
27201b8b31a2SStephen Smalley 	rcu_read_lock();
2721e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
27221b8b31a2SStephen Smalley 	policydb = &policy->policydb;
27231b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
27241da177e4SLinus Torvalds 
272512b29f34SStephen Smalley 	context_init(&usercon);
272612b29f34SStephen Smalley 
27274b02b524SEric Paris 	rc = -EINVAL;
2728aa8e712cSStephen Smalley 	fromcon = sidtab_search(sidtab, fromsid);
27294b02b524SEric Paris 	if (!fromcon)
27301da177e4SLinus Torvalds 		goto out_unlock;
27311da177e4SLinus Torvalds 
27321da177e4SLinus Torvalds 	rc = -EINVAL;
2733237389e3SOndrej Mosnacek 	user = symtab_search(&policydb->p_users, username);
27344b02b524SEric Paris 	if (!user)
27351da177e4SLinus Torvalds 		goto out_unlock;
27364b02b524SEric Paris 
27371da177e4SLinus Torvalds 	usercon.user = user->value;
27381da177e4SLinus Torvalds 
27399fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2740aa8e712cSStephen Smalley 		role = policydb->role_val_to_struct[i];
27411da177e4SLinus Torvalds 		usercon.role = i + 1;
27429fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
27431da177e4SLinus Torvalds 			usercon.type = j + 1;
27441da177e4SLinus Torvalds 
2745aa8e712cSStephen Smalley 			if (mls_setup_user_range(policydb, fromcon, user,
2746aa8e712cSStephen Smalley 						 &usercon))
27471da177e4SLinus Torvalds 				continue;
27481da177e4SLinus Torvalds 
2749225621c9SOndrej Mosnacek 			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
27509ad6e9cbSOndrej Mosnacek 			if (rc == -ESTALE) {
27519ad6e9cbSOndrej Mosnacek 				rcu_read_unlock();
27529ad6e9cbSOndrej Mosnacek 				goto retry;
27539ad6e9cbSOndrej Mosnacek 			}
27542c3c05dbSStephen Smalley 			if (rc)
27551da177e4SLinus Torvalds 				goto out_unlock;
27561da177e4SLinus Torvalds 			if (mynel < maxnel) {
27571da177e4SLinus Torvalds 				mysids[mynel++] = sid;
27581da177e4SLinus Torvalds 			} else {
27594b02b524SEric Paris 				rc = -ENOMEM;
27601da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
276189d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
27624b02b524SEric Paris 				if (!mysids2)
27631da177e4SLinus Torvalds 					goto out_unlock;
27641da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
27651da177e4SLinus Torvalds 				kfree(mysids);
27661da177e4SLinus Torvalds 				mysids = mysids2;
27671da177e4SLinus Torvalds 				mysids[mynel++] = sid;
27681da177e4SLinus Torvalds 			}
27691da177e4SLinus Torvalds 		}
27701da177e4SLinus Torvalds 	}
27714b02b524SEric Paris 	rc = 0;
27721da177e4SLinus Torvalds out_unlock:
27731b8b31a2SStephen Smalley 	rcu_read_unlock();
27742c3c05dbSStephen Smalley 	if (rc || !mynel) {
27752c3c05dbSStephen Smalley 		kfree(mysids);
27769ad6e9cbSOndrej Mosnacek 		return rc;
27772c3c05dbSStephen Smalley 	}
27782c3c05dbSStephen Smalley 
27794b02b524SEric Paris 	rc = -ENOMEM;
27802c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
27812c3c05dbSStephen Smalley 	if (!mysids2) {
27822c3c05dbSStephen Smalley 		kfree(mysids);
27839ad6e9cbSOndrej Mosnacek 		return rc;
27842c3c05dbSStephen Smalley 	}
27852c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
2786f01e1af4SLinus Torvalds 		struct av_decision dummy_avd;
2787e67b7985SStephen Smalley 		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2788c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
27892c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
2790f01e1af4SLinus Torvalds 					  &dummy_avd);
27912c3c05dbSStephen Smalley 		if (!rc)
27922c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
27932c3c05dbSStephen Smalley 		cond_resched();
27942c3c05dbSStephen Smalley 	}
27952c3c05dbSStephen Smalley 	kfree(mysids);
27962c3c05dbSStephen Smalley 	*sids = mysids2;
27972c3c05dbSStephen Smalley 	*nel = j;
27989ad6e9cbSOndrej Mosnacek 	return 0;
27991da177e4SLinus Torvalds }
28001da177e4SLinus Torvalds 
28011da177e4SLinus Torvalds /**
2802f31e7994SWaiman Long  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
2803e9fd7292SPaul Moore  * @policy: policy
28041da177e4SLinus Torvalds  * @fstype: filesystem type
28051da177e4SLinus Torvalds  * @path: path from root of mount
2806e9fd7292SPaul Moore  * @orig_sclass: file security class
28071da177e4SLinus Torvalds  * @sid: SID for path
28081da177e4SLinus Torvalds  *
28091da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
28101da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
28111da177e4SLinus Torvalds  * transition SIDs or task SIDs.
28129ad6e9cbSOndrej Mosnacek  *
28139ad6e9cbSOndrej Mosnacek  * WARNING: This function may return -ESTALE, indicating that the caller
28149ad6e9cbSOndrej Mosnacek  * must retry the operation after re-acquiring the policy pointer!
28151da177e4SLinus Torvalds  */
__security_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)281602a52c5cSStephen Smalley static inline int __security_genfs_sid(struct selinux_policy *policy,
2817aa8e712cSStephen Smalley 				       const char *fstype,
281808df4905SChristian Göttsche 				       const char *path,
2819c6d3aaa4SStephen Smalley 				       u16 orig_sclass,
28201da177e4SLinus Torvalds 				       u32 *sid)
28211da177e4SLinus Torvalds {
282202a52c5cSStephen Smalley 	struct policydb *policydb = &policy->policydb;
2823c7c556f1SStephen Smalley 	struct sidtab *sidtab = policy->sidtab;
2824c6d3aaa4SStephen Smalley 	u16 sclass;
28251da177e4SLinus Torvalds 	struct genfs *genfs;
28261da177e4SLinus Torvalds 	struct ocontext *c;
2827cbfcd13bSOndrej Mosnacek 	int cmp = 0;
28281da177e4SLinus Torvalds 
2829b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2830b1aa5301SStephen Smalley 		path++;
2831b1aa5301SStephen Smalley 
283202a52c5cSStephen Smalley 	sclass = unmap_class(&policy->map, orig_sclass);
28334b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2834c6d3aaa4SStephen Smalley 
2835aa8e712cSStephen Smalley 	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
28361da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
28371da177e4SLinus Torvalds 		if (cmp <= 0)
28381da177e4SLinus Torvalds 			break;
28391da177e4SLinus Torvalds 	}
28401da177e4SLinus Torvalds 
28414b02b524SEric Paris 	if (!genfs || cmp)
2842cbfcd13bSOndrej Mosnacek 		return -ENOENT;
28431da177e4SLinus Torvalds 
28441da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
2845c50e125dSChristian Göttsche 		size_t len = strlen(c->u.name);
28461da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
28471da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
28481da177e4SLinus Torvalds 			break;
28491da177e4SLinus Torvalds 	}
28501da177e4SLinus Torvalds 
28514b02b524SEric Paris 	if (!c)
2852cbfcd13bSOndrej Mosnacek 		return -ENOENT;
28531da177e4SLinus Torvalds 
2854cbfcd13bSOndrej Mosnacek 	return ocontext_to_sid(sidtab, c, 0, sid);
28551da177e4SLinus Torvalds }
28561da177e4SLinus Torvalds 
28571da177e4SLinus Torvalds /**
2858f31e7994SWaiman Long  * security_genfs_sid - Obtain a SID for a file in a filesystem
2859f31e7994SWaiman Long  * @fstype: filesystem type
2860f31e7994SWaiman Long  * @path: path from root of mount
2861e9fd7292SPaul Moore  * @orig_sclass: file security class
2862f31e7994SWaiman Long  * @sid: SID for path
2863f31e7994SWaiman Long  *
2864f31e7994SWaiman Long  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2865f31e7994SWaiman Long  * it afterward.
2866f31e7994SWaiman Long  */
security_genfs_sid(const char * fstype,const char * path,u16 orig_sclass,u32 * sid)2867e67b7985SStephen Smalley int security_genfs_sid(const char *fstype,
286808df4905SChristian Göttsche 		       const char *path,
2869f31e7994SWaiman Long 		       u16 orig_sclass,
2870f31e7994SWaiman Long 		       u32 *sid)
2871f31e7994SWaiman Long {
28721b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2873f31e7994SWaiman Long 	int retval;
2874f31e7994SWaiman Long 
2875e67b7985SStephen Smalley 	if (!selinux_initialized()) {
287637ea433cSStephen Smalley 		*sid = SECINITSID_UNLABELED;
287737ea433cSStephen Smalley 		return 0;
287837ea433cSStephen Smalley 	}
287937ea433cSStephen Smalley 
28809ad6e9cbSOndrej Mosnacek 	do {
28811b8b31a2SStephen Smalley 		rcu_read_lock();
2882e67b7985SStephen Smalley 		policy = rcu_dereference(selinux_state.policy);
28839ad6e9cbSOndrej Mosnacek 		retval = __security_genfs_sid(policy, fstype, path,
28849ad6e9cbSOndrej Mosnacek 					      orig_sclass, sid);
28851b8b31a2SStephen Smalley 		rcu_read_unlock();
28869ad6e9cbSOndrej Mosnacek 	} while (retval == -ESTALE);
2887f31e7994SWaiman Long 	return retval;
2888f31e7994SWaiman Long }
2889f31e7994SWaiman Long 
selinux_policy_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)289002a52c5cSStephen Smalley int selinux_policy_genfs_sid(struct selinux_policy *policy,
289102a52c5cSStephen Smalley 			const char *fstype,
289208df4905SChristian Göttsche 			const char *path,
289302a52c5cSStephen Smalley 			u16 orig_sclass,
289402a52c5cSStephen Smalley 			u32 *sid)
289502a52c5cSStephen Smalley {
289602a52c5cSStephen Smalley 	/* no lock required, policy is not yet accessible by other threads */
289702a52c5cSStephen Smalley 	return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
289802a52c5cSStephen Smalley }
289902a52c5cSStephen Smalley 
2900f31e7994SWaiman Long /**
29011da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
2902a64c54cfSEric Paris  * @sb: superblock in question
29031da177e4SLinus Torvalds  */
security_fs_use(struct super_block * sb)2904e67b7985SStephen Smalley int security_fs_use(struct super_block *sb)
29051da177e4SLinus Torvalds {
29061b8b31a2SStephen Smalley 	struct selinux_policy *policy;
2907aa8e712cSStephen Smalley 	struct policydb *policydb;
2908225621c9SOndrej Mosnacek 	struct sidtab *sidtab;
29099ad6e9cbSOndrej Mosnacek 	int rc;
29101da177e4SLinus Torvalds 	struct ocontext *c;
29111aea7808SCasey Schaufler 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
2912a64c54cfSEric Paris 	const char *fstype = sb->s_type->name;
29131da177e4SLinus Torvalds 
2914e67b7985SStephen Smalley 	if (!selinux_initialized()) {
291537ea433cSStephen Smalley 		sbsec->behavior = SECURITY_FS_USE_NONE;
291637ea433cSStephen Smalley 		sbsec->sid = SECINITSID_UNLABELED;
291737ea433cSStephen Smalley 		return 0;
291837ea433cSStephen Smalley 	}
291937ea433cSStephen Smalley 
29209ad6e9cbSOndrej Mosnacek retry:
29211b8b31a2SStephen Smalley 	rcu_read_lock();
2922e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
29231b8b31a2SStephen Smalley 	policydb = &policy->policydb;
29241b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
2925aa8e712cSStephen Smalley 
2926aa8e712cSStephen Smalley 	c = policydb->ocontexts[OCON_FSUSE];
29274d546f81SPaul Moore 	while (c) {
29284d546f81SPaul Moore 		if (strcmp(fstype, c->u.name) == 0)
29291da177e4SLinus Torvalds 			break;
29304d546f81SPaul Moore 		c = c->next;
29311da177e4SLinus Torvalds 	}
29321da177e4SLinus Torvalds 
29331da177e4SLinus Torvalds 	if (c) {
2934a64c54cfSEric Paris 		sbsec->behavior = c->v.behavior;
2935cbfcd13bSOndrej Mosnacek 		rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
29369ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
29379ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
29389ad6e9cbSOndrej Mosnacek 			goto retry;
29399ad6e9cbSOndrej Mosnacek 		}
29401da177e4SLinus Torvalds 		if (rc)
29411da177e4SLinus Torvalds 			goto out;
2942089be43eSJames Morris 	} else {
29431b8b31a2SStephen Smalley 		rc = __security_genfs_sid(policy, fstype, "/",
294402a52c5cSStephen Smalley 					SECCLASS_DIR, &sbsec->sid);
29459ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
29469ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
29479ad6e9cbSOndrej Mosnacek 			goto retry;
29489ad6e9cbSOndrej Mosnacek 		}
29491da177e4SLinus Torvalds 		if (rc) {
2950a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_NONE;
29511da177e4SLinus Torvalds 			rc = 0;
29521da177e4SLinus Torvalds 		} else {
2953a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_GENFS;
29541da177e4SLinus Torvalds 		}
2955089be43eSJames Morris 	}
29561da177e4SLinus Torvalds 
29571da177e4SLinus Torvalds out:
29581b8b31a2SStephen Smalley 	rcu_read_unlock();
29591da177e4SLinus Torvalds 	return rc;
29601da177e4SLinus Torvalds }
29611da177e4SLinus Torvalds 
security_get_bools(struct selinux_policy * policy,u32 * len,char *** names,int ** values)296202a52c5cSStephen Smalley int security_get_bools(struct selinux_policy *policy,
296360abd318SOndrej Mosnacek 		       u32 *len, char ***names, int **values)
29641da177e4SLinus Torvalds {
2965aa8e712cSStephen Smalley 	struct policydb *policydb;
296660abd318SOndrej Mosnacek 	u32 i;
296760abd318SOndrej Mosnacek 	int rc;
29681da177e4SLinus Torvalds 
296902a52c5cSStephen Smalley 	policydb = &policy->policydb;
2970aa8e712cSStephen Smalley 
29711da177e4SLinus Torvalds 	*names = NULL;
29721da177e4SLinus Torvalds 	*values = NULL;
29731da177e4SLinus Torvalds 
29741da177e4SLinus Torvalds 	rc = 0;
2975aa8e712cSStephen Smalley 	*len = policydb->p_bools.nprim;
29764b02b524SEric Paris 	if (!*len)
29771da177e4SLinus Torvalds 		goto out;
29781da177e4SLinus Torvalds 
29794b02b524SEric Paris 	rc = -ENOMEM;
2980e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
29811da177e4SLinus Torvalds 	if (!*names)
29821da177e4SLinus Torvalds 		goto err;
29831da177e4SLinus Torvalds 
29844b02b524SEric Paris 	rc = -ENOMEM;
2985e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
29861da177e4SLinus Torvalds 	if (!*values)
29871da177e4SLinus Torvalds 		goto err;
29881da177e4SLinus Torvalds 
29891da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
2990aa8e712cSStephen Smalley 		(*values)[i] = policydb->bool_val_to_struct[i]->state;
29914b02b524SEric Paris 
29924b02b524SEric Paris 		rc = -ENOMEM;
2993aa8e712cSStephen Smalley 		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
2994aa8e712cSStephen Smalley 				      GFP_ATOMIC);
29951da177e4SLinus Torvalds 		if (!(*names)[i])
29961da177e4SLinus Torvalds 			goto err;
29971da177e4SLinus Torvalds 	}
29981da177e4SLinus Torvalds 	rc = 0;
29991da177e4SLinus Torvalds out:
30001da177e4SLinus Torvalds 	return rc;
30011da177e4SLinus Torvalds err:
30021da177e4SLinus Torvalds 	if (*names) {
30031da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
30041da177e4SLinus Torvalds 			kfree((*names)[i]);
300565de5096STom Rix 		kfree(*names);
30061da177e4SLinus Torvalds 	}
30071da177e4SLinus Torvalds 	kfree(*values);
300865de5096STom Rix 	*len = 0;
300965de5096STom Rix 	*names = NULL;
301065de5096STom Rix 	*values = NULL;
30111da177e4SLinus Torvalds 	goto out;
30121da177e4SLinus Torvalds }
30131da177e4SLinus Torvalds 
30141da177e4SLinus Torvalds 
security_set_bools(u32 len,int * values)3015e67b7985SStephen Smalley int security_set_bools(u32 len, int *values)
30161da177e4SLinus Torvalds {
3017e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
3018c7c556f1SStephen Smalley 	struct selinux_policy *newpolicy, *oldpolicy;
301960abd318SOndrej Mosnacek 	int rc;
3020c7c556f1SStephen Smalley 	u32 i, seqno = 0;
30211da177e4SLinus Torvalds 
3022e67b7985SStephen Smalley 	if (!selinux_initialized())
302337ea433cSStephen Smalley 		return -EINVAL;
302437ea433cSStephen Smalley 
30259ff9abc4SStephen Smalley 	oldpolicy = rcu_dereference_protected(state->policy,
30269ff9abc4SStephen Smalley 					lockdep_is_held(&state->policy_mutex));
30271b8b31a2SStephen Smalley 
3028c7c556f1SStephen Smalley 	/* Consistency check on number of booleans, should never fail */
30291b8b31a2SStephen Smalley 	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
3030c7c556f1SStephen Smalley 		return -EINVAL;
30311da177e4SLinus Torvalds 
30321b8b31a2SStephen Smalley 	newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
3033c7c556f1SStephen Smalley 	if (!newpolicy)
3034c7c556f1SStephen Smalley 		return -ENOMEM;
30351da177e4SLinus Torvalds 
3036c7c556f1SStephen Smalley 	/*
3037c7c556f1SStephen Smalley 	 * Deep copy only the parts of the policydb that might be
3038c7c556f1SStephen Smalley 	 * modified as a result of changing booleans.
3039c7c556f1SStephen Smalley 	 */
3040c7c556f1SStephen Smalley 	rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
3041c7c556f1SStephen Smalley 	if (rc) {
3042c7c556f1SStephen Smalley 		kfree(newpolicy);
3043c7c556f1SStephen Smalley 		return -ENOMEM;
3044c7c556f1SStephen Smalley 	}
3045c7c556f1SStephen Smalley 
3046c7c556f1SStephen Smalley 	/* Update the boolean states in the copy */
30471da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
3048c7c556f1SStephen Smalley 		int new_state = !!values[i];
3049c7c556f1SStephen Smalley 		int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
3050c7c556f1SStephen Smalley 
3051c7c556f1SStephen Smalley 		if (new_state != old_state) {
3052cdfb6b34SRichard Guy Briggs 			audit_log(audit_context(), GFP_ATOMIC,
3053af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
30544746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
3055c7c556f1SStephen Smalley 				sym_name(&newpolicy->policydb, SYM_BOOLS, i),
3056c7c556f1SStephen Smalley 				new_state,
3057c7c556f1SStephen Smalley 				old_state,
3058581abc09SEric W. Biederman 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
30594746ec5bSEric Paris 				audit_get_sessionid(current));
3060c7c556f1SStephen Smalley 			newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
3061af601e46SSteve Grubb 		}
30621da177e4SLinus Torvalds 	}
30631da177e4SLinus Torvalds 
3064c7c556f1SStephen Smalley 	/* Re-evaluate the conditional rules in the copy */
3065c7c556f1SStephen Smalley 	evaluate_cond_nodes(&newpolicy->policydb);
30661da177e4SLinus Torvalds 
30671b8b31a2SStephen Smalley 	/* Set latest granting seqno for new policy */
30681b8b31a2SStephen Smalley 	newpolicy->latest_granting = oldpolicy->latest_granting + 1;
30691b8b31a2SStephen Smalley 	seqno = newpolicy->latest_granting;
30701b8b31a2SStephen Smalley 
3071c7c556f1SStephen Smalley 	/* Install the new policy */
30721b8b31a2SStephen Smalley 	rcu_assign_pointer(state->policy, newpolicy);
3073c7c556f1SStephen Smalley 
3074c7c556f1SStephen Smalley 	/*
3075c7c556f1SStephen Smalley 	 * Free the conditional portions of the old policydb
30761b8b31a2SStephen Smalley 	 * that were copied for the new policy, and the oldpolicy
30771b8b31a2SStephen Smalley 	 * structure itself but not what it references.
3078c7c556f1SStephen Smalley 	 */
30791b8b31a2SStephen Smalley 	synchronize_rcu();
30801b8b31a2SStephen Smalley 	selinux_policy_cond_free(oldpolicy);
3081c7c556f1SStephen Smalley 
3082c7c556f1SStephen Smalley 	/* Notify others of the policy change */
3083e67b7985SStephen Smalley 	selinux_notify_policy_change(seqno);
3084c7c556f1SStephen Smalley 	return 0;
30851da177e4SLinus Torvalds }
30861da177e4SLinus Torvalds 
security_get_bool_value(u32 index)3087e67b7985SStephen Smalley int security_get_bool_value(u32 index)
30881da177e4SLinus Torvalds {
30891b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3090aa8e712cSStephen Smalley 	struct policydb *policydb;
30914b02b524SEric Paris 	int rc;
309260abd318SOndrej Mosnacek 	u32 len;
30931da177e4SLinus Torvalds 
3094e67b7985SStephen Smalley 	if (!selinux_initialized())
309537ea433cSStephen Smalley 		return 0;
309637ea433cSStephen Smalley 
30971b8b31a2SStephen Smalley 	rcu_read_lock();
3098e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
30991b8b31a2SStephen Smalley 	policydb = &policy->policydb;
31001da177e4SLinus Torvalds 
31011da177e4SLinus Torvalds 	rc = -EFAULT;
3102aa8e712cSStephen Smalley 	len = policydb->p_bools.nprim;
31030fd71a62SPrarit Bhargava 	if (index >= len)
31041da177e4SLinus Torvalds 		goto out;
31051da177e4SLinus Torvalds 
3106aa8e712cSStephen Smalley 	rc = policydb->bool_val_to_struct[index]->state;
31071da177e4SLinus Torvalds out:
31081b8b31a2SStephen Smalley 	rcu_read_unlock();
31091da177e4SLinus Torvalds 	return rc;
31101da177e4SLinus Torvalds }
3111376bd9cbSDarrel Goeddel 
security_preserve_bools(struct selinux_policy * oldpolicy,struct selinux_policy * newpolicy)31121b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
31131b8b31a2SStephen Smalley 				struct selinux_policy *newpolicy)
3114e900a7d9SStephen Smalley {
311560abd318SOndrej Mosnacek 	int rc, *bvalues = NULL;
3116e900a7d9SStephen Smalley 	char **bnames = NULL;
3117e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
311860abd318SOndrej Mosnacek 	u32 i, nbools = 0;
3119e900a7d9SStephen Smalley 
31201b8b31a2SStephen Smalley 	rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
3121e900a7d9SStephen Smalley 	if (rc)
3122e900a7d9SStephen Smalley 		goto out;
3123e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
31241b8b31a2SStephen Smalley 		booldatum = symtab_search(&newpolicy->policydb.p_bools,
31251b8b31a2SStephen Smalley 					bnames[i]);
3126e900a7d9SStephen Smalley 		if (booldatum)
3127e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
3128e900a7d9SStephen Smalley 	}
31291b8b31a2SStephen Smalley 	evaluate_cond_nodes(&newpolicy->policydb);
3130e900a7d9SStephen Smalley 
3131e900a7d9SStephen Smalley out:
3132e900a7d9SStephen Smalley 	if (bnames) {
3133e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
3134e900a7d9SStephen Smalley 			kfree(bnames[i]);
3135e900a7d9SStephen Smalley 	}
3136e900a7d9SStephen Smalley 	kfree(bnames);
3137e900a7d9SStephen Smalley 	kfree(bvalues);
3138e900a7d9SStephen Smalley 	return rc;
3139e900a7d9SStephen Smalley }
3140e900a7d9SStephen Smalley 
314108554d6bSVenkat Yekkirala /*
314208554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
314308554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
314408554d6bSVenkat Yekkirala  */
security_sid_mls_copy(u32 sid,u32 mls_sid,u32 * new_sid)3145e67b7985SStephen Smalley int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
314608554d6bSVenkat Yekkirala {
31471b8b31a2SStephen Smalley 	struct selinux_policy *policy;
314846169802SStephen Smalley 	struct policydb *policydb;
314946169802SStephen Smalley 	struct sidtab *sidtab;
315008554d6bSVenkat Yekkirala 	struct context *context1;
315108554d6bSVenkat Yekkirala 	struct context *context2;
315208554d6bSVenkat Yekkirala 	struct context newcon;
315308554d6bSVenkat Yekkirala 	char *s;
315408554d6bSVenkat Yekkirala 	u32 len;
31554b02b524SEric Paris 	int rc;
315608554d6bSVenkat Yekkirala 
3157e67b7985SStephen Smalley 	if (!selinux_initialized()) {
315808554d6bSVenkat Yekkirala 		*new_sid = sid;
31599ad6e9cbSOndrej Mosnacek 		return 0;
316008554d6bSVenkat Yekkirala 	}
316108554d6bSVenkat Yekkirala 
31629ad6e9cbSOndrej Mosnacek retry:
31639ad6e9cbSOndrej Mosnacek 	rc = 0;
316408554d6bSVenkat Yekkirala 	context_init(&newcon);
316508554d6bSVenkat Yekkirala 
31661b8b31a2SStephen Smalley 	rcu_read_lock();
3167e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
31681b8b31a2SStephen Smalley 	policydb = &policy->policydb;
31691b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
317046169802SStephen Smalley 
317146169802SStephen Smalley 	if (!policydb->mls_enabled) {
317246169802SStephen Smalley 		*new_sid = sid;
317346169802SStephen Smalley 		goto out_unlock;
317446169802SStephen Smalley 	}
317546169802SStephen Smalley 
31764b02b524SEric Paris 	rc = -EINVAL;
3177aa8e712cSStephen Smalley 	context1 = sidtab_search(sidtab, sid);
317808554d6bSVenkat Yekkirala 	if (!context1) {
3179b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3180744ba35eSEric Paris 			__func__, sid);
318108554d6bSVenkat Yekkirala 		goto out_unlock;
318208554d6bSVenkat Yekkirala 	}
318308554d6bSVenkat Yekkirala 
31844b02b524SEric Paris 	rc = -EINVAL;
3185aa8e712cSStephen Smalley 	context2 = sidtab_search(sidtab, mls_sid);
318608554d6bSVenkat Yekkirala 	if (!context2) {
3187b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3188744ba35eSEric Paris 			__func__, mls_sid);
318908554d6bSVenkat Yekkirala 		goto out_unlock;
319008554d6bSVenkat Yekkirala 	}
319108554d6bSVenkat Yekkirala 
319208554d6bSVenkat Yekkirala 	newcon.user = context1->user;
319308554d6bSVenkat Yekkirala 	newcon.role = context1->role;
319408554d6bSVenkat Yekkirala 	newcon.type = context1->type;
31950efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
319608554d6bSVenkat Yekkirala 	if (rc)
319708554d6bSVenkat Yekkirala 		goto out_unlock;
319808554d6bSVenkat Yekkirala 
319908554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
3200aa8e712cSStephen Smalley 	if (!policydb_context_isvalid(policydb, &newcon)) {
3201e67b7985SStephen Smalley 		rc = convert_context_handle_invalid_context(policydb,
32021b8b31a2SStephen Smalley 							&newcon);
32034b02b524SEric Paris 		if (rc) {
3204aa8e712cSStephen Smalley 			if (!context_struct_to_string(policydb, &newcon, &s,
3205aa8e712cSStephen Smalley 						      &len)) {
3206ea74a685SRichard Guy Briggs 				struct audit_buffer *ab;
3207ea74a685SRichard Guy Briggs 
3208ea74a685SRichard Guy Briggs 				ab = audit_log_start(audit_context(),
3209ea74a685SRichard Guy Briggs 						     GFP_ATOMIC,
3210ea74a685SRichard Guy Briggs 						     AUDIT_SELINUX_ERR);
3211ea74a685SRichard Guy Briggs 				audit_log_format(ab,
3212ea74a685SRichard Guy Briggs 						 "op=security_sid_mls_copy invalid_context=");
3213ea74a685SRichard Guy Briggs 				/* don't record NUL with untrusted strings */
3214ea74a685SRichard Guy Briggs 				audit_log_n_untrustedstring(ab, s, len - 1);
3215ea74a685SRichard Guy Briggs 				audit_log_end(ab);
321608554d6bSVenkat Yekkirala 				kfree(s);
321708554d6bSVenkat Yekkirala 			}
32184b02b524SEric Paris 			goto out_unlock;
32194b02b524SEric Paris 		}
32204b02b524SEric Paris 	}
3221225621c9SOndrej Mosnacek 	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
32229ad6e9cbSOndrej Mosnacek 	if (rc == -ESTALE) {
32239ad6e9cbSOndrej Mosnacek 		rcu_read_unlock();
32249ad6e9cbSOndrej Mosnacek 		context_destroy(&newcon);
32259ad6e9cbSOndrej Mosnacek 		goto retry;
32269ad6e9cbSOndrej Mosnacek 	}
322708554d6bSVenkat Yekkirala out_unlock:
32281b8b31a2SStephen Smalley 	rcu_read_unlock();
322908554d6bSVenkat Yekkirala 	context_destroy(&newcon);
323008554d6bSVenkat Yekkirala 	return rc;
323108554d6bSVenkat Yekkirala }
323208554d6bSVenkat Yekkirala 
3233220deb96SPaul Moore /**
3234220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3235220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
3236220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
3237220deb96SPaul Moore  * @xfrm_sid: XFRM SID
3238e9fd7292SPaul Moore  * @peer_sid: network peer sid
3239220deb96SPaul Moore  *
3240220deb96SPaul Moore  * Description:
3241220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3242220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
3243220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
3244220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
3245220deb96SPaul Moore  *
3246220deb96SPaul Moore  *                                 | function return |      @sid
3247220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
3248220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
3249220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
3250220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
3251220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
3252220deb96SPaul Moore  *
3253220deb96SPaul Moore  */
security_net_peersid_resolve(u32 nlbl_sid,u32 nlbl_type,u32 xfrm_sid,u32 * peer_sid)3254e67b7985SStephen Smalley int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
3255220deb96SPaul Moore 				 u32 xfrm_sid,
3256220deb96SPaul Moore 				 u32 *peer_sid)
3257220deb96SPaul Moore {
32581b8b31a2SStephen Smalley 	struct selinux_policy *policy;
325946169802SStephen Smalley 	struct policydb *policydb;
326046169802SStephen Smalley 	struct sidtab *sidtab;
3261220deb96SPaul Moore 	int rc;
3262220deb96SPaul Moore 	struct context *nlbl_ctx;
3263220deb96SPaul Moore 	struct context *xfrm_ctx;
3264220deb96SPaul Moore 
32654b02b524SEric Paris 	*peer_sid = SECSID_NULL;
32664b02b524SEric Paris 
3267220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
3268220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
3269220deb96SPaul Moore 	 * single or absent peer SID/label */
3270220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
3271220deb96SPaul Moore 		*peer_sid = nlbl_sid;
3272220deb96SPaul Moore 		return 0;
3273220deb96SPaul Moore 	}
3274220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3275220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3276220deb96SPaul Moore 	 * is present */
3277220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3278220deb96SPaul Moore 		*peer_sid = xfrm_sid;
3279220deb96SPaul Moore 		return 0;
3280220deb96SPaul Moore 	}
3281220deb96SPaul Moore 
3282e67b7985SStephen Smalley 	if (!selinux_initialized())
328337ea433cSStephen Smalley 		return 0;
328437ea433cSStephen Smalley 
32851b8b31a2SStephen Smalley 	rcu_read_lock();
3286e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
32871b8b31a2SStephen Smalley 	policydb = &policy->policydb;
32881b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
328946169802SStephen Smalley 
3290aa8e712cSStephen Smalley 	/*
3291aa8e712cSStephen Smalley 	 * We don't need to check initialized here since the only way both
3292220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3293aa8e712cSStephen Smalley 	 * security server was initialized and state->initialized was true.
3294aa8e712cSStephen Smalley 	 */
329546169802SStephen Smalley 	if (!policydb->mls_enabled) {
329646169802SStephen Smalley 		rc = 0;
329746169802SStephen Smalley 		goto out;
329846169802SStephen Smalley 	}
3299220deb96SPaul Moore 
33004b02b524SEric Paris 	rc = -EINVAL;
3301aa8e712cSStephen Smalley 	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3302220deb96SPaul Moore 	if (!nlbl_ctx) {
3303b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3304744ba35eSEric Paris 		       __func__, nlbl_sid);
33054b02b524SEric Paris 		goto out;
3306220deb96SPaul Moore 	}
33074b02b524SEric Paris 	rc = -EINVAL;
3308aa8e712cSStephen Smalley 	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3309220deb96SPaul Moore 	if (!xfrm_ctx) {
3310b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3311744ba35eSEric Paris 		       __func__, xfrm_sid);
33124b02b524SEric Paris 		goto out;
3313220deb96SPaul Moore 	}
3314220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
33154b02b524SEric Paris 	if (rc)
33164b02b524SEric Paris 		goto out;
3317220deb96SPaul Moore 
3318220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
3319220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
3320220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
3321220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
3322220deb96SPaul Moore 	 * expressive */
3323220deb96SPaul Moore 	*peer_sid = xfrm_sid;
33244b02b524SEric Paris out:
33251b8b31a2SStephen Smalley 	rcu_read_unlock();
3326220deb96SPaul Moore 	return rc;
3327220deb96SPaul Moore }
3328220deb96SPaul Moore 
get_classes_callback(void * k,void * d,void * args)332955fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
333055fcf09bSChristopher J. PeBenito {
333155fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
333255fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
3333c50e125dSChristian Göttsche 	u32 value = datum->value - 1;
333455fcf09bSChristopher J. PeBenito 
333555fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
333655fcf09bSChristopher J. PeBenito 	if (!classes[value])
333755fcf09bSChristopher J. PeBenito 		return -ENOMEM;
333855fcf09bSChristopher J. PeBenito 
333955fcf09bSChristopher J. PeBenito 	return 0;
334055fcf09bSChristopher J. PeBenito }
334155fcf09bSChristopher J. PeBenito 
security_get_classes(struct selinux_policy * policy,char *** classes,u32 * nclasses)334202a52c5cSStephen Smalley int security_get_classes(struct selinux_policy *policy,
3343c50e125dSChristian Göttsche 			 char ***classes, u32 *nclasses)
334455fcf09bSChristopher J. PeBenito {
334546169802SStephen Smalley 	struct policydb *policydb;
33464b02b524SEric Paris 	int rc;
334755fcf09bSChristopher J. PeBenito 
334802a52c5cSStephen Smalley 	policydb = &policy->policydb;
334946169802SStephen Smalley 
33504b02b524SEric Paris 	rc = -ENOMEM;
3351aa8e712cSStephen Smalley 	*nclasses = policydb->p_classes.nprim;
33529f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
335355fcf09bSChristopher J. PeBenito 	if (!*classes)
335455fcf09bSChristopher J. PeBenito 		goto out;
335555fcf09bSChristopher J. PeBenito 
335603414a49SOndrej Mosnacek 	rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
335755fcf09bSChristopher J. PeBenito 			 *classes);
33584b02b524SEric Paris 	if (rc) {
3359c50e125dSChristian Göttsche 		u32 i;
3360c50e125dSChristian Göttsche 
336155fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
336255fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
336355fcf09bSChristopher J. PeBenito 		kfree(*classes);
336455fcf09bSChristopher J. PeBenito 	}
336555fcf09bSChristopher J. PeBenito 
336655fcf09bSChristopher J. PeBenito out:
336755fcf09bSChristopher J. PeBenito 	return rc;
336855fcf09bSChristopher J. PeBenito }
336955fcf09bSChristopher J. PeBenito 
get_permissions_callback(void * k,void * d,void * args)337055fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
337155fcf09bSChristopher J. PeBenito {
337255fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
337355fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
3374c50e125dSChristian Göttsche 	u32 value = datum->value - 1;
337555fcf09bSChristopher J. PeBenito 
337655fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
337755fcf09bSChristopher J. PeBenito 	if (!perms[value])
337855fcf09bSChristopher J. PeBenito 		return -ENOMEM;
337955fcf09bSChristopher J. PeBenito 
338055fcf09bSChristopher J. PeBenito 	return 0;
338155fcf09bSChristopher J. PeBenito }
338255fcf09bSChristopher J. PeBenito 
security_get_permissions(struct selinux_policy * policy,const char * class,char *** perms,u32 * nperms)338302a52c5cSStephen Smalley int security_get_permissions(struct selinux_policy *policy,
3384c50e125dSChristian Göttsche 			     const char *class, char ***perms, u32 *nperms)
338555fcf09bSChristopher J. PeBenito {
338646169802SStephen Smalley 	struct policydb *policydb;
3387c50e125dSChristian Göttsche 	u32 i;
3388c50e125dSChristian Göttsche 	int rc;
338955fcf09bSChristopher J. PeBenito 	struct class_datum *match;
339055fcf09bSChristopher J. PeBenito 
339102a52c5cSStephen Smalley 	policydb = &policy->policydb;
339246169802SStephen Smalley 
33934b02b524SEric Paris 	rc = -EINVAL;
3394237389e3SOndrej Mosnacek 	match = symtab_search(&policydb->p_classes, class);
339555fcf09bSChristopher J. PeBenito 	if (!match) {
3396b54c85c1Speter enderborg 		pr_err("SELinux: %s:  unrecognized class %s\n",
3397dd6f953aSHarvey Harrison 			__func__, class);
339855fcf09bSChristopher J. PeBenito 		goto out;
339955fcf09bSChristopher J. PeBenito 	}
340055fcf09bSChristopher J. PeBenito 
34014b02b524SEric Paris 	rc = -ENOMEM;
340255fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
34039f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
340455fcf09bSChristopher J. PeBenito 	if (!*perms)
340555fcf09bSChristopher J. PeBenito 		goto out;
340655fcf09bSChristopher J. PeBenito 
340755fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
340803414a49SOndrej Mosnacek 		rc = hashtab_map(&match->comdatum->permissions.table,
340955fcf09bSChristopher J. PeBenito 				 get_permissions_callback, *perms);
34104b02b524SEric Paris 		if (rc)
341155fcf09bSChristopher J. PeBenito 			goto err;
341255fcf09bSChristopher J. PeBenito 	}
341355fcf09bSChristopher J. PeBenito 
341403414a49SOndrej Mosnacek 	rc = hashtab_map(&match->permissions.table, get_permissions_callback,
341555fcf09bSChristopher J. PeBenito 			 *perms);
34164b02b524SEric Paris 	if (rc)
341755fcf09bSChristopher J. PeBenito 		goto err;
341855fcf09bSChristopher J. PeBenito 
341955fcf09bSChristopher J. PeBenito out:
342055fcf09bSChristopher J. PeBenito 	return rc;
342155fcf09bSChristopher J. PeBenito 
342255fcf09bSChristopher J. PeBenito err:
342355fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
342455fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
342555fcf09bSChristopher J. PeBenito 	kfree(*perms);
342655fcf09bSChristopher J. PeBenito 	return rc;
342755fcf09bSChristopher J. PeBenito }
342855fcf09bSChristopher J. PeBenito 
security_get_reject_unknown(void)3429e67b7985SStephen Smalley int security_get_reject_unknown(void)
34303f12070eSEric Paris {
34311b8b31a2SStephen Smalley 	struct selinux_policy *policy;
343246169802SStephen Smalley 	int value;
343346169802SStephen Smalley 
3434e67b7985SStephen Smalley 	if (!selinux_initialized())
343537ea433cSStephen Smalley 		return 0;
343637ea433cSStephen Smalley 
34371b8b31a2SStephen Smalley 	rcu_read_lock();
3438e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34391b8b31a2SStephen Smalley 	value = policy->policydb.reject_unknown;
34401b8b31a2SStephen Smalley 	rcu_read_unlock();
344146169802SStephen Smalley 	return value;
34423f12070eSEric Paris }
34433f12070eSEric Paris 
security_get_allow_unknown(void)3444e67b7985SStephen Smalley int security_get_allow_unknown(void)
34453f12070eSEric Paris {
34461b8b31a2SStephen Smalley 	struct selinux_policy *policy;
344746169802SStephen Smalley 	int value;
344846169802SStephen Smalley 
3449e67b7985SStephen Smalley 	if (!selinux_initialized())
345037ea433cSStephen Smalley 		return 0;
345137ea433cSStephen Smalley 
34521b8b31a2SStephen Smalley 	rcu_read_lock();
3453e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34541b8b31a2SStephen Smalley 	value = policy->policydb.allow_unknown;
34551b8b31a2SStephen Smalley 	rcu_read_unlock();
345646169802SStephen Smalley 	return value;
34573f12070eSEric Paris }
34583f12070eSEric Paris 
34593bb56b25SPaul Moore /**
34603bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
34613bb56b25SPaul Moore  * @req_cap: capability
34623bb56b25SPaul Moore  *
34633bb56b25SPaul Moore  * Description:
34643bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
34653bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
34663bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
34673bb56b25SPaul Moore  *
34683bb56b25SPaul Moore  */
security_policycap_supported(unsigned int req_cap)3469e67b7985SStephen Smalley int security_policycap_supported(unsigned int req_cap)
34703bb56b25SPaul Moore {
34711b8b31a2SStephen Smalley 	struct selinux_policy *policy;
34723bb56b25SPaul Moore 	int rc;
34733bb56b25SPaul Moore 
3474e67b7985SStephen Smalley 	if (!selinux_initialized())
347537ea433cSStephen Smalley 		return 0;
347637ea433cSStephen Smalley 
34771b8b31a2SStephen Smalley 	rcu_read_lock();
3478e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
34791b8b31a2SStephen Smalley 	rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
34801b8b31a2SStephen Smalley 	rcu_read_unlock();
34813bb56b25SPaul Moore 
34823bb56b25SPaul Moore 	return rc;
34833bb56b25SPaul Moore }
34843bb56b25SPaul Moore 
3485376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3486376bd9cbSDarrel Goeddel 	u32 au_seqno;
3487376bd9cbSDarrel Goeddel 	struct context au_ctxt;
3488376bd9cbSDarrel Goeddel };
3489376bd9cbSDarrel Goeddel 
selinux_audit_rule_free(void * vrule)34909d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3491376bd9cbSDarrel Goeddel {
34929d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
34939d57a7f9SAhmed S. Darwish 
3494376bd9cbSDarrel Goeddel 	if (rule) {
3495376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
3496376bd9cbSDarrel Goeddel 		kfree(rule);
3497376bd9cbSDarrel Goeddel 	}
3498376bd9cbSDarrel Goeddel }
3499376bd9cbSDarrel Goeddel 
selinux_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule)35009d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3501376bd9cbSDarrel Goeddel {
3502aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
35031b8b31a2SStephen Smalley 	struct selinux_policy *policy;
350446169802SStephen Smalley 	struct policydb *policydb;
3505376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
3506376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
3507376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
3508376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
35099d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3510376bd9cbSDarrel Goeddel 	int rc = 0;
3511376bd9cbSDarrel Goeddel 
3512376bd9cbSDarrel Goeddel 	*rule = NULL;
3513376bd9cbSDarrel Goeddel 
3514e67b7985SStephen Smalley 	if (!selinux_initialized())
35153ad40d64SSteve G 		return -EOPNOTSUPP;
3516376bd9cbSDarrel Goeddel 
3517376bd9cbSDarrel Goeddel 	switch (field) {
35183a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
35193a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
35203a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
35216e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
35226e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
35236e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3524376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
35255af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
3526376bd9cbSDarrel Goeddel 			return -EINVAL;
3527376bd9cbSDarrel Goeddel 		break;
35283a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
35293a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
35306e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
35316e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
353225985edcSLucas De Marchi 		/* we do not allow a range, indicated by the presence of '-' */
3533376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
3534376bd9cbSDarrel Goeddel 			return -EINVAL;
3535376bd9cbSDarrel Goeddel 		break;
3536376bd9cbSDarrel Goeddel 	default:
3537376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
3538376bd9cbSDarrel Goeddel 		return -EINVAL;
3539376bd9cbSDarrel Goeddel 	}
3540376bd9cbSDarrel Goeddel 
3541376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
3542376bd9cbSDarrel Goeddel 	if (!tmprule)
3543376bd9cbSDarrel Goeddel 		return -ENOMEM;
3544376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
3545376bd9cbSDarrel Goeddel 
35461b8b31a2SStephen Smalley 	rcu_read_lock();
35471b8b31a2SStephen Smalley 	policy = rcu_dereference(state->policy);
35481b8b31a2SStephen Smalley 	policydb = &policy->policydb;
35491b8b31a2SStephen Smalley 	tmprule->au_seqno = policy->latest_granting;
3550376bd9cbSDarrel Goeddel 	switch (field) {
35513a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
35526e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3553237389e3SOndrej Mosnacek 		userdatum = symtab_search(&policydb->p_users, rulestr);
3554c52df19eSPaul Moore 		if (!userdatum) {
3555c52df19eSPaul Moore 			rc = -EINVAL;
3556c52df19eSPaul Moore 			goto err;
3557c52df19eSPaul Moore 		}
3558376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
3559376bd9cbSDarrel Goeddel 		break;
35603a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
35616e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3562237389e3SOndrej Mosnacek 		roledatum = symtab_search(&policydb->p_roles, rulestr);
3563c52df19eSPaul Moore 		if (!roledatum) {
3564c52df19eSPaul Moore 			rc = -EINVAL;
3565c52df19eSPaul Moore 			goto err;
3566c52df19eSPaul Moore 		}
3567376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
3568376bd9cbSDarrel Goeddel 		break;
35693a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
35706e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3571237389e3SOndrej Mosnacek 		typedatum = symtab_search(&policydb->p_types, rulestr);
3572c52df19eSPaul Moore 		if (!typedatum) {
3573c52df19eSPaul Moore 			rc = -EINVAL;
3574c52df19eSPaul Moore 			goto err;
3575c52df19eSPaul Moore 		}
3576376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
3577376bd9cbSDarrel Goeddel 		break;
35783a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
35793a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
35806e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
35816e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
3582aa8e712cSStephen Smalley 		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3583aa8e712cSStephen Smalley 				     GFP_ATOMIC);
35844b02b524SEric Paris 		if (rc)
3585c52df19eSPaul Moore 			goto err;
3586376bd9cbSDarrel Goeddel 		break;
3587376bd9cbSDarrel Goeddel 	}
35881b8b31a2SStephen Smalley 	rcu_read_unlock();
3589376bd9cbSDarrel Goeddel 
3590376bd9cbSDarrel Goeddel 	*rule = tmprule;
3591c52df19eSPaul Moore 	return 0;
3592376bd9cbSDarrel Goeddel 
3593c52df19eSPaul Moore err:
3594c52df19eSPaul Moore 	rcu_read_unlock();
3595c52df19eSPaul Moore 	selinux_audit_rule_free(tmprule);
3596c52df19eSPaul Moore 	*rule = NULL;
3597376bd9cbSDarrel Goeddel 	return rc;
3598376bd9cbSDarrel Goeddel }
3599376bd9cbSDarrel Goeddel 
36009d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
selinux_audit_rule_known(struct audit_krule * rule)36019d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
36029d57a7f9SAhmed S. Darwish {
3603c50e125dSChristian Göttsche 	u32 i;
36049d57a7f9SAhmed S. Darwish 
36059d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
36069d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
36079d57a7f9SAhmed S. Darwish 		switch (f->type) {
36089d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
36099d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
36109d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
36119d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
36129d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
36139d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
36149d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
36159d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
36169d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
36179d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
36189d57a7f9SAhmed S. Darwish 			return 1;
36199d57a7f9SAhmed S. Darwish 		}
36209d57a7f9SAhmed S. Darwish 	}
36219d57a7f9SAhmed S. Darwish 
36229d57a7f9SAhmed S. Darwish 	return 0;
36239d57a7f9SAhmed S. Darwish }
36249d57a7f9SAhmed S. Darwish 
selinux_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)362590462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3626376bd9cbSDarrel Goeddel {
3627aa8e712cSStephen Smalley 	struct selinux_state *state = &selinux_state;
36281b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3629376bd9cbSDarrel Goeddel 	struct context *ctxt;
3630376bd9cbSDarrel Goeddel 	struct mls_level *level;
36319d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
3632376bd9cbSDarrel Goeddel 	int match = 0;
3633376bd9cbSDarrel Goeddel 
36349ad42a79SRichard Guy Briggs 	if (unlikely(!rule)) {
36359ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3636376bd9cbSDarrel Goeddel 		return -ENOENT;
3637376bd9cbSDarrel Goeddel 	}
3638376bd9cbSDarrel Goeddel 
3639e67b7985SStephen Smalley 	if (!selinux_initialized())
364037ea433cSStephen Smalley 		return 0;
364137ea433cSStephen Smalley 
36421b8b31a2SStephen Smalley 	rcu_read_lock();
3643376bd9cbSDarrel Goeddel 
36441b8b31a2SStephen Smalley 	policy = rcu_dereference(state->policy);
36451b8b31a2SStephen Smalley 
36461b8b31a2SStephen Smalley 	if (rule->au_seqno < policy->latest_granting) {
3647376bd9cbSDarrel Goeddel 		match = -ESTALE;
3648376bd9cbSDarrel Goeddel 		goto out;
3649376bd9cbSDarrel Goeddel 	}
3650376bd9cbSDarrel Goeddel 
36511b8b31a2SStephen Smalley 	ctxt = sidtab_search(policy->sidtab, sid);
36529ad42a79SRichard Guy Briggs 	if (unlikely(!ctxt)) {
36539ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
36549a2f44f0SStephen Smalley 			  sid);
3655376bd9cbSDarrel Goeddel 		match = -ENOENT;
3656376bd9cbSDarrel Goeddel 		goto out;
3657376bd9cbSDarrel Goeddel 	}
3658376bd9cbSDarrel Goeddel 
3659376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
3660376bd9cbSDarrel Goeddel 	   without a match */
3661376bd9cbSDarrel Goeddel 	switch (field) {
36623a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
36636e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3664376bd9cbSDarrel Goeddel 		switch (op) {
36655af75d8dSAl Viro 		case Audit_equal:
3666376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
3667376bd9cbSDarrel Goeddel 			break;
36685af75d8dSAl Viro 		case Audit_not_equal:
3669376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
3670376bd9cbSDarrel Goeddel 			break;
3671376bd9cbSDarrel Goeddel 		}
3672376bd9cbSDarrel Goeddel 		break;
36733a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
36746e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3675376bd9cbSDarrel Goeddel 		switch (op) {
36765af75d8dSAl Viro 		case Audit_equal:
3677376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
3678376bd9cbSDarrel Goeddel 			break;
36795af75d8dSAl Viro 		case Audit_not_equal:
3680376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
3681376bd9cbSDarrel Goeddel 			break;
3682376bd9cbSDarrel Goeddel 		}
3683376bd9cbSDarrel Goeddel 		break;
36843a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
36856e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3686376bd9cbSDarrel Goeddel 		switch (op) {
36875af75d8dSAl Viro 		case Audit_equal:
3688376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
3689376bd9cbSDarrel Goeddel 			break;
36905af75d8dSAl Viro 		case Audit_not_equal:
3691376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
3692376bd9cbSDarrel Goeddel 			break;
3693376bd9cbSDarrel Goeddel 		}
3694376bd9cbSDarrel Goeddel 		break;
36953a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
36963a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
36976e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
36986e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
36996e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
37006e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
3701376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3702376bd9cbSDarrel Goeddel 		switch (op) {
37035af75d8dSAl Viro 		case Audit_equal:
3704376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3705376bd9cbSDarrel Goeddel 					     level);
3706376bd9cbSDarrel Goeddel 			break;
37075af75d8dSAl Viro 		case Audit_not_equal:
3708376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3709376bd9cbSDarrel Goeddel 					      level);
3710376bd9cbSDarrel Goeddel 			break;
37115af75d8dSAl Viro 		case Audit_lt:
3712376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3713376bd9cbSDarrel Goeddel 					       level) &&
3714376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3715376bd9cbSDarrel Goeddel 					       level));
3716376bd9cbSDarrel Goeddel 			break;
37175af75d8dSAl Viro 		case Audit_le:
3718376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3719376bd9cbSDarrel Goeddel 					      level);
3720376bd9cbSDarrel Goeddel 			break;
37215af75d8dSAl Viro 		case Audit_gt:
3722376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
3723376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
3724376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
3725376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
3726376bd9cbSDarrel Goeddel 			break;
37275af75d8dSAl Viro 		case Audit_ge:
3728376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
3729376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
3730376bd9cbSDarrel Goeddel 			break;
3731376bd9cbSDarrel Goeddel 		}
3732376bd9cbSDarrel Goeddel 	}
3733376bd9cbSDarrel Goeddel 
3734376bd9cbSDarrel Goeddel out:
37351b8b31a2SStephen Smalley 	rcu_read_unlock();
3736376bd9cbSDarrel Goeddel 	return match;
3737376bd9cbSDarrel Goeddel }
3738376bd9cbSDarrel Goeddel 
aurule_avc_callback(u32 event)3739562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3740376bd9cbSDarrel Goeddel {
37413c797e51SOndrej Mosnacek 	if (event == AVC_CALLBACK_RESET)
37423c797e51SOndrej Mosnacek 		return audit_update_lsm_rules();
37433c797e51SOndrej Mosnacek 	return 0;
3744376bd9cbSDarrel Goeddel }
3745376bd9cbSDarrel Goeddel 
aurule_init(void)3746376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3747376bd9cbSDarrel Goeddel {
3748376bd9cbSDarrel Goeddel 	int err;
3749376bd9cbSDarrel Goeddel 
3750562c99f2SWanlong Gao 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3751376bd9cbSDarrel Goeddel 	if (err)
3752376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
3753376bd9cbSDarrel Goeddel 
3754376bd9cbSDarrel Goeddel 	return err;
3755376bd9cbSDarrel Goeddel }
3756376bd9cbSDarrel Goeddel __initcall(aurule_init);
3757376bd9cbSDarrel Goeddel 
37587420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
37597420ed23SVenkat Yekkirala /**
37605778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
37615778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
37625dbe1eb0SPaul Moore  * @sid: the SELinux SID
37637420ed23SVenkat Yekkirala  *
37647420ed23SVenkat Yekkirala  * Description:
37657420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
37665778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
37675778eabdSPaul Moore  * already been initialized.
37687420ed23SVenkat Yekkirala  *
37697420ed23SVenkat Yekkirala  */
security_netlbl_cache_add(struct netlbl_lsm_secattr * secattr,u32 sid)37705778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
37715dbe1eb0SPaul Moore 				      u32 sid)
37727420ed23SVenkat Yekkirala {
37735dbe1eb0SPaul Moore 	u32 *sid_cache;
37747420ed23SVenkat Yekkirala 
37755dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
37765dbe1eb0SPaul Moore 	if (sid_cache == NULL)
37775dbe1eb0SPaul Moore 		return;
37785778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
37795dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
37805dbe1eb0SPaul Moore 		kfree(sid_cache);
37815778eabdSPaul Moore 		return;
37820ec8abd7SJesper Juhl 	}
37837420ed23SVenkat Yekkirala 
37845dbe1eb0SPaul Moore 	*sid_cache = sid;
37855dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
37865dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
37875778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
37887420ed23SVenkat Yekkirala }
37897420ed23SVenkat Yekkirala 
37907420ed23SVenkat Yekkirala /**
37915778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
37927420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
37937420ed23SVenkat Yekkirala  * @sid: the SELinux SID
37947420ed23SVenkat Yekkirala  *
37957420ed23SVenkat Yekkirala  * Description:
37965778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
37977420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
379825985edcSLucas De Marchi  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
37995dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
38005dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
38015dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
38025dbe1eb0SPaul Moore  * failure.
38037420ed23SVenkat Yekkirala  *
38047420ed23SVenkat Yekkirala  */
security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr * secattr,u32 * sid)3805e67b7985SStephen Smalley int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
38067420ed23SVenkat Yekkirala 				   u32 *sid)
38077420ed23SVenkat Yekkirala {
38081b8b31a2SStephen Smalley 	struct selinux_policy *policy;
380946169802SStephen Smalley 	struct policydb *policydb;
381046169802SStephen Smalley 	struct sidtab *sidtab;
38117ae9f23cSEric Paris 	int rc;
38127420ed23SVenkat Yekkirala 	struct context *ctx;
38137420ed23SVenkat Yekkirala 	struct context ctx_new;
38145778eabdSPaul Moore 
3815e67b7985SStephen Smalley 	if (!selinux_initialized()) {
38165778eabdSPaul Moore 		*sid = SECSID_NULL;
38175778eabdSPaul Moore 		return 0;
38185778eabdSPaul Moore 	}
38197420ed23SVenkat Yekkirala 
38209ad6e9cbSOndrej Mosnacek retry:
38219ad6e9cbSOndrej Mosnacek 	rc = 0;
38221b8b31a2SStephen Smalley 	rcu_read_lock();
3823e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
38241b8b31a2SStephen Smalley 	policydb = &policy->policydb;
38251b8b31a2SStephen Smalley 	sidtab = policy->sidtab;
382646169802SStephen Smalley 
38277ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
38285dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
38297ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
383016efd454SPaul Moore 		*sid = secattr->attr.secid;
38317ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
38327ae9f23cSEric Paris 		rc = -EIDRM;
3833aa8e712cSStephen Smalley 		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
38347420ed23SVenkat Yekkirala 		if (ctx == NULL)
38357ae9f23cSEric Paris 			goto out;
38367420ed23SVenkat Yekkirala 
383781990fbdSPaul Moore 		context_init(&ctx_new);
38387420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
38397420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
38407420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
3841aa8e712cSStephen Smalley 		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3842701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3843aa8e712cSStephen Smalley 			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
38447ae9f23cSEric Paris 			if (rc)
38457ae9f23cSEric Paris 				goto out;
38467420ed23SVenkat Yekkirala 		}
38477ae9f23cSEric Paris 		rc = -EIDRM;
38489ad6e9cbSOndrej Mosnacek 		if (!mls_context_isvalid(policydb, &ctx_new)) {
38499ad6e9cbSOndrej Mosnacek 			ebitmap_destroy(&ctx_new.range.level[0].cat);
38509ad6e9cbSOndrej Mosnacek 			goto out;
38519ad6e9cbSOndrej Mosnacek 		}
38527420ed23SVenkat Yekkirala 
3853225621c9SOndrej Mosnacek 		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
38549ad6e9cbSOndrej Mosnacek 		ebitmap_destroy(&ctx_new.range.level[0].cat);
38559ad6e9cbSOndrej Mosnacek 		if (rc == -ESTALE) {
38569ad6e9cbSOndrej Mosnacek 			rcu_read_unlock();
38579ad6e9cbSOndrej Mosnacek 			goto retry;
38589ad6e9cbSOndrej Mosnacek 		}
38597ae9f23cSEric Paris 		if (rc)
38609ad6e9cbSOndrej Mosnacek 			goto out;
38617420ed23SVenkat Yekkirala 
38625dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
38637ae9f23cSEric Paris 	} else
3864388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
38657420ed23SVenkat Yekkirala 
38667ae9f23cSEric Paris out:
38671b8b31a2SStephen Smalley 	rcu_read_unlock();
38687420ed23SVenkat Yekkirala 	return rc;
38697420ed23SVenkat Yekkirala }
38707420ed23SVenkat Yekkirala 
38717420ed23SVenkat Yekkirala /**
38725778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
38735778eabdSPaul Moore  * @sid: the SELinux SID
38745778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
38757420ed23SVenkat Yekkirala  *
38767420ed23SVenkat Yekkirala  * Description:
38775778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
38785778eabdSPaul Moore  * Returns zero on success, negative values on failure.
38797420ed23SVenkat Yekkirala  *
38807420ed23SVenkat Yekkirala  */
security_netlbl_sid_to_secattr(u32 sid,struct netlbl_lsm_secattr * secattr)3881e67b7985SStephen Smalley int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
38827420ed23SVenkat Yekkirala {
38831b8b31a2SStephen Smalley 	struct selinux_policy *policy;
388446169802SStephen Smalley 	struct policydb *policydb;
388599d854d2SPaul Moore 	int rc;
38867420ed23SVenkat Yekkirala 	struct context *ctx;
38877420ed23SVenkat Yekkirala 
3888e67b7985SStephen Smalley 	if (!selinux_initialized())
38897420ed23SVenkat Yekkirala 		return 0;
38907420ed23SVenkat Yekkirala 
38911b8b31a2SStephen Smalley 	rcu_read_lock();
3892e67b7985SStephen Smalley 	policy = rcu_dereference(selinux_state.policy);
38931b8b31a2SStephen Smalley 	policydb = &policy->policydb;
389446169802SStephen Smalley 
389599d854d2SPaul Moore 	rc = -ENOENT;
38961b8b31a2SStephen Smalley 	ctx = sidtab_search(policy->sidtab, sid);
38974b02b524SEric Paris 	if (ctx == NULL)
38984b02b524SEric Paris 		goto out;
38994b02b524SEric Paris 
39004b02b524SEric Paris 	rc = -ENOMEM;
3901aa8e712cSStephen Smalley 	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
39027420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
39034b02b524SEric Paris 	if (secattr->domain == NULL)
39044b02b524SEric Paris 		goto out;
39054b02b524SEric Paris 
39068d75899dSPaul Moore 	secattr->attr.secid = sid;
39078d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3908aa8e712cSStephen Smalley 	mls_export_netlbl_lvl(policydb, ctx, secattr);
3909aa8e712cSStephen Smalley 	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
39104b02b524SEric Paris out:
39111b8b31a2SStephen Smalley 	rcu_read_unlock();
3912f8687afeSPaul Moore 	return rc;
3913f8687afeSPaul Moore }
39147420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3915cee74f47SEric Paris 
3916cee74f47SEric Paris /**
3917fdd1ffe8SLakshmi Ramasubramanian  * __security_read_policy - read the policy.
3918fdd1ffe8SLakshmi Ramasubramanian  * @policy: SELinux policy
3919fdd1ffe8SLakshmi Ramasubramanian  * @data: binary policy data
3920fdd1ffe8SLakshmi Ramasubramanian  * @len: length of data in bytes
3921fdd1ffe8SLakshmi Ramasubramanian  *
3922fdd1ffe8SLakshmi Ramasubramanian  */
__security_read_policy(struct selinux_policy * policy,void * data,size_t * len)3923fdd1ffe8SLakshmi Ramasubramanian static int __security_read_policy(struct selinux_policy *policy,
3924fdd1ffe8SLakshmi Ramasubramanian 				  void *data, size_t *len)
3925fdd1ffe8SLakshmi Ramasubramanian {
3926fdd1ffe8SLakshmi Ramasubramanian 	int rc;
3927fdd1ffe8SLakshmi Ramasubramanian 	struct policy_file fp;
3928fdd1ffe8SLakshmi Ramasubramanian 
3929fdd1ffe8SLakshmi Ramasubramanian 	fp.data = data;
3930fdd1ffe8SLakshmi Ramasubramanian 	fp.len = *len;
3931fdd1ffe8SLakshmi Ramasubramanian 
3932fdd1ffe8SLakshmi Ramasubramanian 	rc = policydb_write(&policy->policydb, &fp);
3933fdd1ffe8SLakshmi Ramasubramanian 	if (rc)
3934fdd1ffe8SLakshmi Ramasubramanian 		return rc;
3935fdd1ffe8SLakshmi Ramasubramanian 
3936fdd1ffe8SLakshmi Ramasubramanian 	*len = (unsigned long)fp.data - (unsigned long)data;
3937fdd1ffe8SLakshmi Ramasubramanian 	return 0;
3938fdd1ffe8SLakshmi Ramasubramanian }
3939fdd1ffe8SLakshmi Ramasubramanian 
3940fdd1ffe8SLakshmi Ramasubramanian /**
3941cee74f47SEric Paris  * security_read_policy - read the policy.
3942cee74f47SEric Paris  * @data: binary policy data
3943cee74f47SEric Paris  * @len: length of data in bytes
3944cee74f47SEric Paris  *
3945cee74f47SEric Paris  */
security_read_policy(void ** data,size_t * len)3946e67b7985SStephen Smalley int security_read_policy(void **data, size_t *len)
3947cee74f47SEric Paris {
3948e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
39491b8b31a2SStephen Smalley 	struct selinux_policy *policy;
3950cee74f47SEric Paris 
395166ccd256SOndrej Mosnacek 	policy = rcu_dereference_protected(
395266ccd256SOndrej Mosnacek 			state->policy, lockdep_is_held(&state->policy_mutex));
395366ccd256SOndrej Mosnacek 	if (!policy)
3954cee74f47SEric Paris 		return -EINVAL;
3955cee74f47SEric Paris 
395666ccd256SOndrej Mosnacek 	*len = policy->policydb.len;
3957845ca30fSEric Paris 	*data = vmalloc_user(*len);
3958cee74f47SEric Paris 	if (!*data)
3959cee74f47SEric Paris 		return -ENOMEM;
3960cee74f47SEric Paris 
3961fdd1ffe8SLakshmi Ramasubramanian 	return __security_read_policy(policy, *data, len);
3962fdd1ffe8SLakshmi Ramasubramanian }
3963cee74f47SEric Paris 
3964fdd1ffe8SLakshmi Ramasubramanian /**
3965fdd1ffe8SLakshmi Ramasubramanian  * security_read_state_kernel - read the policy.
3966fdd1ffe8SLakshmi Ramasubramanian  * @data: binary policy data
3967fdd1ffe8SLakshmi Ramasubramanian  * @len: length of data in bytes
3968fdd1ffe8SLakshmi Ramasubramanian  *
3969fdd1ffe8SLakshmi Ramasubramanian  * Allocates kernel memory for reading SELinux policy.
3970fdd1ffe8SLakshmi Ramasubramanian  * This function is for internal use only and should not
3971fdd1ffe8SLakshmi Ramasubramanian  * be used for returning data to user space.
3972fdd1ffe8SLakshmi Ramasubramanian  *
3973fdd1ffe8SLakshmi Ramasubramanian  * This function must be called with policy_mutex held.
3974fdd1ffe8SLakshmi Ramasubramanian  */
security_read_state_kernel(void ** data,size_t * len)3975e67b7985SStephen Smalley int security_read_state_kernel(void **data, size_t *len)
3976fdd1ffe8SLakshmi Ramasubramanian {
397773de1befSXiu Jianfeng 	int err;
3978e67b7985SStephen Smalley 	struct selinux_state *state = &selinux_state;
3979fdd1ffe8SLakshmi Ramasubramanian 	struct selinux_policy *policy;
3980cee74f47SEric Paris 
3981fdd1ffe8SLakshmi Ramasubramanian 	policy = rcu_dereference_protected(
3982fdd1ffe8SLakshmi Ramasubramanian 			state->policy, lockdep_is_held(&state->policy_mutex));
3983fdd1ffe8SLakshmi Ramasubramanian 	if (!policy)
3984fdd1ffe8SLakshmi Ramasubramanian 		return -EINVAL;
3985cee74f47SEric Paris 
3986fdd1ffe8SLakshmi Ramasubramanian 	*len = policy->policydb.len;
3987fdd1ffe8SLakshmi Ramasubramanian 	*data = vmalloc(*len);
3988fdd1ffe8SLakshmi Ramasubramanian 	if (!*data)
3989fdd1ffe8SLakshmi Ramasubramanian 		return -ENOMEM;
3990fdd1ffe8SLakshmi Ramasubramanian 
399173de1befSXiu Jianfeng 	err = __security_read_policy(policy, *data, len);
399273de1befSXiu Jianfeng 	if (err) {
399373de1befSXiu Jianfeng 		vfree(*data);
399473de1befSXiu Jianfeng 		*data = NULL;
399573de1befSXiu Jianfeng 		*len = 0;
399673de1befSXiu Jianfeng 	}
399773de1befSXiu Jianfeng 	return err;
3998cee74f47SEric Paris }
3999