xref: /openbmc/linux/security/selinux/ss/services.c (revision f31e799459659ae88c341aeac16a8a5efb1271d4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Implementation of the security services.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
51da177e4SLinus Torvalds  *	     James Morris <jmorris@redhat.com>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Support for enhanced MLS infrastructure.
10376bd9cbSDarrel Goeddel  *	Support for context based audit filters.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *	Added conditional policy language extensions
151da177e4SLinus Torvalds  *
1682c21bfaSPaul Moore  * Updated: Hewlett-Packard <paul@paul-moore.com>
177420ed23SVenkat Yekkirala  *
187420ed23SVenkat Yekkirala  *      Added support for NetLabel
193bb56b25SPaul Moore  *      Added support for the policy capability bitmap
207420ed23SVenkat Yekkirala  *
21b94c7e67SChad Sellers  * Updated: Chad Sellers <csellers@tresys.com>
22b94c7e67SChad Sellers  *
23b94c7e67SChad Sellers  *  Added validation of kernel classes and permissions
24b94c7e67SChad Sellers  *
2544c2d9bdSKaiGai Kohei  * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
2644c2d9bdSKaiGai Kohei  *
2744c2d9bdSKaiGai Kohei  *  Added support for bounds domain and audit messaged on masked permissions
2844c2d9bdSKaiGai Kohei  *
290719aaf5SGuido Trentalancia  * Updated: Guido Trentalancia <guido@trentalancia.com>
300719aaf5SGuido Trentalancia  *
310719aaf5SGuido Trentalancia  *  Added support for runtime switching of the policy type
320719aaf5SGuido Trentalancia  *
3344c2d9bdSKaiGai Kohei  * Copyright (C) 2008, 2009 NEC Corporation
343bb56b25SPaul Moore  * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
35376bd9cbSDarrel Goeddel  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
36b94c7e67SChad Sellers  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
371da177e4SLinus Torvalds  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
381da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or modify
391da177e4SLinus Torvalds  *	it under the terms of the GNU General Public License as published by
401da177e4SLinus Torvalds  *	the Free Software Foundation, version 2.
411da177e4SLinus Torvalds  */
421da177e4SLinus Torvalds #include <linux/kernel.h>
431da177e4SLinus Torvalds #include <linux/slab.h>
441da177e4SLinus Torvalds #include <linux/string.h>
451da177e4SLinus Torvalds #include <linux/spinlock.h>
469f2ad665SPaul Moore #include <linux/rcupdate.h>
471da177e4SLinus Torvalds #include <linux/errno.h>
481da177e4SLinus Torvalds #include <linux/in.h>
491da177e4SLinus Torvalds #include <linux/sched.h>
501da177e4SLinus Torvalds #include <linux/audit.h>
51bb003079SIngo Molnar #include <linux/mutex.h>
520e55a004SAdrian Bunk #include <linux/selinux.h>
536371dcd3SEric Paris #include <linux/flex_array.h>
54f0d3d989SStephen Rothwell #include <linux/vmalloc.h>
557420ed23SVenkat Yekkirala #include <net/netlabel.h>
56bb003079SIngo Molnar 
571da177e4SLinus Torvalds #include "flask.h"
581da177e4SLinus Torvalds #include "avc.h"
591da177e4SLinus Torvalds #include "avc_ss.h"
601da177e4SLinus Torvalds #include "security.h"
611da177e4SLinus Torvalds #include "context.h"
621da177e4SLinus Torvalds #include "policydb.h"
631da177e4SLinus Torvalds #include "sidtab.h"
641da177e4SLinus Torvalds #include "services.h"
651da177e4SLinus Torvalds #include "conditional.h"
661da177e4SLinus Torvalds #include "mls.h"
677420ed23SVenkat Yekkirala #include "objsec.h"
68c60475bfSPaul Moore #include "netlabel.h"
693de4bab5SPaul Moore #include "xfrm.h"
7002752760SPaul Moore #include "ebitmap.h"
719d57a7f9SAhmed S. Darwish #include "audit.h"
721da177e4SLinus Torvalds 
733bb56b25SPaul Moore int selinux_policycap_netpeer;
74b0c636b9SEric Paris int selinux_policycap_openperm;
752be4d74fSChris PeBenito int selinux_policycap_alwaysnetwork;
763bb56b25SPaul Moore 
771da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static struct sidtab sidtab;
801da177e4SLinus Torvalds struct policydb policydb;
815d55a345SEric Paris int ss_initialized;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /*
841da177e4SLinus Torvalds  * The largest sequence number that has been used when
851da177e4SLinus Torvalds  * providing an access decision to the access vector cache.
861da177e4SLinus Torvalds  * The sequence number only changes when a policy change
871da177e4SLinus Torvalds  * occurs.
881da177e4SLinus Torvalds  */
895d55a345SEric Paris static u32 latest_granting;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds /* Forward declaration. */
921da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext,
931da177e4SLinus Torvalds 				    u32 *scontext_len);
941da177e4SLinus Torvalds 
9519439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext,
96d9250deaSKaiGai Kohei 				      struct context *tcontext,
97d9250deaSKaiGai Kohei 				      u16 tclass,
98d9250deaSKaiGai Kohei 				      struct av_decision *avd);
99c6d3aaa4SStephen Smalley 
100c6d3aaa4SStephen Smalley struct selinux_mapping {
101c6d3aaa4SStephen Smalley 	u16 value; /* policy value */
102c6d3aaa4SStephen Smalley 	unsigned num_perms;
103c6d3aaa4SStephen Smalley 	u32 perms[sizeof(u32) * 8];
104c6d3aaa4SStephen Smalley };
105c6d3aaa4SStephen Smalley 
106c6d3aaa4SStephen Smalley static struct selinux_mapping *current_mapping;
107c6d3aaa4SStephen Smalley static u16 current_mapping_size;
108c6d3aaa4SStephen Smalley 
109c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol,
110c6d3aaa4SStephen Smalley 			       struct security_class_mapping *map,
111c6d3aaa4SStephen Smalley 			       struct selinux_mapping **out_map_p,
112c6d3aaa4SStephen Smalley 			       u16 *out_map_size)
113c6d3aaa4SStephen Smalley {
114c6d3aaa4SStephen Smalley 	struct selinux_mapping *out_map = NULL;
115c6d3aaa4SStephen Smalley 	size_t size = sizeof(struct selinux_mapping);
116c6d3aaa4SStephen Smalley 	u16 i, j;
117c6d3aaa4SStephen Smalley 	unsigned k;
118c6d3aaa4SStephen Smalley 	bool print_unknown_handle = false;
119c6d3aaa4SStephen Smalley 
120c6d3aaa4SStephen Smalley 	/* Find number of classes in the input mapping */
121c6d3aaa4SStephen Smalley 	if (!map)
122c6d3aaa4SStephen Smalley 		return -EINVAL;
123c6d3aaa4SStephen Smalley 	i = 0;
124c6d3aaa4SStephen Smalley 	while (map[i].name)
125c6d3aaa4SStephen Smalley 		i++;
126c6d3aaa4SStephen Smalley 
127c6d3aaa4SStephen Smalley 	/* Allocate space for the class records, plus one for class zero */
128c6d3aaa4SStephen Smalley 	out_map = kcalloc(++i, size, GFP_ATOMIC);
129c6d3aaa4SStephen Smalley 	if (!out_map)
130c6d3aaa4SStephen Smalley 		return -ENOMEM;
131c6d3aaa4SStephen Smalley 
132c6d3aaa4SStephen Smalley 	/* Store the raw class and permission values */
133c6d3aaa4SStephen Smalley 	j = 0;
134c6d3aaa4SStephen Smalley 	while (map[j].name) {
135c6d3aaa4SStephen Smalley 		struct security_class_mapping *p_in = map + (j++);
136c6d3aaa4SStephen Smalley 		struct selinux_mapping *p_out = out_map + j;
137c6d3aaa4SStephen Smalley 
138c6d3aaa4SStephen Smalley 		/* An empty class string skips ahead */
139c6d3aaa4SStephen Smalley 		if (!strcmp(p_in->name, "")) {
140c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
141c6d3aaa4SStephen Smalley 			continue;
142c6d3aaa4SStephen Smalley 		}
143c6d3aaa4SStephen Smalley 
144c6d3aaa4SStephen Smalley 		p_out->value = string_to_security_class(pol, p_in->name);
145c6d3aaa4SStephen Smalley 		if (!p_out->value) {
146c6d3aaa4SStephen Smalley 			printk(KERN_INFO
147c6d3aaa4SStephen Smalley 			       "SELinux:  Class %s not defined in policy.\n",
148c6d3aaa4SStephen Smalley 			       p_in->name);
149c6d3aaa4SStephen Smalley 			if (pol->reject_unknown)
150c6d3aaa4SStephen Smalley 				goto err;
151c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
152c6d3aaa4SStephen Smalley 			print_unknown_handle = true;
153c6d3aaa4SStephen Smalley 			continue;
154c6d3aaa4SStephen Smalley 		}
155c6d3aaa4SStephen Smalley 
156c6d3aaa4SStephen Smalley 		k = 0;
157c6d3aaa4SStephen Smalley 		while (p_in->perms && p_in->perms[k]) {
158c6d3aaa4SStephen Smalley 			/* An empty permission string skips ahead */
159c6d3aaa4SStephen Smalley 			if (!*p_in->perms[k]) {
160c6d3aaa4SStephen Smalley 				k++;
161c6d3aaa4SStephen Smalley 				continue;
162c6d3aaa4SStephen Smalley 			}
163c6d3aaa4SStephen Smalley 			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
164c6d3aaa4SStephen Smalley 							    p_in->perms[k]);
165c6d3aaa4SStephen Smalley 			if (!p_out->perms[k]) {
166c6d3aaa4SStephen Smalley 				printk(KERN_INFO
167c6d3aaa4SStephen Smalley 				       "SELinux:  Permission %s in class %s not defined in policy.\n",
168c6d3aaa4SStephen Smalley 				       p_in->perms[k], p_in->name);
169c6d3aaa4SStephen Smalley 				if (pol->reject_unknown)
170c6d3aaa4SStephen Smalley 					goto err;
171c6d3aaa4SStephen Smalley 				print_unknown_handle = true;
172c6d3aaa4SStephen Smalley 			}
173c6d3aaa4SStephen Smalley 
174c6d3aaa4SStephen Smalley 			k++;
175c6d3aaa4SStephen Smalley 		}
176c6d3aaa4SStephen Smalley 		p_out->num_perms = k;
177c6d3aaa4SStephen Smalley 	}
178c6d3aaa4SStephen Smalley 
179c6d3aaa4SStephen Smalley 	if (print_unknown_handle)
180c6d3aaa4SStephen Smalley 		printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
181c6d3aaa4SStephen Smalley 		       pol->allow_unknown ? "allowed" : "denied");
182c6d3aaa4SStephen Smalley 
183c6d3aaa4SStephen Smalley 	*out_map_p = out_map;
184c6d3aaa4SStephen Smalley 	*out_map_size = i;
185c6d3aaa4SStephen Smalley 	return 0;
186c6d3aaa4SStephen Smalley err:
187c6d3aaa4SStephen Smalley 	kfree(out_map);
188c6d3aaa4SStephen Smalley 	return -EINVAL;
189c6d3aaa4SStephen Smalley }
190c6d3aaa4SStephen Smalley 
191c6d3aaa4SStephen Smalley /*
192c6d3aaa4SStephen Smalley  * Get real, policy values from mapped values
193c6d3aaa4SStephen Smalley  */
194c6d3aaa4SStephen Smalley 
195c6d3aaa4SStephen Smalley static u16 unmap_class(u16 tclass)
196c6d3aaa4SStephen Smalley {
197c6d3aaa4SStephen Smalley 	if (tclass < current_mapping_size)
198c6d3aaa4SStephen Smalley 		return current_mapping[tclass].value;
199c6d3aaa4SStephen Smalley 
200c6d3aaa4SStephen Smalley 	return tclass;
201c6d3aaa4SStephen Smalley }
202c6d3aaa4SStephen Smalley 
2036f5317e7SHarry Ciao /*
2046f5317e7SHarry Ciao  * Get kernel value for class from its policy value
2056f5317e7SHarry Ciao  */
2066f5317e7SHarry Ciao static u16 map_class(u16 pol_value)
2076f5317e7SHarry Ciao {
2086f5317e7SHarry Ciao 	u16 i;
2096f5317e7SHarry Ciao 
2106f5317e7SHarry Ciao 	for (i = 1; i < current_mapping_size; i++) {
2116f5317e7SHarry Ciao 		if (current_mapping[i].value == pol_value)
2126f5317e7SHarry Ciao 			return i;
2136f5317e7SHarry Ciao 	}
2146f5317e7SHarry Ciao 
21585cd6da5SStephen Smalley 	return SECCLASS_NULL;
2166f5317e7SHarry Ciao }
2176f5317e7SHarry Ciao 
218c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd,
219c6d3aaa4SStephen Smalley 			 int allow_unknown)
220c6d3aaa4SStephen Smalley {
221c6d3aaa4SStephen Smalley 	if (tclass < current_mapping_size) {
222c6d3aaa4SStephen Smalley 		unsigned i, n = current_mapping[tclass].num_perms;
223c6d3aaa4SStephen Smalley 		u32 result;
224c6d3aaa4SStephen Smalley 
225c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
226c6d3aaa4SStephen Smalley 			if (avd->allowed & current_mapping[tclass].perms[i])
227c6d3aaa4SStephen Smalley 				result |= 1<<i;
228c6d3aaa4SStephen Smalley 			if (allow_unknown && !current_mapping[tclass].perms[i])
229c6d3aaa4SStephen Smalley 				result |= 1<<i;
230c6d3aaa4SStephen Smalley 		}
231c6d3aaa4SStephen Smalley 		avd->allowed = result;
232c6d3aaa4SStephen Smalley 
233c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++)
234c6d3aaa4SStephen Smalley 			if (avd->auditallow & current_mapping[tclass].perms[i])
235c6d3aaa4SStephen Smalley 				result |= 1<<i;
236c6d3aaa4SStephen Smalley 		avd->auditallow = result;
237c6d3aaa4SStephen Smalley 
238c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
239c6d3aaa4SStephen Smalley 			if (avd->auditdeny & current_mapping[tclass].perms[i])
240c6d3aaa4SStephen Smalley 				result |= 1<<i;
241c6d3aaa4SStephen Smalley 			if (!allow_unknown && !current_mapping[tclass].perms[i])
242c6d3aaa4SStephen Smalley 				result |= 1<<i;
243c6d3aaa4SStephen Smalley 		}
2440bce9527SEric Paris 		/*
2450bce9527SEric Paris 		 * In case the kernel has a bug and requests a permission
2460bce9527SEric Paris 		 * between num_perms and the maximum permission number, we
2470bce9527SEric Paris 		 * should audit that denial
2480bce9527SEric Paris 		 */
2490bce9527SEric Paris 		for (; i < (sizeof(u32)*8); i++)
2500bce9527SEric Paris 			result |= 1<<i;
251c6d3aaa4SStephen Smalley 		avd->auditdeny = result;
252c6d3aaa4SStephen Smalley 	}
253c6d3aaa4SStephen Smalley }
254c6d3aaa4SStephen Smalley 
2550719aaf5SGuido Trentalancia int security_mls_enabled(void)
2560719aaf5SGuido Trentalancia {
2570719aaf5SGuido Trentalancia 	return policydb.mls_enabled;
2580719aaf5SGuido Trentalancia }
259c6d3aaa4SStephen Smalley 
2601da177e4SLinus Torvalds /*
2611da177e4SLinus Torvalds  * Return the boolean value of a constraint expression
2621da177e4SLinus Torvalds  * when it is applied to the specified source and target
2631da177e4SLinus Torvalds  * security contexts.
2641da177e4SLinus Torvalds  *
2651da177e4SLinus Torvalds  * xcontext is a special beast...  It is used by the validatetrans rules
2661da177e4SLinus Torvalds  * only.  For these rules, scontext is the context before the transition,
2671da177e4SLinus Torvalds  * tcontext is the context after the transition, and xcontext is the context
2681da177e4SLinus Torvalds  * of the process performing the transition.  All other callers of
2691da177e4SLinus Torvalds  * constraint_expr_eval should pass in NULL for xcontext.
2701da177e4SLinus Torvalds  */
2711da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext,
2721da177e4SLinus Torvalds 				struct context *tcontext,
2731da177e4SLinus Torvalds 				struct context *xcontext,
2741da177e4SLinus Torvalds 				struct constraint_expr *cexpr)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	u32 val1, val2;
2771da177e4SLinus Torvalds 	struct context *c;
2781da177e4SLinus Torvalds 	struct role_datum *r1, *r2;
2791da177e4SLinus Torvalds 	struct mls_level *l1, *l2;
2801da177e4SLinus Torvalds 	struct constraint_expr *e;
2811da177e4SLinus Torvalds 	int s[CEXPR_MAXDEPTH];
2821da177e4SLinus Torvalds 	int sp = -1;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	for (e = cexpr; e; e = e->next) {
2851da177e4SLinus Torvalds 		switch (e->expr_type) {
2861da177e4SLinus Torvalds 		case CEXPR_NOT:
2871da177e4SLinus Torvalds 			BUG_ON(sp < 0);
2881da177e4SLinus Torvalds 			s[sp] = !s[sp];
2891da177e4SLinus Torvalds 			break;
2901da177e4SLinus Torvalds 		case CEXPR_AND:
2911da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2921da177e4SLinus Torvalds 			sp--;
2931da177e4SLinus Torvalds 			s[sp] &= s[sp + 1];
2941da177e4SLinus Torvalds 			break;
2951da177e4SLinus Torvalds 		case CEXPR_OR:
2961da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2971da177e4SLinus Torvalds 			sp--;
2981da177e4SLinus Torvalds 			s[sp] |= s[sp + 1];
2991da177e4SLinus Torvalds 			break;
3001da177e4SLinus Torvalds 		case CEXPR_ATTR:
3011da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH - 1))
3021da177e4SLinus Torvalds 				return 0;
3031da177e4SLinus Torvalds 			switch (e->attr) {
3041da177e4SLinus Torvalds 			case CEXPR_USER:
3051da177e4SLinus Torvalds 				val1 = scontext->user;
3061da177e4SLinus Torvalds 				val2 = tcontext->user;
3071da177e4SLinus Torvalds 				break;
3081da177e4SLinus Torvalds 			case CEXPR_TYPE:
3091da177e4SLinus Torvalds 				val1 = scontext->type;
3101da177e4SLinus Torvalds 				val2 = tcontext->type;
3111da177e4SLinus Torvalds 				break;
3121da177e4SLinus Torvalds 			case CEXPR_ROLE:
3131da177e4SLinus Torvalds 				val1 = scontext->role;
3141da177e4SLinus Torvalds 				val2 = tcontext->role;
3151da177e4SLinus Torvalds 				r1 = policydb.role_val_to_struct[val1 - 1];
3161da177e4SLinus Torvalds 				r2 = policydb.role_val_to_struct[val2 - 1];
3171da177e4SLinus Torvalds 				switch (e->op) {
3181da177e4SLinus Torvalds 				case CEXPR_DOM:
3191da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r1->dominates,
3201da177e4SLinus Torvalds 								  val2 - 1);
3211da177e4SLinus Torvalds 					continue;
3221da177e4SLinus Torvalds 				case CEXPR_DOMBY:
3231da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r2->dominates,
3241da177e4SLinus Torvalds 								  val1 - 1);
3251da177e4SLinus Torvalds 					continue;
3261da177e4SLinus Torvalds 				case CEXPR_INCOMP:
3271da177e4SLinus Torvalds 					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
3281da177e4SLinus Torvalds 								    val2 - 1) &&
3291da177e4SLinus Torvalds 						   !ebitmap_get_bit(&r2->dominates,
3301da177e4SLinus Torvalds 								    val1 - 1));
3311da177e4SLinus Torvalds 					continue;
3321da177e4SLinus Torvalds 				default:
3331da177e4SLinus Torvalds 					break;
3341da177e4SLinus Torvalds 				}
3351da177e4SLinus Torvalds 				break;
3361da177e4SLinus Torvalds 			case CEXPR_L1L2:
3371da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3381da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3391da177e4SLinus Torvalds 				goto mls_ops;
3401da177e4SLinus Torvalds 			case CEXPR_L1H2:
3411da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3421da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3431da177e4SLinus Torvalds 				goto mls_ops;
3441da177e4SLinus Torvalds 			case CEXPR_H1L2:
3451da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3461da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3471da177e4SLinus Torvalds 				goto mls_ops;
3481da177e4SLinus Torvalds 			case CEXPR_H1H2:
3491da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3501da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3511da177e4SLinus Torvalds 				goto mls_ops;
3521da177e4SLinus Torvalds 			case CEXPR_L1H1:
3531da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3541da177e4SLinus Torvalds 				l2 = &(scontext->range.level[1]);
3551da177e4SLinus Torvalds 				goto mls_ops;
3561da177e4SLinus Torvalds 			case CEXPR_L2H2:
3571da177e4SLinus Torvalds 				l1 = &(tcontext->range.level[0]);
3581da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3591da177e4SLinus Torvalds 				goto mls_ops;
3601da177e4SLinus Torvalds mls_ops:
3611da177e4SLinus Torvalds 			switch (e->op) {
3621da177e4SLinus Torvalds 			case CEXPR_EQ:
3631da177e4SLinus Torvalds 				s[++sp] = mls_level_eq(l1, l2);
3641da177e4SLinus Torvalds 				continue;
3651da177e4SLinus Torvalds 			case CEXPR_NEQ:
3661da177e4SLinus Torvalds 				s[++sp] = !mls_level_eq(l1, l2);
3671da177e4SLinus Torvalds 				continue;
3681da177e4SLinus Torvalds 			case CEXPR_DOM:
3691da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l1, l2);
3701da177e4SLinus Torvalds 				continue;
3711da177e4SLinus Torvalds 			case CEXPR_DOMBY:
3721da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l2, l1);
3731da177e4SLinus Torvalds 				continue;
3741da177e4SLinus Torvalds 			case CEXPR_INCOMP:
3751da177e4SLinus Torvalds 				s[++sp] = mls_level_incomp(l2, l1);
3761da177e4SLinus Torvalds 				continue;
3771da177e4SLinus Torvalds 			default:
3781da177e4SLinus Torvalds 				BUG();
3791da177e4SLinus Torvalds 				return 0;
3801da177e4SLinus Torvalds 			}
3811da177e4SLinus Torvalds 			break;
3821da177e4SLinus Torvalds 			default:
3831da177e4SLinus Torvalds 				BUG();
3841da177e4SLinus Torvalds 				return 0;
3851da177e4SLinus Torvalds 			}
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 			switch (e->op) {
3881da177e4SLinus Torvalds 			case CEXPR_EQ:
3891da177e4SLinus Torvalds 				s[++sp] = (val1 == val2);
3901da177e4SLinus Torvalds 				break;
3911da177e4SLinus Torvalds 			case CEXPR_NEQ:
3921da177e4SLinus Torvalds 				s[++sp] = (val1 != val2);
3931da177e4SLinus Torvalds 				break;
3941da177e4SLinus Torvalds 			default:
3951da177e4SLinus Torvalds 				BUG();
3961da177e4SLinus Torvalds 				return 0;
3971da177e4SLinus Torvalds 			}
3981da177e4SLinus Torvalds 			break;
3991da177e4SLinus Torvalds 		case CEXPR_NAMES:
4001da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH-1))
4011da177e4SLinus Torvalds 				return 0;
4021da177e4SLinus Torvalds 			c = scontext;
4031da177e4SLinus Torvalds 			if (e->attr & CEXPR_TARGET)
4041da177e4SLinus Torvalds 				c = tcontext;
4051da177e4SLinus Torvalds 			else if (e->attr & CEXPR_XTARGET) {
4061da177e4SLinus Torvalds 				c = xcontext;
4071da177e4SLinus Torvalds 				if (!c) {
4081da177e4SLinus Torvalds 					BUG();
4091da177e4SLinus Torvalds 					return 0;
4101da177e4SLinus Torvalds 				}
4111da177e4SLinus Torvalds 			}
4121da177e4SLinus Torvalds 			if (e->attr & CEXPR_USER)
4131da177e4SLinus Torvalds 				val1 = c->user;
4141da177e4SLinus Torvalds 			else if (e->attr & CEXPR_ROLE)
4151da177e4SLinus Torvalds 				val1 = c->role;
4161da177e4SLinus Torvalds 			else if (e->attr & CEXPR_TYPE)
4171da177e4SLinus Torvalds 				val1 = c->type;
4181da177e4SLinus Torvalds 			else {
4191da177e4SLinus Torvalds 				BUG();
4201da177e4SLinus Torvalds 				return 0;
4211da177e4SLinus Torvalds 			}
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 			switch (e->op) {
4241da177e4SLinus Torvalds 			case CEXPR_EQ:
4251da177e4SLinus Torvalds 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
4261da177e4SLinus Torvalds 				break;
4271da177e4SLinus Torvalds 			case CEXPR_NEQ:
4281da177e4SLinus Torvalds 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
4291da177e4SLinus Torvalds 				break;
4301da177e4SLinus Torvalds 			default:
4311da177e4SLinus Torvalds 				BUG();
4321da177e4SLinus Torvalds 				return 0;
4331da177e4SLinus Torvalds 			}
4341da177e4SLinus Torvalds 			break;
4351da177e4SLinus Torvalds 		default:
4361da177e4SLinus Torvalds 			BUG();
4371da177e4SLinus Torvalds 			return 0;
4381da177e4SLinus Torvalds 		}
4391da177e4SLinus Torvalds 	}
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 	BUG_ON(sp != 0);
4421da177e4SLinus Torvalds 	return s[0];
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds /*
44644c2d9bdSKaiGai Kohei  * security_dump_masked_av - dumps masked permissions during
44744c2d9bdSKaiGai Kohei  * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
44844c2d9bdSKaiGai Kohei  */
44944c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args)
45044c2d9bdSKaiGai Kohei {
45144c2d9bdSKaiGai Kohei 	struct perm_datum *pdatum = d;
45244c2d9bdSKaiGai Kohei 	char **permission_names = args;
45344c2d9bdSKaiGai Kohei 
45444c2d9bdSKaiGai Kohei 	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
45544c2d9bdSKaiGai Kohei 
45644c2d9bdSKaiGai Kohei 	permission_names[pdatum->value - 1] = (char *)k;
45744c2d9bdSKaiGai Kohei 
45844c2d9bdSKaiGai Kohei 	return 0;
45944c2d9bdSKaiGai Kohei }
46044c2d9bdSKaiGai Kohei 
46144c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext,
46244c2d9bdSKaiGai Kohei 				    struct context *tcontext,
46344c2d9bdSKaiGai Kohei 				    u16 tclass,
46444c2d9bdSKaiGai Kohei 				    u32 permissions,
46544c2d9bdSKaiGai Kohei 				    const char *reason)
46644c2d9bdSKaiGai Kohei {
46744c2d9bdSKaiGai Kohei 	struct common_datum *common_dat;
46844c2d9bdSKaiGai Kohei 	struct class_datum *tclass_dat;
46944c2d9bdSKaiGai Kohei 	struct audit_buffer *ab;
47044c2d9bdSKaiGai Kohei 	char *tclass_name;
47144c2d9bdSKaiGai Kohei 	char *scontext_name = NULL;
47244c2d9bdSKaiGai Kohei 	char *tcontext_name = NULL;
47344c2d9bdSKaiGai Kohei 	char *permission_names[32];
4742da5d31bSJames Morris 	int index;
4752da5d31bSJames Morris 	u32 length;
47644c2d9bdSKaiGai Kohei 	bool need_comma = false;
47744c2d9bdSKaiGai Kohei 
47844c2d9bdSKaiGai Kohei 	if (!permissions)
47944c2d9bdSKaiGai Kohei 		return;
48044c2d9bdSKaiGai Kohei 
481ac76c05bSEric Paris 	tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
48244c2d9bdSKaiGai Kohei 	tclass_dat = policydb.class_val_to_struct[tclass - 1];
48344c2d9bdSKaiGai Kohei 	common_dat = tclass_dat->comdatum;
48444c2d9bdSKaiGai Kohei 
48544c2d9bdSKaiGai Kohei 	/* init permission_names */
48644c2d9bdSKaiGai Kohei 	if (common_dat &&
48744c2d9bdSKaiGai Kohei 	    hashtab_map(common_dat->permissions.table,
48844c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
48944c2d9bdSKaiGai Kohei 		goto out;
49044c2d9bdSKaiGai Kohei 
49144c2d9bdSKaiGai Kohei 	if (hashtab_map(tclass_dat->permissions.table,
49244c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
49344c2d9bdSKaiGai Kohei 		goto out;
49444c2d9bdSKaiGai Kohei 
49544c2d9bdSKaiGai Kohei 	/* get scontext/tcontext in text form */
49644c2d9bdSKaiGai Kohei 	if (context_struct_to_string(scontext,
49744c2d9bdSKaiGai Kohei 				     &scontext_name, &length) < 0)
49844c2d9bdSKaiGai Kohei 		goto out;
49944c2d9bdSKaiGai Kohei 
50044c2d9bdSKaiGai Kohei 	if (context_struct_to_string(tcontext,
50144c2d9bdSKaiGai Kohei 				     &tcontext_name, &length) < 0)
50244c2d9bdSKaiGai Kohei 		goto out;
50344c2d9bdSKaiGai Kohei 
50444c2d9bdSKaiGai Kohei 	/* audit a message */
50544c2d9bdSKaiGai Kohei 	ab = audit_log_start(current->audit_context,
50644c2d9bdSKaiGai Kohei 			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
50744c2d9bdSKaiGai Kohei 	if (!ab)
50844c2d9bdSKaiGai Kohei 		goto out;
50944c2d9bdSKaiGai Kohei 
51044c2d9bdSKaiGai Kohei 	audit_log_format(ab, "op=security_compute_av reason=%s "
51144c2d9bdSKaiGai Kohei 			 "scontext=%s tcontext=%s tclass=%s perms=",
51244c2d9bdSKaiGai Kohei 			 reason, scontext_name, tcontext_name, tclass_name);
51344c2d9bdSKaiGai Kohei 
51444c2d9bdSKaiGai Kohei 	for (index = 0; index < 32; index++) {
51544c2d9bdSKaiGai Kohei 		u32 mask = (1 << index);
51644c2d9bdSKaiGai Kohei 
51744c2d9bdSKaiGai Kohei 		if ((mask & permissions) == 0)
51844c2d9bdSKaiGai Kohei 			continue;
51944c2d9bdSKaiGai Kohei 
52044c2d9bdSKaiGai Kohei 		audit_log_format(ab, "%s%s",
52144c2d9bdSKaiGai Kohei 				 need_comma ? "," : "",
52244c2d9bdSKaiGai Kohei 				 permission_names[index]
52344c2d9bdSKaiGai Kohei 				 ? permission_names[index] : "????");
52444c2d9bdSKaiGai Kohei 		need_comma = true;
52544c2d9bdSKaiGai Kohei 	}
52644c2d9bdSKaiGai Kohei 	audit_log_end(ab);
52744c2d9bdSKaiGai Kohei out:
52844c2d9bdSKaiGai Kohei 	/* release scontext/tcontext */
52944c2d9bdSKaiGai Kohei 	kfree(tcontext_name);
53044c2d9bdSKaiGai Kohei 	kfree(scontext_name);
53144c2d9bdSKaiGai Kohei 
53244c2d9bdSKaiGai Kohei 	return;
53344c2d9bdSKaiGai Kohei }
53444c2d9bdSKaiGai Kohei 
53544c2d9bdSKaiGai Kohei /*
536d9250deaSKaiGai Kohei  * security_boundary_permission - drops violated permissions
537d9250deaSKaiGai Kohei  * on boundary constraint.
538d9250deaSKaiGai Kohei  */
539d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext,
540d9250deaSKaiGai Kohei 				     struct context *tcontext,
541d9250deaSKaiGai Kohei 				     u16 tclass,
542d9250deaSKaiGai Kohei 				     struct av_decision *avd)
543d9250deaSKaiGai Kohei {
5442ae3ba39SKaiGai Kohei 	struct context lo_scontext;
5452ae3ba39SKaiGai Kohei 	struct context lo_tcontext;
5462ae3ba39SKaiGai Kohei 	struct av_decision lo_avd;
54723bdecb0SEric Paris 	struct type_datum *source;
54823bdecb0SEric Paris 	struct type_datum *target;
5492ae3ba39SKaiGai Kohei 	u32 masked = 0;
550d9250deaSKaiGai Kohei 
55123bdecb0SEric Paris 	source = flex_array_get_ptr(policydb.type_val_to_struct_array,
55223bdecb0SEric Paris 				    scontext->type - 1);
55323bdecb0SEric Paris 	BUG_ON(!source);
55423bdecb0SEric Paris 
55523bdecb0SEric Paris 	target = flex_array_get_ptr(policydb.type_val_to_struct_array,
55623bdecb0SEric Paris 				    tcontext->type - 1);
55723bdecb0SEric Paris 	BUG_ON(!target);
55823bdecb0SEric Paris 
559d9250deaSKaiGai Kohei 	if (source->bounds) {
560d9250deaSKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
561d9250deaSKaiGai Kohei 
562d9250deaSKaiGai Kohei 		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
563d9250deaSKaiGai Kohei 		lo_scontext.type = source->bounds;
564d9250deaSKaiGai Kohei 
565d9250deaSKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
566d9250deaSKaiGai Kohei 					  tcontext,
567d9250deaSKaiGai Kohei 					  tclass,
568d9250deaSKaiGai Kohei 					  &lo_avd);
569d9250deaSKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
570d9250deaSKaiGai Kohei 			return;		/* no masked permission */
571d9250deaSKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5722ae3ba39SKaiGai Kohei 	}
573d9250deaSKaiGai Kohei 
5742ae3ba39SKaiGai Kohei 	if (target->bounds) {
5752ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5762ae3ba39SKaiGai Kohei 
5772ae3ba39SKaiGai Kohei 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5782ae3ba39SKaiGai Kohei 		lo_tcontext.type = target->bounds;
5792ae3ba39SKaiGai Kohei 
5802ae3ba39SKaiGai Kohei 		context_struct_compute_av(scontext,
5812ae3ba39SKaiGai Kohei 					  &lo_tcontext,
5822ae3ba39SKaiGai Kohei 					  tclass,
5832ae3ba39SKaiGai Kohei 					  &lo_avd);
5842ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
5852ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
5862ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5872ae3ba39SKaiGai Kohei 	}
5882ae3ba39SKaiGai Kohei 
5892ae3ba39SKaiGai Kohei 	if (source->bounds && target->bounds) {
5902ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5912ae3ba39SKaiGai Kohei 		/*
5922ae3ba39SKaiGai Kohei 		 * lo_scontext and lo_tcontext are already
5932ae3ba39SKaiGai Kohei 		 * set up.
5942ae3ba39SKaiGai Kohei 		 */
5952ae3ba39SKaiGai Kohei 
5962ae3ba39SKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
5972ae3ba39SKaiGai Kohei 					  &lo_tcontext,
5982ae3ba39SKaiGai Kohei 					  tclass,
5992ae3ba39SKaiGai Kohei 					  &lo_avd);
6002ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
6012ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
6022ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
6032ae3ba39SKaiGai Kohei 	}
6042ae3ba39SKaiGai Kohei 
6052ae3ba39SKaiGai Kohei 	if (masked) {
606d9250deaSKaiGai Kohei 		/* mask violated permissions */
607d9250deaSKaiGai Kohei 		avd->allowed &= ~masked;
608d9250deaSKaiGai Kohei 
60944c2d9bdSKaiGai Kohei 		/* audit masked permissions */
61044c2d9bdSKaiGai Kohei 		security_dump_masked_av(scontext, tcontext,
61144c2d9bdSKaiGai Kohei 					tclass, masked, "bounds");
612d9250deaSKaiGai Kohei 	}
613d9250deaSKaiGai Kohei }
614d9250deaSKaiGai Kohei 
615d9250deaSKaiGai Kohei /*
6161da177e4SLinus Torvalds  * Compute access vectors based on a context structure pair for
6171da177e4SLinus Torvalds  * the permissions in a particular class.
6181da177e4SLinus Torvalds  */
61919439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext,
6201da177e4SLinus Torvalds 				      struct context *tcontext,
6211da177e4SLinus Torvalds 				      u16 tclass,
6221da177e4SLinus Torvalds 				      struct av_decision *avd)
6231da177e4SLinus Torvalds {
6241da177e4SLinus Torvalds 	struct constraint_node *constraint;
6251da177e4SLinus Torvalds 	struct role_allow *ra;
6261da177e4SLinus Torvalds 	struct avtab_key avkey;
627782ebb99SStephen Smalley 	struct avtab_node *node;
6281da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
629782ebb99SStephen Smalley 	struct ebitmap *sattr, *tattr;
630782ebb99SStephen Smalley 	struct ebitmap_node *snode, *tnode;
631782ebb99SStephen Smalley 	unsigned int i, j;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	avd->allowed = 0;
6341da177e4SLinus Torvalds 	avd->auditallow = 0;
6351da177e4SLinus Torvalds 	avd->auditdeny = 0xffffffff;
6361da177e4SLinus Torvalds 
637c6d3aaa4SStephen Smalley 	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
638c6d3aaa4SStephen Smalley 		if (printk_ratelimit())
639c6d3aaa4SStephen Smalley 			printk(KERN_WARNING "SELinux:  Invalid class %hu\n", tclass);
64019439d05SStephen Smalley 		return;
641c6d3aaa4SStephen Smalley 	}
6423f12070eSEric Paris 
6433f12070eSEric Paris 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
6443f12070eSEric Paris 
6453f12070eSEric Paris 	/*
6461da177e4SLinus Torvalds 	 * If a specific type enforcement rule was defined for
6471da177e4SLinus Torvalds 	 * this permission check, then use it.
6481da177e4SLinus Torvalds 	 */
6491da177e4SLinus Torvalds 	avkey.target_class = tclass;
650782ebb99SStephen Smalley 	avkey.specified = AVTAB_AV;
6516371dcd3SEric Paris 	sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
6526371dcd3SEric Paris 	BUG_ON(!sattr);
6536371dcd3SEric Paris 	tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
6546371dcd3SEric Paris 	BUG_ON(!tattr);
6559fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(sattr, snode, i) {
6569fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
657782ebb99SStephen Smalley 			avkey.source_type = i + 1;
658782ebb99SStephen Smalley 			avkey.target_type = j + 1;
659782ebb99SStephen Smalley 			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
660dbc74c65SVesa-Matti Kari 			     node;
661782ebb99SStephen Smalley 			     node = avtab_search_node_next(node, avkey.specified)) {
662782ebb99SStephen Smalley 				if (node->key.specified == AVTAB_ALLOWED)
663782ebb99SStephen Smalley 					avd->allowed |= node->datum.data;
664782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITALLOW)
665782ebb99SStephen Smalley 					avd->auditallow |= node->datum.data;
666782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITDENY)
667782ebb99SStephen Smalley 					avd->auditdeny &= node->datum.data;
6681da177e4SLinus Torvalds 			}
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 			/* Check conditional av table for additional permissions */
6711da177e4SLinus Torvalds 			cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
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)) &&
6831da177e4SLinus Torvalds 		    !constraint_expr_eval(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 	 */
695c6d3aaa4SStephen Smalley 	if (tclass == policydb.process_class &&
696c6d3aaa4SStephen Smalley 	    (avd->allowed & policydb.process_trans_perms) &&
6971da177e4SLinus Torvalds 	    scontext->role != tcontext->role) {
6981da177e4SLinus Torvalds 		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)
704c6d3aaa4SStephen 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 	 */
712d9250deaSKaiGai Kohei 	type_attribute_bounds_av(scontext, tcontext,
71319439d05SStephen Smalley 				 tclass, avd);
71422df4adbSStephen Smalley }
71522df4adbSStephen Smalley 
7161da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext,
7171da177e4SLinus Torvalds 					   struct context *ncontext,
7181da177e4SLinus Torvalds 					   struct context *tcontext,
7191da177e4SLinus Torvalds 					   u16 tclass)
7201da177e4SLinus Torvalds {
7211da177e4SLinus Torvalds 	char *o = NULL, *n = NULL, *t = NULL;
7221da177e4SLinus Torvalds 	u32 olen, nlen, tlen;
7231da177e4SLinus Torvalds 
7244b02b524SEric Paris 	if (context_struct_to_string(ocontext, &o, &olen))
7251da177e4SLinus Torvalds 		goto out;
7264b02b524SEric Paris 	if (context_struct_to_string(ncontext, &n, &nlen))
7271da177e4SLinus Torvalds 		goto out;
7284b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
7291da177e4SLinus Torvalds 		goto out;
7309ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
7311da177e4SLinus Torvalds 		  "security_validate_transition:  denied for"
7321da177e4SLinus Torvalds 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
733ac76c05bSEric Paris 		  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
7341da177e4SLinus Torvalds out:
7351da177e4SLinus Torvalds 	kfree(o);
7361da177e4SLinus Torvalds 	kfree(n);
7371da177e4SLinus Torvalds 	kfree(t);
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	if (!selinux_enforcing)
7401da177e4SLinus Torvalds 		return 0;
7411da177e4SLinus Torvalds 	return -EPERM;
7421da177e4SLinus Torvalds }
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
745c6d3aaa4SStephen Smalley 				 u16 orig_tclass)
7461da177e4SLinus Torvalds {
7471da177e4SLinus Torvalds 	struct context *ocontext;
7481da177e4SLinus Torvalds 	struct context *ncontext;
7491da177e4SLinus Torvalds 	struct context *tcontext;
7501da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
7511da177e4SLinus Torvalds 	struct constraint_node *constraint;
752c6d3aaa4SStephen Smalley 	u16 tclass;
7531da177e4SLinus Torvalds 	int rc = 0;
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	if (!ss_initialized)
7561da177e4SLinus Torvalds 		return 0;
7571da177e4SLinus Torvalds 
7580804d113SJames Morris 	read_lock(&policy_rwlock);
7591da177e4SLinus Torvalds 
760c6d3aaa4SStephen Smalley 	tclass = unmap_class(orig_tclass);
761c6d3aaa4SStephen Smalley 
7621da177e4SLinus Torvalds 	if (!tclass || tclass > policydb.p_classes.nprim) {
763744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n",
764744ba35eSEric Paris 			__func__, tclass);
7651da177e4SLinus Torvalds 		rc = -EINVAL;
7661da177e4SLinus Torvalds 		goto out;
7671da177e4SLinus Torvalds 	}
7681da177e4SLinus Torvalds 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 	ocontext = sidtab_search(&sidtab, oldsid);
7711da177e4SLinus Torvalds 	if (!ocontext) {
772744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
773744ba35eSEric Paris 			__func__, oldsid);
7741da177e4SLinus Torvalds 		rc = -EINVAL;
7751da177e4SLinus Torvalds 		goto out;
7761da177e4SLinus Torvalds 	}
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	ncontext = sidtab_search(&sidtab, newsid);
7791da177e4SLinus Torvalds 	if (!ncontext) {
780744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
781744ba35eSEric Paris 			__func__, newsid);
7821da177e4SLinus Torvalds 		rc = -EINVAL;
7831da177e4SLinus Torvalds 		goto out;
7841da177e4SLinus Torvalds 	}
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tasksid);
7871da177e4SLinus Torvalds 	if (!tcontext) {
788744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
789744ba35eSEric Paris 			__func__, tasksid);
7901da177e4SLinus Torvalds 		rc = -EINVAL;
7911da177e4SLinus Torvalds 		goto out;
7921da177e4SLinus Torvalds 	}
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 	constraint = tclass_datum->validatetrans;
7951da177e4SLinus Torvalds 	while (constraint) {
7961da177e4SLinus Torvalds 		if (!constraint_expr_eval(ocontext, ncontext, tcontext,
7971da177e4SLinus Torvalds 					  constraint->expr)) {
7981da177e4SLinus Torvalds 			rc = security_validtrans_handle_fail(ocontext, ncontext,
7991da177e4SLinus Torvalds 							     tcontext, tclass);
8001da177e4SLinus Torvalds 			goto out;
8011da177e4SLinus Torvalds 		}
8021da177e4SLinus Torvalds 		constraint = constraint->next;
8031da177e4SLinus Torvalds 	}
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds out:
8060804d113SJames Morris 	read_unlock(&policy_rwlock);
8071da177e4SLinus Torvalds 	return rc;
8081da177e4SLinus Torvalds }
8091da177e4SLinus Torvalds 
810d9250deaSKaiGai Kohei /*
811d9250deaSKaiGai Kohei  * security_bounded_transition - check whether the given
812d9250deaSKaiGai Kohei  * transition is directed to bounded, or not.
813d9250deaSKaiGai Kohei  * It returns 0, if @newsid is bounded by @oldsid.
814d9250deaSKaiGai Kohei  * Otherwise, it returns error code.
815d9250deaSKaiGai Kohei  *
816d9250deaSKaiGai Kohei  * @oldsid : current security identifier
817d9250deaSKaiGai Kohei  * @newsid : destinated security identifier
818d9250deaSKaiGai Kohei  */
819d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid)
820d9250deaSKaiGai Kohei {
821d9250deaSKaiGai Kohei 	struct context *old_context, *new_context;
822d9250deaSKaiGai Kohei 	struct type_datum *type;
823d9250deaSKaiGai Kohei 	int index;
8244b02b524SEric Paris 	int rc;
825d9250deaSKaiGai Kohei 
826d9250deaSKaiGai Kohei 	read_lock(&policy_rwlock);
827d9250deaSKaiGai Kohei 
8284b02b524SEric Paris 	rc = -EINVAL;
829d9250deaSKaiGai Kohei 	old_context = sidtab_search(&sidtab, old_sid);
830d9250deaSKaiGai Kohei 	if (!old_context) {
831d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
832d9250deaSKaiGai Kohei 		       __func__, old_sid);
833d9250deaSKaiGai Kohei 		goto out;
834d9250deaSKaiGai Kohei 	}
835d9250deaSKaiGai Kohei 
8364b02b524SEric Paris 	rc = -EINVAL;
837d9250deaSKaiGai Kohei 	new_context = sidtab_search(&sidtab, new_sid);
838d9250deaSKaiGai Kohei 	if (!new_context) {
839d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
840d9250deaSKaiGai Kohei 		       __func__, new_sid);
841d9250deaSKaiGai Kohei 		goto out;
842d9250deaSKaiGai Kohei 	}
843d9250deaSKaiGai Kohei 
844d9250deaSKaiGai Kohei 	rc = 0;
8454b02b524SEric Paris 	/* type/domain unchanged */
8464b02b524SEric Paris 	if (old_context->type == new_context->type)
847d9250deaSKaiGai Kohei 		goto out;
848d9250deaSKaiGai Kohei 
849d9250deaSKaiGai Kohei 	index = new_context->type;
850d9250deaSKaiGai Kohei 	while (true) {
85123bdecb0SEric Paris 		type = flex_array_get_ptr(policydb.type_val_to_struct_array,
85223bdecb0SEric Paris 					  index - 1);
853d9250deaSKaiGai Kohei 		BUG_ON(!type);
854d9250deaSKaiGai Kohei 
855d9250deaSKaiGai Kohei 		/* not bounded anymore */
856d9250deaSKaiGai Kohei 		rc = -EPERM;
8574b02b524SEric Paris 		if (!type->bounds)
858d9250deaSKaiGai Kohei 			break;
859d9250deaSKaiGai Kohei 
860d9250deaSKaiGai Kohei 		/* @newsid is bounded by @oldsid */
861d9250deaSKaiGai Kohei 		rc = 0;
8624b02b524SEric Paris 		if (type->bounds == old_context->type)
863d9250deaSKaiGai Kohei 			break;
8644b02b524SEric Paris 
865d9250deaSKaiGai Kohei 		index = type->bounds;
866d9250deaSKaiGai Kohei 	}
86744c2d9bdSKaiGai Kohei 
86844c2d9bdSKaiGai Kohei 	if (rc) {
86944c2d9bdSKaiGai Kohei 		char *old_name = NULL;
87044c2d9bdSKaiGai Kohei 		char *new_name = NULL;
8712da5d31bSJames Morris 		u32 length;
87244c2d9bdSKaiGai Kohei 
87344c2d9bdSKaiGai Kohei 		if (!context_struct_to_string(old_context,
87444c2d9bdSKaiGai Kohei 					      &old_name, &length) &&
87544c2d9bdSKaiGai Kohei 		    !context_struct_to_string(new_context,
87644c2d9bdSKaiGai Kohei 					      &new_name, &length)) {
87744c2d9bdSKaiGai Kohei 			audit_log(current->audit_context,
87844c2d9bdSKaiGai Kohei 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
87944c2d9bdSKaiGai Kohei 				  "op=security_bounded_transition "
88044c2d9bdSKaiGai Kohei 				  "result=denied "
88144c2d9bdSKaiGai Kohei 				  "oldcontext=%s newcontext=%s",
88244c2d9bdSKaiGai Kohei 				  old_name, new_name);
88344c2d9bdSKaiGai Kohei 		}
88444c2d9bdSKaiGai Kohei 		kfree(new_name);
88544c2d9bdSKaiGai Kohei 		kfree(old_name);
88644c2d9bdSKaiGai Kohei 	}
887d9250deaSKaiGai Kohei out:
888d9250deaSKaiGai Kohei 	read_unlock(&policy_rwlock);
889d9250deaSKaiGai Kohei 
890d9250deaSKaiGai Kohei 	return rc;
891d9250deaSKaiGai Kohei }
892d9250deaSKaiGai Kohei 
89319439d05SStephen Smalley static void avd_init(struct av_decision *avd)
894c6d3aaa4SStephen Smalley {
89519439d05SStephen Smalley 	avd->allowed = 0;
89619439d05SStephen Smalley 	avd->auditallow = 0;
89719439d05SStephen Smalley 	avd->auditdeny = 0xffffffff;
89819439d05SStephen Smalley 	avd->seqno = latest_granting;
89919439d05SStephen Smalley 	avd->flags = 0;
900c6d3aaa4SStephen Smalley }
901c6d3aaa4SStephen Smalley 
902c6d3aaa4SStephen Smalley 
9031da177e4SLinus Torvalds /**
9041da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
9051da177e4SLinus Torvalds  * @ssid: source security identifier
9061da177e4SLinus Torvalds  * @tsid: target security identifier
9071da177e4SLinus Torvalds  * @tclass: target security class
9081da177e4SLinus Torvalds  * @avd: access vector decisions
9091da177e4SLinus Torvalds  *
9101da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
9111da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
9121da177e4SLinus Torvalds  */
91319439d05SStephen Smalley void security_compute_av(u32 ssid,
9141da177e4SLinus Torvalds 			 u32 tsid,
915c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
916c6d3aaa4SStephen Smalley 			 struct av_decision *avd)
917c6d3aaa4SStephen Smalley {
918c6d3aaa4SStephen Smalley 	u16 tclass;
91919439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
920c6d3aaa4SStephen Smalley 
921b7f3008aSStephen Smalley 	read_lock(&policy_rwlock);
92219439d05SStephen Smalley 	avd_init(avd);
923c6d3aaa4SStephen Smalley 	if (!ss_initialized)
924c6d3aaa4SStephen Smalley 		goto allow;
925c6d3aaa4SStephen Smalley 
92619439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
92719439d05SStephen Smalley 	if (!scontext) {
92819439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
92919439d05SStephen Smalley 		       __func__, ssid);
93019439d05SStephen Smalley 		goto out;
93119439d05SStephen Smalley 	}
93219439d05SStephen Smalley 
93319439d05SStephen Smalley 	/* permissive domain? */
93419439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
93519439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
93619439d05SStephen Smalley 
93719439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
93819439d05SStephen Smalley 	if (!tcontext) {
93919439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
94019439d05SStephen Smalley 		       __func__, tsid);
94119439d05SStephen Smalley 		goto out;
94219439d05SStephen Smalley 	}
94319439d05SStephen Smalley 
944c6d3aaa4SStephen Smalley 	tclass = unmap_class(orig_tclass);
945c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
946c6d3aaa4SStephen Smalley 		if (policydb.allow_unknown)
947c6d3aaa4SStephen Smalley 			goto allow;
948b7f3008aSStephen Smalley 		goto out;
949c6d3aaa4SStephen Smalley 	}
95019439d05SStephen Smalley 	context_struct_compute_av(scontext, tcontext, tclass, avd);
951c6d3aaa4SStephen Smalley 	map_decision(orig_tclass, avd, policydb.allow_unknown);
952b7f3008aSStephen Smalley out:
953c6d3aaa4SStephen Smalley 	read_unlock(&policy_rwlock);
95419439d05SStephen Smalley 	return;
955c6d3aaa4SStephen Smalley allow:
956c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
957b7f3008aSStephen Smalley 	goto out;
958c6d3aaa4SStephen Smalley }
959c6d3aaa4SStephen Smalley 
96019439d05SStephen Smalley void security_compute_av_user(u32 ssid,
961c6d3aaa4SStephen Smalley 			      u32 tsid,
9621da177e4SLinus Torvalds 			      u16 tclass,
9631da177e4SLinus Torvalds 			      struct av_decision *avd)
9641da177e4SLinus Torvalds {
96519439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
9661da177e4SLinus Torvalds 
9670804d113SJames Morris 	read_lock(&policy_rwlock);
96819439d05SStephen Smalley 	avd_init(avd);
96919439d05SStephen Smalley 	if (!ss_initialized)
97019439d05SStephen Smalley 		goto allow;
97119439d05SStephen Smalley 
97219439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
97319439d05SStephen Smalley 	if (!scontext) {
97419439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
97519439d05SStephen Smalley 		       __func__, ssid);
97619439d05SStephen Smalley 		goto out;
97719439d05SStephen Smalley 	}
97819439d05SStephen Smalley 
97919439d05SStephen Smalley 	/* permissive domain? */
98019439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
98119439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
98219439d05SStephen Smalley 
98319439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
98419439d05SStephen Smalley 	if (!tcontext) {
98519439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
98619439d05SStephen Smalley 		       __func__, tsid);
98719439d05SStephen Smalley 		goto out;
98819439d05SStephen Smalley 	}
98919439d05SStephen Smalley 
99019439d05SStephen Smalley 	if (unlikely(!tclass)) {
99119439d05SStephen Smalley 		if (policydb.allow_unknown)
99219439d05SStephen Smalley 			goto allow;
99319439d05SStephen Smalley 		goto out;
99419439d05SStephen Smalley 	}
99519439d05SStephen Smalley 
99619439d05SStephen Smalley 	context_struct_compute_av(scontext, tcontext, tclass, avd);
99719439d05SStephen Smalley  out:
9980804d113SJames Morris 	read_unlock(&policy_rwlock);
99919439d05SStephen Smalley 	return;
100019439d05SStephen Smalley allow:
100119439d05SStephen Smalley 	avd->allowed = 0xffffffff;
100219439d05SStephen Smalley 	goto out;
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds 
10051da177e4SLinus Torvalds /*
10061da177e4SLinus Torvalds  * Write the security context string representation of
10071da177e4SLinus Torvalds  * the context structure `context' into a dynamically
10081da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
10091da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
10101da177e4SLinus Torvalds  * the length of the string.
10111da177e4SLinus Torvalds  */
10121da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
10131da177e4SLinus Torvalds {
10141da177e4SLinus Torvalds 	char *scontextp;
10151da177e4SLinus Torvalds 
1016d5630b9dSEric Paris 	if (scontext)
10171da177e4SLinus Torvalds 		*scontext = NULL;
10181da177e4SLinus Torvalds 	*scontext_len = 0;
10191da177e4SLinus Torvalds 
102012b29f34SStephen Smalley 	if (context->len) {
102112b29f34SStephen Smalley 		*scontext_len = context->len;
1022bb7081abSEric Paris 		if (scontext) {
102312b29f34SStephen Smalley 			*scontext = kstrdup(context->str, GFP_ATOMIC);
102412b29f34SStephen Smalley 			if (!(*scontext))
102512b29f34SStephen Smalley 				return -ENOMEM;
1026bb7081abSEric Paris 		}
102712b29f34SStephen Smalley 		return 0;
102812b29f34SStephen Smalley 	}
102912b29f34SStephen Smalley 
10301da177e4SLinus Torvalds 	/* Compute the size of the context. */
1031ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
1032ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
1033ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
10341da177e4SLinus Torvalds 	*scontext_len += mls_compute_context_len(context);
10351da177e4SLinus Torvalds 
1036d5630b9dSEric Paris 	if (!scontext)
1037d5630b9dSEric Paris 		return 0;
1038d5630b9dSEric Paris 
10391da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
10401da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
10415d55a345SEric Paris 	if (!scontextp)
10421da177e4SLinus Torvalds 		return -ENOMEM;
10431da177e4SLinus Torvalds 	*scontext = scontextp;
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 	/*
10461da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
10471da177e4SLinus Torvalds 	 */
10481da177e4SLinus Torvalds 	sprintf(scontextp, "%s:%s:%s",
1049ac76c05bSEric Paris 		sym_name(&policydb, SYM_USERS, context->user - 1),
1050ac76c05bSEric Paris 		sym_name(&policydb, SYM_ROLES, context->role - 1),
1051ac76c05bSEric Paris 		sym_name(&policydb, SYM_TYPES, context->type - 1));
1052ac76c05bSEric Paris 	scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
1053ac76c05bSEric Paris 		     1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
1054ac76c05bSEric Paris 		     1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	mls_sid_to_context(context, &scontextp);
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	*scontextp = 0;
10591da177e4SLinus Torvalds 
10601da177e4SLinus Torvalds 	return 0;
10611da177e4SLinus Torvalds }
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds #include "initial_sid_to_string.h"
10641da177e4SLinus Torvalds 
1065f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1066f0ee2e46SJames Carter {
1067f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1068f0ee2e46SJames Carter 		return NULL;
1069f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1070f0ee2e46SJames Carter }
1071f0ee2e46SJames Carter 
107212b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
107312b29f34SStephen Smalley 					u32 *scontext_len, int force)
10741da177e4SLinus Torvalds {
10751da177e4SLinus Torvalds 	struct context *context;
10761da177e4SLinus Torvalds 	int rc = 0;
10771da177e4SLinus Torvalds 
1078d5630b9dSEric Paris 	if (scontext)
10794f4acf3aSStephen Smalley 		*scontext = NULL;
10804f4acf3aSStephen Smalley 	*scontext_len  = 0;
10814f4acf3aSStephen Smalley 
10821da177e4SLinus Torvalds 	if (!ss_initialized) {
10831da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
10841da177e4SLinus Torvalds 			char *scontextp;
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
1087d5630b9dSEric Paris 			if (!scontext)
1088d5630b9dSEric Paris 				goto out;
10891da177e4SLinus Torvalds 			scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
10900cccca06SSerge E. Hallyn 			if (!scontextp) {
10910cccca06SSerge E. Hallyn 				rc = -ENOMEM;
10920cccca06SSerge E. Hallyn 				goto out;
10930cccca06SSerge E. Hallyn 			}
10941da177e4SLinus Torvalds 			strcpy(scontextp, initial_sid_to_string[sid]);
10951da177e4SLinus Torvalds 			*scontext = scontextp;
10961da177e4SLinus Torvalds 			goto out;
10971da177e4SLinus Torvalds 		}
1098744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  called before initial "
1099744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
11001da177e4SLinus Torvalds 		rc = -EINVAL;
11011da177e4SLinus Torvalds 		goto out;
11021da177e4SLinus Torvalds 	}
11030804d113SJames Morris 	read_lock(&policy_rwlock);
110412b29f34SStephen Smalley 	if (force)
110512b29f34SStephen Smalley 		context = sidtab_search_force(&sidtab, sid);
110612b29f34SStephen Smalley 	else
11071da177e4SLinus Torvalds 		context = sidtab_search(&sidtab, sid);
11081da177e4SLinus Torvalds 	if (!context) {
1109744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1110744ba35eSEric Paris 			__func__, sid);
11111da177e4SLinus Torvalds 		rc = -EINVAL;
11121da177e4SLinus Torvalds 		goto out_unlock;
11131da177e4SLinus Torvalds 	}
11141da177e4SLinus Torvalds 	rc = context_struct_to_string(context, scontext, scontext_len);
11151da177e4SLinus Torvalds out_unlock:
11160804d113SJames Morris 	read_unlock(&policy_rwlock);
11171da177e4SLinus Torvalds out:
11181da177e4SLinus Torvalds 	return rc;
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds 
112212b29f34SStephen Smalley /**
112312b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
112412b29f34SStephen Smalley  * @sid: security identifier, SID
112512b29f34SStephen Smalley  * @scontext: security context
112612b29f34SStephen Smalley  * @scontext_len: length in bytes
112712b29f34SStephen Smalley  *
112812b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
112912b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
113012b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
113112b29f34SStephen Smalley  */
113212b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
11331da177e4SLinus Torvalds {
113412b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 0);
113512b29f34SStephen Smalley }
113612b29f34SStephen Smalley 
113712b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
113812b29f34SStephen Smalley {
113912b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 1);
114012b29f34SStephen Smalley }
114112b29f34SStephen Smalley 
11429a59daa0SStephen Smalley /*
11439a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
11449a59daa0SStephen Smalley  */
114512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
114612b29f34SStephen Smalley 				    struct sidtab *sidtabp,
11479a59daa0SStephen Smalley 				    char *scontext,
114812b29f34SStephen Smalley 				    u32 scontext_len,
114912b29f34SStephen Smalley 				    struct context *ctx,
11509a59daa0SStephen Smalley 				    u32 def_sid)
115112b29f34SStephen Smalley {
11521da177e4SLinus Torvalds 	struct role_datum *role;
11531da177e4SLinus Torvalds 	struct type_datum *typdatum;
11541da177e4SLinus Torvalds 	struct user_datum *usrdatum;
11551da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
11561da177e4SLinus Torvalds 	int rc = 0;
11571da177e4SLinus Torvalds 
115812b29f34SStephen Smalley 	context_init(ctx);
115912b29f34SStephen Smalley 
116012b29f34SStephen Smalley 	/* Parse the security context. */
116112b29f34SStephen Smalley 
116212b29f34SStephen Smalley 	rc = -EINVAL;
11639a59daa0SStephen Smalley 	scontextp = (char *) scontext;
116412b29f34SStephen Smalley 
116512b29f34SStephen Smalley 	/* Extract the user. */
116612b29f34SStephen Smalley 	p = scontextp;
116712b29f34SStephen Smalley 	while (*p && *p != ':')
116812b29f34SStephen Smalley 		p++;
116912b29f34SStephen Smalley 
117012b29f34SStephen Smalley 	if (*p == 0)
117112b29f34SStephen Smalley 		goto out;
117212b29f34SStephen Smalley 
117312b29f34SStephen Smalley 	*p++ = 0;
117412b29f34SStephen Smalley 
117512b29f34SStephen Smalley 	usrdatum = hashtab_search(pol->p_users.table, scontextp);
117612b29f34SStephen Smalley 	if (!usrdatum)
117712b29f34SStephen Smalley 		goto out;
117812b29f34SStephen Smalley 
117912b29f34SStephen Smalley 	ctx->user = usrdatum->value;
118012b29f34SStephen Smalley 
118112b29f34SStephen Smalley 	/* Extract role. */
118212b29f34SStephen Smalley 	scontextp = p;
118312b29f34SStephen Smalley 	while (*p && *p != ':')
118412b29f34SStephen Smalley 		p++;
118512b29f34SStephen Smalley 
118612b29f34SStephen Smalley 	if (*p == 0)
118712b29f34SStephen Smalley 		goto out;
118812b29f34SStephen Smalley 
118912b29f34SStephen Smalley 	*p++ = 0;
119012b29f34SStephen Smalley 
119112b29f34SStephen Smalley 	role = hashtab_search(pol->p_roles.table, scontextp);
119212b29f34SStephen Smalley 	if (!role)
119312b29f34SStephen Smalley 		goto out;
119412b29f34SStephen Smalley 	ctx->role = role->value;
119512b29f34SStephen Smalley 
119612b29f34SStephen Smalley 	/* Extract type. */
119712b29f34SStephen Smalley 	scontextp = p;
119812b29f34SStephen Smalley 	while (*p && *p != ':')
119912b29f34SStephen Smalley 		p++;
120012b29f34SStephen Smalley 	oldc = *p;
120112b29f34SStephen Smalley 	*p++ = 0;
120212b29f34SStephen Smalley 
120312b29f34SStephen Smalley 	typdatum = hashtab_search(pol->p_types.table, scontextp);
1204d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
120512b29f34SStephen Smalley 		goto out;
120612b29f34SStephen Smalley 
120712b29f34SStephen Smalley 	ctx->type = typdatum->value;
120812b29f34SStephen Smalley 
120912b29f34SStephen Smalley 	rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
121012b29f34SStephen Smalley 	if (rc)
121112b29f34SStephen Smalley 		goto out;
121212b29f34SStephen Smalley 
121312b29f34SStephen Smalley 	rc = -EINVAL;
12144b02b524SEric Paris 	if ((p - scontext) < scontext_len)
121512b29f34SStephen Smalley 		goto out;
121612b29f34SStephen Smalley 
121712b29f34SStephen Smalley 	/* Check the validity of the new context. */
12184b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
121912b29f34SStephen Smalley 		goto out;
122012b29f34SStephen Smalley 	rc = 0;
122112b29f34SStephen Smalley out:
12228e531af9SEric Paris 	if (rc)
12238e531af9SEric Paris 		context_destroy(ctx);
122412b29f34SStephen Smalley 	return rc;
122512b29f34SStephen Smalley }
122612b29f34SStephen Smalley 
122712b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
122812b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
122912b29f34SStephen Smalley 					int force)
123012b29f34SStephen Smalley {
12319a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
123212b29f34SStephen Smalley 	struct context context;
123312b29f34SStephen Smalley 	int rc = 0;
123412b29f34SStephen Smalley 
12352172fa70SStephen Smalley 	/* An empty security context is never valid. */
12362172fa70SStephen Smalley 	if (!scontext_len)
12372172fa70SStephen Smalley 		return -EINVAL;
12382172fa70SStephen Smalley 
12391da177e4SLinus Torvalds 	if (!ss_initialized) {
12401da177e4SLinus Torvalds 		int i;
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
12431da177e4SLinus Torvalds 			if (!strcmp(initial_sid_to_string[i], scontext)) {
12441da177e4SLinus Torvalds 				*sid = i;
12459a59daa0SStephen Smalley 				return 0;
12461da177e4SLinus Torvalds 			}
12471da177e4SLinus Torvalds 		}
12481da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
12499a59daa0SStephen Smalley 		return 0;
12501da177e4SLinus Torvalds 	}
12511da177e4SLinus Torvalds 	*sid = SECSID_NULL;
12521da177e4SLinus Torvalds 
12539a59daa0SStephen Smalley 	/* Copy the string so that we can modify the copy as we parse it. */
12549a59daa0SStephen Smalley 	scontext2 = kmalloc(scontext_len + 1, gfp_flags);
12559a59daa0SStephen Smalley 	if (!scontext2)
12569a59daa0SStephen Smalley 		return -ENOMEM;
12579a59daa0SStephen Smalley 	memcpy(scontext2, scontext, scontext_len);
12589a59daa0SStephen Smalley 	scontext2[scontext_len] = 0;
12599a59daa0SStephen Smalley 
12609a59daa0SStephen Smalley 	if (force) {
12619a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
12624b02b524SEric Paris 		rc = -ENOMEM;
12639a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
12644b02b524SEric Paris 		if (!str)
12654b02b524SEric Paris 			goto out;
12669a59daa0SStephen Smalley 	}
12679a59daa0SStephen Smalley 
12680804d113SJames Morris 	read_lock(&policy_rwlock);
12694b02b524SEric Paris 	rc = string_to_context_struct(&policydb, &sidtab, scontext2,
12704b02b524SEric Paris 				      scontext_len, &context, def_sid);
127112b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
12729a59daa0SStephen Smalley 		context.str = str;
127312b29f34SStephen Smalley 		context.len = scontext_len;
12749a59daa0SStephen Smalley 		str = NULL;
127512b29f34SStephen Smalley 	} else if (rc)
12764b02b524SEric Paris 		goto out_unlock;
12771da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &context, sid);
12781da177e4SLinus Torvalds 	context_destroy(&context);
12794b02b524SEric Paris out_unlock:
12800804d113SJames Morris 	read_unlock(&policy_rwlock);
12814b02b524SEric Paris out:
12829a59daa0SStephen Smalley 	kfree(scontext2);
12839a59daa0SStephen Smalley 	kfree(str);
12841da177e4SLinus Torvalds 	return rc;
12851da177e4SLinus Torvalds }
12861da177e4SLinus Torvalds 
1287f5c1d5b2SJames Morris /**
1288f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1289f5c1d5b2SJames Morris  * @scontext: security context
1290f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1291f5c1d5b2SJames Morris  * @sid: security identifier, SID
129252a4c640SNikolay Aleksandrov  * @gfp: context for the allocation
1293f5c1d5b2SJames Morris  *
1294f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1295f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1296f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1297f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1298f5c1d5b2SJames Morris  */
129952a4c640SNikolay Aleksandrov int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
130052a4c640SNikolay Aleksandrov 			    gfp_t gfp)
1301f5c1d5b2SJames Morris {
1302f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
130352a4c640SNikolay Aleksandrov 					    sid, SECSID_NULL, gfp, 0);
1304f5c1d5b2SJames Morris }
1305f5c1d5b2SJames Morris 
1306f5c1d5b2SJames Morris /**
1307f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1308f5c1d5b2SJames Morris  * falling back to specified default if needed.
1309f5c1d5b2SJames Morris  *
1310f5c1d5b2SJames Morris  * @scontext: security context
1311f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1312f5c1d5b2SJames Morris  * @sid: security identifier, SID
1313d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1314f5c1d5b2SJames Morris  *
1315f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1316f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1317f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1318f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1319f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
132012b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1321f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1322f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1323f5c1d5b2SJames Morris  */
13247bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len,
13257bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1326f5c1d5b2SJames Morris {
1327f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
132812b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
132912b29f34SStephen Smalley }
133012b29f34SStephen Smalley 
133112b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
133212b29f34SStephen Smalley 				  u32 *sid)
133312b29f34SStephen Smalley {
133412b29f34SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
133512b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1336f5c1d5b2SJames Morris }
1337f5c1d5b2SJames Morris 
13381da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
13391da177e4SLinus Torvalds 	struct context *scontext,
13401da177e4SLinus Torvalds 	struct context *tcontext,
13411da177e4SLinus Torvalds 	u16 tclass,
13421da177e4SLinus Torvalds 	struct context *newcontext)
13431da177e4SLinus Torvalds {
13441da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
13451da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
13461da177e4SLinus Torvalds 
13474b02b524SEric Paris 	if (context_struct_to_string(scontext, &s, &slen))
13481da177e4SLinus Torvalds 		goto out;
13494b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
13501da177e4SLinus Torvalds 		goto out;
13514b02b524SEric Paris 	if (context_struct_to_string(newcontext, &n, &nlen))
13521da177e4SLinus Torvalds 		goto out;
13539ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
13541da177e4SLinus Torvalds 		  "security_compute_sid:  invalid context %s"
13551da177e4SLinus Torvalds 		  " for scontext=%s"
13561da177e4SLinus Torvalds 		  " tcontext=%s"
13571da177e4SLinus Torvalds 		  " tclass=%s",
1358ac76c05bSEric Paris 		  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
13591da177e4SLinus Torvalds out:
13601da177e4SLinus Torvalds 	kfree(s);
13611da177e4SLinus Torvalds 	kfree(t);
13621da177e4SLinus Torvalds 	kfree(n);
13631da177e4SLinus Torvalds 	if (!selinux_enforcing)
13641da177e4SLinus Torvalds 		return 0;
13651da177e4SLinus Torvalds 	return -EACCES;
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds 
1368652bb9b0SEric Paris static void filename_compute_type(struct policydb *p, struct context *newcontext,
13692667991fSEric Paris 				  u32 stype, u32 ttype, u16 tclass,
1370f50a3ec9SKohei Kaigai 				  const char *objname)
1371652bb9b0SEric Paris {
13722463c26dSEric Paris 	struct filename_trans ft;
13732463c26dSEric Paris 	struct filename_trans_datum *otype;
137403a4c018SEric Paris 
137503a4c018SEric Paris 	/*
137603a4c018SEric Paris 	 * Most filename trans rules are going to live in specific directories
137703a4c018SEric Paris 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
137803a4c018SEric Paris 	 * if the ttype does not contain any rules.
137903a4c018SEric Paris 	 */
138003a4c018SEric Paris 	if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
1381652bb9b0SEric Paris 		return;
138203a4c018SEric Paris 
13832463c26dSEric Paris 	ft.stype = stype;
13842463c26dSEric Paris 	ft.ttype = ttype;
13852463c26dSEric Paris 	ft.tclass = tclass;
13862463c26dSEric Paris 	ft.name = objname;
13872463c26dSEric Paris 
13882463c26dSEric Paris 	otype = hashtab_search(p->filename_trans, &ft);
13892463c26dSEric Paris 	if (otype)
13902463c26dSEric Paris 		newcontext->type = otype->otype;
1391652bb9b0SEric Paris }
1392652bb9b0SEric Paris 
13931da177e4SLinus Torvalds static int security_compute_sid(u32 ssid,
13941da177e4SLinus Torvalds 				u32 tsid,
1395c6d3aaa4SStephen Smalley 				u16 orig_tclass,
13961da177e4SLinus Torvalds 				u32 specified,
1397f50a3ec9SKohei Kaigai 				const char *objname,
1398c6d3aaa4SStephen Smalley 				u32 *out_sid,
1399c6d3aaa4SStephen Smalley 				bool kern)
14001da177e4SLinus Torvalds {
1401aa893269SEric Paris 	struct class_datum *cladatum = NULL;
14021da177e4SLinus Torvalds 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
14031da177e4SLinus Torvalds 	struct role_trans *roletr = NULL;
14041da177e4SLinus Torvalds 	struct avtab_key avkey;
14051da177e4SLinus Torvalds 	struct avtab_datum *avdatum;
14061da177e4SLinus Torvalds 	struct avtab_node *node;
1407c6d3aaa4SStephen Smalley 	u16 tclass;
14081da177e4SLinus Torvalds 	int rc = 0;
14096f5317e7SHarry Ciao 	bool sock;
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	if (!ss_initialized) {
1412c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1413c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
14141da177e4SLinus Torvalds 			*out_sid = ssid;
14151da177e4SLinus Torvalds 			break;
14161da177e4SLinus Torvalds 		default:
14171da177e4SLinus Torvalds 			*out_sid = tsid;
14181da177e4SLinus Torvalds 			break;
14191da177e4SLinus Torvalds 		}
14201da177e4SLinus Torvalds 		goto out;
14211da177e4SLinus Torvalds 	}
14221da177e4SLinus Torvalds 
1423851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1424851f8a69SVenkat Yekkirala 
14250804d113SJames Morris 	read_lock(&policy_rwlock);
14261da177e4SLinus Torvalds 
14276f5317e7SHarry Ciao 	if (kern) {
1428c6d3aaa4SStephen Smalley 		tclass = unmap_class(orig_tclass);
14296f5317e7SHarry Ciao 		sock = security_is_socket_class(orig_tclass);
14306f5317e7SHarry Ciao 	} else {
1431c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
14326f5317e7SHarry Ciao 		sock = security_is_socket_class(map_class(tclass));
14336f5317e7SHarry Ciao 	}
1434c6d3aaa4SStephen Smalley 
14351da177e4SLinus Torvalds 	scontext = sidtab_search(&sidtab, ssid);
14361da177e4SLinus Torvalds 	if (!scontext) {
1437744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1438744ba35eSEric Paris 		       __func__, ssid);
14391da177e4SLinus Torvalds 		rc = -EINVAL;
14401da177e4SLinus Torvalds 		goto out_unlock;
14411da177e4SLinus Torvalds 	}
14421da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tsid);
14431da177e4SLinus Torvalds 	if (!tcontext) {
1444744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1445744ba35eSEric Paris 		       __func__, tsid);
14461da177e4SLinus Torvalds 		rc = -EINVAL;
14471da177e4SLinus Torvalds 		goto out_unlock;
14481da177e4SLinus Torvalds 	}
14491da177e4SLinus Torvalds 
1450aa893269SEric Paris 	if (tclass && tclass <= policydb.p_classes.nprim)
1451aa893269SEric Paris 		cladatum = policydb.class_val_to_struct[tclass - 1];
1452aa893269SEric Paris 
14531da177e4SLinus Torvalds 	/* Set the user identity. */
14541da177e4SLinus Torvalds 	switch (specified) {
14551da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
14561da177e4SLinus Torvalds 	case AVTAB_CHANGE:
1457aa893269SEric Paris 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1458aa893269SEric Paris 			newcontext.user = tcontext->user;
1459aa893269SEric Paris 		} else {
1460aa893269SEric Paris 			/* notice this gets both DEFAULT_SOURCE and unset */
14611da177e4SLinus Torvalds 			/* Use the process user identity. */
14621da177e4SLinus Torvalds 			newcontext.user = scontext->user;
1463aa893269SEric Paris 		}
14641da177e4SLinus Torvalds 		break;
14651da177e4SLinus Torvalds 	case AVTAB_MEMBER:
14661da177e4SLinus Torvalds 		/* Use the related object owner. */
14671da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
14681da177e4SLinus Torvalds 		break;
14691da177e4SLinus Torvalds 	}
14701da177e4SLinus Torvalds 
1471aa893269SEric Paris 	/* Set the role to default values. */
1472aa893269SEric Paris 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
14731da177e4SLinus Torvalds 		newcontext.role = scontext->role;
1474aa893269SEric Paris 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1475aa893269SEric Paris 		newcontext.role = tcontext->role;
1476aa893269SEric Paris 	} else {
1477aa893269SEric Paris 		if ((tclass == policydb.process_class) || (sock == true))
1478aa893269SEric Paris 			newcontext.role = scontext->role;
1479aa893269SEric Paris 		else
1480aa893269SEric Paris 			newcontext.role = OBJECT_R_VAL;
1481aa893269SEric Paris 	}
1482aa893269SEric Paris 
1483aa893269SEric Paris 	/* Set the type to default values. */
1484eed7795dSEric Paris 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1485eed7795dSEric Paris 		newcontext.type = scontext->type;
1486eed7795dSEric Paris 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1487eed7795dSEric Paris 		newcontext.type = tcontext->type;
1488eed7795dSEric Paris 	} else {
1489aa893269SEric Paris 		if ((tclass == policydb.process_class) || (sock == true)) {
1490aa893269SEric Paris 			/* Use the type of process. */
14911da177e4SLinus Torvalds 			newcontext.type = scontext->type;
1492c6d3aaa4SStephen Smalley 		} else {
14931da177e4SLinus Torvalds 			/* Use the type of the related object. */
14941da177e4SLinus Torvalds 			newcontext.type = tcontext->type;
14951da177e4SLinus Torvalds 		}
1496eed7795dSEric Paris 	}
14971da177e4SLinus Torvalds 
14981da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
14991da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
15001da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
15011da177e4SLinus Torvalds 	avkey.target_class = tclass;
1502782ebb99SStephen Smalley 	avkey.specified = specified;
1503782ebb99SStephen Smalley 	avdatum = avtab_search(&policydb.te_avtab, &avkey);
15041da177e4SLinus Torvalds 
15051da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
15061da177e4SLinus Torvalds 	if (!avdatum) {
1507782ebb99SStephen Smalley 		node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
1508dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1509782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
15101da177e4SLinus Torvalds 				avdatum = &node->datum;
15111da177e4SLinus Torvalds 				break;
15121da177e4SLinus Torvalds 			}
15131da177e4SLinus Torvalds 		}
15141da177e4SLinus Torvalds 	}
15151da177e4SLinus Torvalds 
1516782ebb99SStephen Smalley 	if (avdatum) {
15171da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
1518782ebb99SStephen Smalley 		newcontext.type = avdatum->data;
15191da177e4SLinus Torvalds 	}
15201da177e4SLinus Torvalds 
15214742600cSEric Paris 	/* if we have a objname this is a file trans check so check those rules */
1522f50a3ec9SKohei Kaigai 	if (objname)
1523652bb9b0SEric Paris 		filename_compute_type(&policydb, &newcontext, scontext->type,
1524f50a3ec9SKohei Kaigai 				      tcontext->type, tclass, objname);
1525652bb9b0SEric Paris 
15261da177e4SLinus Torvalds 	/* Check for class-specific changes. */
15271da177e4SLinus Torvalds 	if (specified & AVTAB_TRANSITION) {
15281da177e4SLinus Torvalds 		/* Look for a role transition rule. */
152963a312caSHarry Ciao 		for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
153063a312caSHarry Ciao 			if ((roletr->role == scontext->role) &&
153163a312caSHarry Ciao 			    (roletr->type == tcontext->type) &&
153263a312caSHarry Ciao 			    (roletr->tclass == tclass)) {
15331da177e4SLinus Torvalds 				/* Use the role transition rule. */
15341da177e4SLinus Torvalds 				newcontext.role = roletr->new_role;
15351da177e4SLinus Torvalds 				break;
15361da177e4SLinus Torvalds 			}
15371da177e4SLinus Torvalds 		}
15381da177e4SLinus Torvalds 	}
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	/* Set the MLS attributes.
15411da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
15426f5317e7SHarry Ciao 	rc = mls_compute_sid(scontext, tcontext, tclass, specified,
15436f5317e7SHarry Ciao 			     &newcontext, sock);
15441da177e4SLinus Torvalds 	if (rc)
15451da177e4SLinus Torvalds 		goto out_unlock;
15461da177e4SLinus Torvalds 
15471da177e4SLinus Torvalds 	/* Check the validity of the context. */
15481da177e4SLinus Torvalds 	if (!policydb_context_isvalid(&policydb, &newcontext)) {
15491da177e4SLinus Torvalds 		rc = compute_sid_handle_invalid_context(scontext,
15501da177e4SLinus Torvalds 							tcontext,
15511da177e4SLinus Torvalds 							tclass,
15521da177e4SLinus Torvalds 							&newcontext);
15531da177e4SLinus Torvalds 		if (rc)
15541da177e4SLinus Torvalds 			goto out_unlock;
15551da177e4SLinus Torvalds 	}
15561da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
15571da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
15581da177e4SLinus Torvalds out_unlock:
15590804d113SJames Morris 	read_unlock(&policy_rwlock);
15601da177e4SLinus Torvalds 	context_destroy(&newcontext);
15611da177e4SLinus Torvalds out:
15621da177e4SLinus Torvalds 	return rc;
15631da177e4SLinus Torvalds }
15641da177e4SLinus Torvalds 
15651da177e4SLinus Torvalds /**
15661da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
15671da177e4SLinus Torvalds  * @ssid: source security identifier
15681da177e4SLinus Torvalds  * @tsid: target security identifier
15691da177e4SLinus Torvalds  * @tclass: target security class
15701da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
15711da177e4SLinus Torvalds  *
15721da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
15731da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
15741da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
15751da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
15761da177e4SLinus Torvalds  * computed successfully.
15771da177e4SLinus Torvalds  */
1578652bb9b0SEric Paris int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1579652bb9b0SEric Paris 			    const struct qstr *qstr, u32 *out_sid)
15801da177e4SLinus Torvalds {
1581c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1582f50a3ec9SKohei Kaigai 				    qstr ? qstr->name : NULL, out_sid, true);
1583c6d3aaa4SStephen Smalley }
1584c6d3aaa4SStephen Smalley 
1585f50a3ec9SKohei Kaigai int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1586f50a3ec9SKohei Kaigai 				 const char *objname, u32 *out_sid)
1587c6d3aaa4SStephen Smalley {
1588c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1589f50a3ec9SKohei Kaigai 				    objname, out_sid, false);
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds /**
15931da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
15941da177e4SLinus Torvalds  * @ssid: source security identifier
15951da177e4SLinus Torvalds  * @tsid: target security identifier
15961da177e4SLinus Torvalds  * @tclass: target security class
15971da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
15981da177e4SLinus Torvalds  *
15991da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
16001da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
16011da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
16021da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
16031da177e4SLinus Torvalds  * computed successfully.
16041da177e4SLinus Torvalds  */
16051da177e4SLinus Torvalds int security_member_sid(u32 ssid,
16061da177e4SLinus Torvalds 			u32 tsid,
16071da177e4SLinus Torvalds 			u16 tclass,
16081da177e4SLinus Torvalds 			u32 *out_sid)
16091da177e4SLinus Torvalds {
1610652bb9b0SEric Paris 	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL,
1611652bb9b0SEric Paris 				    out_sid, false);
16121da177e4SLinus Torvalds }
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds /**
16151da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
16161da177e4SLinus Torvalds  * @ssid: source security identifier
16171da177e4SLinus Torvalds  * @tsid: target security identifier
16181da177e4SLinus Torvalds  * @tclass: target security class
16191da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
16201da177e4SLinus Torvalds  *
16211da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
16221da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
16231da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
16241da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
16251da177e4SLinus Torvalds  * computed successfully.
16261da177e4SLinus Torvalds  */
16271da177e4SLinus Torvalds int security_change_sid(u32 ssid,
16281da177e4SLinus Torvalds 			u32 tsid,
16291da177e4SLinus Torvalds 			u16 tclass,
16301da177e4SLinus Torvalds 			u32 *out_sid)
16311da177e4SLinus Torvalds {
1632652bb9b0SEric Paris 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1633652bb9b0SEric Paris 				    out_sid, false);
1634b94c7e67SChad Sellers }
1635b94c7e67SChad Sellers 
16361da177e4SLinus Torvalds /* Clone the SID into the new SID table. */
16371da177e4SLinus Torvalds static int clone_sid(u32 sid,
16381da177e4SLinus Torvalds 		     struct context *context,
16391da177e4SLinus Torvalds 		     void *arg)
16401da177e4SLinus Torvalds {
16411da177e4SLinus Torvalds 	struct sidtab *s = arg;
16421da177e4SLinus Torvalds 
164342596eafSGuido Trentalancia 	if (sid > SECINITSID_NUM)
16441da177e4SLinus Torvalds 		return sidtab_insert(s, sid, context);
164542596eafSGuido Trentalancia 	else
164642596eafSGuido Trentalancia 		return 0;
16471da177e4SLinus Torvalds }
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context)
16501da177e4SLinus Torvalds {
16511da177e4SLinus Torvalds 	char *s;
16521da177e4SLinus Torvalds 	u32 len;
16531da177e4SLinus Torvalds 
16544b02b524SEric Paris 	if (selinux_enforcing)
16554b02b524SEric Paris 		return -EINVAL;
16564b02b524SEric Paris 
165712b29f34SStephen Smalley 	if (!context_struct_to_string(context, &s, &len)) {
16584b02b524SEric Paris 		printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
16591da177e4SLinus Torvalds 		kfree(s);
16601da177e4SLinus Torvalds 	}
16614b02b524SEric Paris 	return 0;
16621da177e4SLinus Torvalds }
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds struct convert_context_args {
16651da177e4SLinus Torvalds 	struct policydb *oldp;
16661da177e4SLinus Torvalds 	struct policydb *newp;
16671da177e4SLinus Torvalds };
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds /*
16701da177e4SLinus Torvalds  * Convert the values in the security context
16711da177e4SLinus Torvalds  * structure `c' from the values specified
16721da177e4SLinus Torvalds  * in the policy `p->oldp' to the values specified
16731da177e4SLinus Torvalds  * in the policy `p->newp'.  Verify that the
16741da177e4SLinus Torvalds  * context is valid under the new policy.
16751da177e4SLinus Torvalds  */
16761da177e4SLinus Torvalds static int convert_context(u32 key,
16771da177e4SLinus Torvalds 			   struct context *c,
16781da177e4SLinus Torvalds 			   void *p)
16791da177e4SLinus Torvalds {
16801da177e4SLinus Torvalds 	struct convert_context_args *args;
16811da177e4SLinus Torvalds 	struct context oldc;
16820719aaf5SGuido Trentalancia 	struct ocontext *oc;
16830719aaf5SGuido Trentalancia 	struct mls_range *range;
16841da177e4SLinus Torvalds 	struct role_datum *role;
16851da177e4SLinus Torvalds 	struct type_datum *typdatum;
16861da177e4SLinus Torvalds 	struct user_datum *usrdatum;
16871da177e4SLinus Torvalds 	char *s;
16881da177e4SLinus Torvalds 	u32 len;
168942596eafSGuido Trentalancia 	int rc = 0;
169042596eafSGuido Trentalancia 
169142596eafSGuido Trentalancia 	if (key <= SECINITSID_NUM)
169242596eafSGuido Trentalancia 		goto out;
16931da177e4SLinus Torvalds 
16941da177e4SLinus Torvalds 	args = p;
16951da177e4SLinus Torvalds 
169612b29f34SStephen Smalley 	if (c->str) {
169712b29f34SStephen Smalley 		struct context ctx;
16984b02b524SEric Paris 
16999a59daa0SStephen Smalley 		rc = -ENOMEM;
17004b02b524SEric Paris 		s = kstrdup(c->str, GFP_KERNEL);
17014b02b524SEric Paris 		if (!s)
17029a59daa0SStephen Smalley 			goto out;
17034b02b524SEric Paris 
17049a59daa0SStephen Smalley 		rc = string_to_context_struct(args->newp, NULL, s,
17059a59daa0SStephen Smalley 					      c->len, &ctx, SECSID_NULL);
17069a59daa0SStephen Smalley 		kfree(s);
170712b29f34SStephen Smalley 		if (!rc) {
17084b02b524SEric Paris 			printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
170912b29f34SStephen Smalley 			       c->str);
171012b29f34SStephen Smalley 			/* Replace string with mapped representation. */
171112b29f34SStephen Smalley 			kfree(c->str);
171212b29f34SStephen Smalley 			memcpy(c, &ctx, sizeof(*c));
171312b29f34SStephen Smalley 			goto out;
171412b29f34SStephen Smalley 		} else if (rc == -EINVAL) {
171512b29f34SStephen Smalley 			/* Retain string representation for later mapping. */
171612b29f34SStephen Smalley 			rc = 0;
171712b29f34SStephen Smalley 			goto out;
171812b29f34SStephen Smalley 		} else {
171912b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
17204b02b524SEric Paris 			printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
172112b29f34SStephen Smalley 			       c->str, -rc);
172212b29f34SStephen Smalley 			goto out;
172312b29f34SStephen Smalley 		}
172412b29f34SStephen Smalley 	}
172512b29f34SStephen Smalley 
17261da177e4SLinus Torvalds 	rc = context_cpy(&oldc, c);
17271da177e4SLinus Torvalds 	if (rc)
17281da177e4SLinus Torvalds 		goto out;
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds 	/* Convert the user. */
17314b02b524SEric Paris 	rc = -EINVAL;
17321da177e4SLinus Torvalds 	usrdatum = hashtab_search(args->newp->p_users.table,
1733ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_USERS, c->user - 1));
17345d55a345SEric Paris 	if (!usrdatum)
17351da177e4SLinus Torvalds 		goto bad;
17361da177e4SLinus Torvalds 	c->user = usrdatum->value;
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 	/* Convert the role. */
17394b02b524SEric Paris 	rc = -EINVAL;
17401da177e4SLinus Torvalds 	role = hashtab_search(args->newp->p_roles.table,
1741ac76c05bSEric Paris 			      sym_name(args->oldp, SYM_ROLES, c->role - 1));
17425d55a345SEric Paris 	if (!role)
17431da177e4SLinus Torvalds 		goto bad;
17441da177e4SLinus Torvalds 	c->role = role->value;
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds 	/* Convert the type. */
17474b02b524SEric Paris 	rc = -EINVAL;
17481da177e4SLinus Torvalds 	typdatum = hashtab_search(args->newp->p_types.table,
1749ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_TYPES, c->type - 1));
17505d55a345SEric Paris 	if (!typdatum)
17511da177e4SLinus Torvalds 		goto bad;
17521da177e4SLinus Torvalds 	c->type = typdatum->value;
17531da177e4SLinus Torvalds 
17540719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
17550719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
17561da177e4SLinus Torvalds 		rc = mls_convert_context(args->oldp, args->newp, c);
17571da177e4SLinus Torvalds 		if (rc)
17581da177e4SLinus Torvalds 			goto bad;
17590719aaf5SGuido Trentalancia 	} else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
17600719aaf5SGuido Trentalancia 		/*
17610719aaf5SGuido Trentalancia 		 * Switching between MLS and non-MLS policy:
17620719aaf5SGuido Trentalancia 		 * free any storage used by the MLS fields in the
17630719aaf5SGuido Trentalancia 		 * context for all existing entries in the sidtab.
17640719aaf5SGuido Trentalancia 		 */
17650719aaf5SGuido Trentalancia 		mls_context_destroy(c);
17660719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
17670719aaf5SGuido Trentalancia 		/*
17680719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
17690719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
17700719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
17710719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
17720719aaf5SGuido Trentalancia 		 * initial SIDs.
17730719aaf5SGuido Trentalancia 		 */
17740719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
17750719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
17760719aaf5SGuido Trentalancia 			oc = oc->next;
17774b02b524SEric Paris 		rc = -EINVAL;
17780719aaf5SGuido Trentalancia 		if (!oc) {
17790719aaf5SGuido Trentalancia 			printk(KERN_ERR "SELinux:  unable to look up"
17800719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
17810719aaf5SGuido Trentalancia 			goto bad;
17820719aaf5SGuido Trentalancia 		}
17830719aaf5SGuido Trentalancia 		range = &oc->context[0].range;
17840719aaf5SGuido Trentalancia 		rc = mls_range_set(c, range);
17850719aaf5SGuido Trentalancia 		if (rc)
17860719aaf5SGuido Trentalancia 			goto bad;
17870719aaf5SGuido Trentalancia 	}
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds 	/* Check the validity of the new context. */
17901da177e4SLinus Torvalds 	if (!policydb_context_isvalid(args->newp, c)) {
17911da177e4SLinus Torvalds 		rc = convert_context_handle_invalid_context(&oldc);
17921da177e4SLinus Torvalds 		if (rc)
17931da177e4SLinus Torvalds 			goto bad;
17941da177e4SLinus Torvalds 	}
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 	context_destroy(&oldc);
17974b02b524SEric Paris 
179812b29f34SStephen Smalley 	rc = 0;
17991da177e4SLinus Torvalds out:
18001da177e4SLinus Torvalds 	return rc;
18011da177e4SLinus Torvalds bad:
180212b29f34SStephen Smalley 	/* Map old representation to string and save it. */
18034b02b524SEric Paris 	rc = context_struct_to_string(&oldc, &s, &len);
18044b02b524SEric Paris 	if (rc)
18054b02b524SEric Paris 		return rc;
18061da177e4SLinus Torvalds 	context_destroy(&oldc);
180712b29f34SStephen Smalley 	context_destroy(c);
180812b29f34SStephen Smalley 	c->str = s;
180912b29f34SStephen Smalley 	c->len = len;
18104b02b524SEric Paris 	printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
181112b29f34SStephen Smalley 	       c->str);
181212b29f34SStephen Smalley 	rc = 0;
18131da177e4SLinus Torvalds 	goto out;
18141da177e4SLinus Torvalds }
18151da177e4SLinus Torvalds 
18163bb56b25SPaul Moore static void security_load_policycaps(void)
18173bb56b25SPaul Moore {
18183bb56b25SPaul Moore 	selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
18193bb56b25SPaul Moore 						  POLICYDB_CAPABILITY_NETPEER);
1820b0c636b9SEric Paris 	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
1821b0c636b9SEric Paris 						  POLICYDB_CAPABILITY_OPENPERM);
18222be4d74fSChris PeBenito 	selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
18232be4d74fSChris PeBenito 						  POLICYDB_CAPABILITY_ALWAYSNETWORK);
18243bb56b25SPaul Moore }
18253bb56b25SPaul Moore 
1826e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p);
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds /**
18291da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
18301da177e4SLinus Torvalds  * @data: binary policy data
18311da177e4SLinus Torvalds  * @len: length of data in bytes
18321da177e4SLinus Torvalds  *
18331da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
18341da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
18351da177e4SLinus Torvalds  * This function will flush the access vector cache after
18361da177e4SLinus Torvalds  * loading the new policy.
18371da177e4SLinus Torvalds  */
18381da177e4SLinus Torvalds int security_load_policy(void *data, size_t len)
18391da177e4SLinus Torvalds {
1840b5495b42STim Gardner 	struct policydb *oldpolicydb, *newpolicydb;
18411da177e4SLinus Torvalds 	struct sidtab oldsidtab, newsidtab;
1842c6d3aaa4SStephen Smalley 	struct selinux_mapping *oldmap, *map = NULL;
18431da177e4SLinus Torvalds 	struct convert_context_args args;
18441da177e4SLinus Torvalds 	u32 seqno;
1845c6d3aaa4SStephen Smalley 	u16 map_size;
18461da177e4SLinus Torvalds 	int rc = 0;
18471da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
18481da177e4SLinus Torvalds 
1849b5495b42STim Gardner 	oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
1850b5495b42STim Gardner 	if (!oldpolicydb) {
1851b5495b42STim Gardner 		rc = -ENOMEM;
1852b5495b42STim Gardner 		goto out;
1853b5495b42STim Gardner 	}
1854b5495b42STim Gardner 	newpolicydb = oldpolicydb + 1;
1855b5495b42STim Gardner 
18561da177e4SLinus Torvalds 	if (!ss_initialized) {
18571da177e4SLinus Torvalds 		avtab_cache_init();
1858a2000050SEric Paris 		rc = policydb_read(&policydb, fp);
1859a2000050SEric Paris 		if (rc) {
18601da177e4SLinus Torvalds 			avtab_cache_destroy();
1861b5495b42STim Gardner 			goto out;
18621da177e4SLinus Torvalds 		}
1863a2000050SEric Paris 
1864cee74f47SEric Paris 		policydb.len = len;
1865a2000050SEric Paris 		rc = selinux_set_mapping(&policydb, secclass_map,
1866c6d3aaa4SStephen Smalley 					 &current_mapping,
1867a2000050SEric Paris 					 &current_mapping_size);
1868a2000050SEric Paris 		if (rc) {
18691da177e4SLinus Torvalds 			policydb_destroy(&policydb);
18701da177e4SLinus Torvalds 			avtab_cache_destroy();
1871b5495b42STim Gardner 			goto out;
18721da177e4SLinus Torvalds 		}
1873a2000050SEric Paris 
1874a2000050SEric Paris 		rc = policydb_load_isids(&policydb, &sidtab);
1875a2000050SEric Paris 		if (rc) {
1876b94c7e67SChad Sellers 			policydb_destroy(&policydb);
1877b94c7e67SChad Sellers 			avtab_cache_destroy();
1878b5495b42STim Gardner 			goto out;
1879b94c7e67SChad Sellers 		}
1880a2000050SEric Paris 
18813bb56b25SPaul Moore 		security_load_policycaps();
18821da177e4SLinus Torvalds 		ss_initialized = 1;
18834c443d1bSStephen Smalley 		seqno = ++latest_granting;
18841da177e4SLinus Torvalds 		selinux_complete_init();
18854c443d1bSStephen Smalley 		avc_ss_reset(seqno);
18864c443d1bSStephen Smalley 		selnl_notify_policyload(seqno);
188711904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
18887420ed23SVenkat Yekkirala 		selinux_netlbl_cache_invalidate();
1889342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
1890b5495b42STim Gardner 		goto out;
18911da177e4SLinus Torvalds 	}
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds #if 0
18941da177e4SLinus Torvalds 	sidtab_hash_eval(&sidtab, "sids");
18951da177e4SLinus Torvalds #endif
18961da177e4SLinus Torvalds 
1897b5495b42STim Gardner 	rc = policydb_read(newpolicydb, fp);
1898a2000050SEric Paris 	if (rc)
1899b5495b42STim Gardner 		goto out;
19001da177e4SLinus Torvalds 
1901b5495b42STim Gardner 	newpolicydb->len = len;
19020719aaf5SGuido Trentalancia 	/* If switching between different policy types, log MLS status */
1903b5495b42STim Gardner 	if (policydb.mls_enabled && !newpolicydb->mls_enabled)
19040719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Disabling MLS support...\n");
1905b5495b42STim Gardner 	else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
19060719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Enabling MLS support...\n");
19070719aaf5SGuido Trentalancia 
1908b5495b42STim Gardner 	rc = policydb_load_isids(newpolicydb, &newsidtab);
190942596eafSGuido Trentalancia 	if (rc) {
191042596eafSGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
1911b5495b42STim Gardner 		policydb_destroy(newpolicydb);
1912b5495b42STim Gardner 		goto out;
191312b29f34SStephen Smalley 	}
19141da177e4SLinus Torvalds 
1915b5495b42STim Gardner 	rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
1916a2000050SEric Paris 	if (rc)
1917b94c7e67SChad Sellers 		goto err;
1918b94c7e67SChad Sellers 
1919b5495b42STim Gardner 	rc = security_preserve_bools(newpolicydb);
1920e900a7d9SStephen Smalley 	if (rc) {
1921454d972cSJames Morris 		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");
1922e900a7d9SStephen Smalley 		goto err;
1923e900a7d9SStephen Smalley 	}
1924e900a7d9SStephen Smalley 
19251da177e4SLinus Torvalds 	/* Clone the SID table. */
19261da177e4SLinus Torvalds 	sidtab_shutdown(&sidtab);
1927a2000050SEric Paris 
1928a2000050SEric Paris 	rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
1929a2000050SEric Paris 	if (rc)
19301da177e4SLinus Torvalds 		goto err;
19311da177e4SLinus Torvalds 
193212b29f34SStephen Smalley 	/*
193312b29f34SStephen Smalley 	 * Convert the internal representations of contexts
193412b29f34SStephen Smalley 	 * in the new SID table.
193512b29f34SStephen Smalley 	 */
19361da177e4SLinus Torvalds 	args.oldp = &policydb;
1937b5495b42STim Gardner 	args.newp = newpolicydb;
193812b29f34SStephen Smalley 	rc = sidtab_map(&newsidtab, convert_context, &args);
19390719aaf5SGuido Trentalancia 	if (rc) {
19400719aaf5SGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to convert the internal"
19410719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
19420719aaf5SGuido Trentalancia 			" table\n");
194312b29f34SStephen Smalley 		goto err;
19440719aaf5SGuido Trentalancia 	}
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 	/* Save the old policydb and SID table to free later. */
1947b5495b42STim Gardner 	memcpy(oldpolicydb, &policydb, sizeof(policydb));
19481da177e4SLinus Torvalds 	sidtab_set(&oldsidtab, &sidtab);
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 	/* Install the new policydb and SID table. */
19510804d113SJames Morris 	write_lock_irq(&policy_rwlock);
1952b5495b42STim Gardner 	memcpy(&policydb, newpolicydb, sizeof(policydb));
19531da177e4SLinus Torvalds 	sidtab_set(&sidtab, &newsidtab);
19543bb56b25SPaul Moore 	security_load_policycaps();
1955c6d3aaa4SStephen Smalley 	oldmap = current_mapping;
1956c6d3aaa4SStephen Smalley 	current_mapping = map;
1957c6d3aaa4SStephen Smalley 	current_mapping_size = map_size;
19581da177e4SLinus Torvalds 	seqno = ++latest_granting;
19590804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	/* Free the old policydb and SID table. */
1962b5495b42STim Gardner 	policydb_destroy(oldpolicydb);
19631da177e4SLinus Torvalds 	sidtab_destroy(&oldsidtab);
1964c6d3aaa4SStephen Smalley 	kfree(oldmap);
19651da177e4SLinus Torvalds 
19661da177e4SLinus Torvalds 	avc_ss_reset(seqno);
19671da177e4SLinus Torvalds 	selnl_notify_policyload(seqno);
196811904167SKaiGai Kohei 	selinux_status_update_policyload(seqno);
19697420ed23SVenkat Yekkirala 	selinux_netlbl_cache_invalidate();
1970342a0cffSVenkat Yekkirala 	selinux_xfrm_notify_policyload();
19711da177e4SLinus Torvalds 
1972b5495b42STim Gardner 	rc = 0;
1973b5495b42STim Gardner 	goto out;
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds err:
1976c6d3aaa4SStephen Smalley 	kfree(map);
19771da177e4SLinus Torvalds 	sidtab_destroy(&newsidtab);
1978b5495b42STim Gardner 	policydb_destroy(newpolicydb);
19791da177e4SLinus Torvalds 
1980b5495b42STim Gardner out:
1981b5495b42STim Gardner 	kfree(oldpolicydb);
1982b5495b42STim Gardner 	return rc;
19831da177e4SLinus Torvalds }
19841da177e4SLinus Torvalds 
1985cee74f47SEric Paris size_t security_policydb_len(void)
1986cee74f47SEric Paris {
1987cee74f47SEric Paris 	size_t len;
1988cee74f47SEric Paris 
1989cee74f47SEric Paris 	read_lock(&policy_rwlock);
1990cee74f47SEric Paris 	len = policydb.len;
1991cee74f47SEric Paris 	read_unlock(&policy_rwlock);
1992cee74f47SEric Paris 
1993cee74f47SEric Paris 	return len;
1994cee74f47SEric Paris }
1995cee74f47SEric Paris 
19961da177e4SLinus Torvalds /**
19971da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
19981da177e4SLinus Torvalds  * @protocol: protocol number
19991da177e4SLinus Torvalds  * @port: port number
20001da177e4SLinus Torvalds  * @out_sid: security identifier
20011da177e4SLinus Torvalds  */
20023e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
20031da177e4SLinus Torvalds {
20041da177e4SLinus Torvalds 	struct ocontext *c;
20051da177e4SLinus Torvalds 	int rc = 0;
20061da177e4SLinus Torvalds 
20070804d113SJames Morris 	read_lock(&policy_rwlock);
20081da177e4SLinus Torvalds 
20091da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_PORT];
20101da177e4SLinus Torvalds 	while (c) {
20111da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
20121da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
20131da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
20141da177e4SLinus Torvalds 			break;
20151da177e4SLinus Torvalds 		c = c->next;
20161da177e4SLinus Torvalds 	}
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 	if (c) {
20191da177e4SLinus Torvalds 		if (!c->sid[0]) {
20201da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
20211da177e4SLinus Torvalds 						   &c->context[0],
20221da177e4SLinus Torvalds 						   &c->sid[0]);
20231da177e4SLinus Torvalds 			if (rc)
20241da177e4SLinus Torvalds 				goto out;
20251da177e4SLinus Torvalds 		}
20261da177e4SLinus Torvalds 		*out_sid = c->sid[0];
20271da177e4SLinus Torvalds 	} else {
20281da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
20291da177e4SLinus Torvalds 	}
20301da177e4SLinus Torvalds 
20311da177e4SLinus Torvalds out:
20320804d113SJames Morris 	read_unlock(&policy_rwlock);
20331da177e4SLinus Torvalds 	return rc;
20341da177e4SLinus Torvalds }
20351da177e4SLinus Torvalds 
20361da177e4SLinus Torvalds /**
20371da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
20381da177e4SLinus Torvalds  * @name: interface name
20391da177e4SLinus Torvalds  * @if_sid: interface SID
20401da177e4SLinus Torvalds  */
2041e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid)
20421da177e4SLinus Torvalds {
20431da177e4SLinus Torvalds 	int rc = 0;
20441da177e4SLinus Torvalds 	struct ocontext *c;
20451da177e4SLinus Torvalds 
20460804d113SJames Morris 	read_lock(&policy_rwlock);
20471da177e4SLinus Torvalds 
20481da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_NETIF];
20491da177e4SLinus Torvalds 	while (c) {
20501da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
20511da177e4SLinus Torvalds 			break;
20521da177e4SLinus Torvalds 		c = c->next;
20531da177e4SLinus Torvalds 	}
20541da177e4SLinus Torvalds 
20551da177e4SLinus Torvalds 	if (c) {
20561da177e4SLinus Torvalds 		if (!c->sid[0] || !c->sid[1]) {
20571da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
20581da177e4SLinus Torvalds 						  &c->context[0],
20591da177e4SLinus Torvalds 						  &c->sid[0]);
20601da177e4SLinus Torvalds 			if (rc)
20611da177e4SLinus Torvalds 				goto out;
20621da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
20631da177e4SLinus Torvalds 						   &c->context[1],
20641da177e4SLinus Torvalds 						   &c->sid[1]);
20651da177e4SLinus Torvalds 			if (rc)
20661da177e4SLinus Torvalds 				goto out;
20671da177e4SLinus Torvalds 		}
20681da177e4SLinus Torvalds 		*if_sid = c->sid[0];
2069e8bfdb9dSPaul Moore 	} else
20701da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
20711da177e4SLinus Torvalds 
20721da177e4SLinus Torvalds out:
20730804d113SJames Morris 	read_unlock(&policy_rwlock);
20741da177e4SLinus Torvalds 	return rc;
20751da177e4SLinus Torvalds }
20761da177e4SLinus Torvalds 
20771da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
20781da177e4SLinus Torvalds {
20791da177e4SLinus Torvalds 	int i, fail = 0;
20801da177e4SLinus Torvalds 
20811da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
20821da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
20831da177e4SLinus Torvalds 			fail = 1;
20841da177e4SLinus Torvalds 			break;
20851da177e4SLinus Torvalds 		}
20861da177e4SLinus Torvalds 
20871da177e4SLinus Torvalds 	return !fail;
20881da177e4SLinus Torvalds }
20891da177e4SLinus Torvalds 
20901da177e4SLinus Torvalds /**
20911da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
20921da177e4SLinus Torvalds  * @domain: communication domain aka address family
20931da177e4SLinus Torvalds  * @addrp: address
20941da177e4SLinus Torvalds  * @addrlen: address length in bytes
20951da177e4SLinus Torvalds  * @out_sid: security identifier
20961da177e4SLinus Torvalds  */
20971da177e4SLinus Torvalds int security_node_sid(u16 domain,
20981da177e4SLinus Torvalds 		      void *addrp,
20991da177e4SLinus Torvalds 		      u32 addrlen,
21001da177e4SLinus Torvalds 		      u32 *out_sid)
21011da177e4SLinus Torvalds {
21024b02b524SEric Paris 	int rc;
21031da177e4SLinus Torvalds 	struct ocontext *c;
21041da177e4SLinus Torvalds 
21050804d113SJames Morris 	read_lock(&policy_rwlock);
21061da177e4SLinus Torvalds 
21071da177e4SLinus Torvalds 	switch (domain) {
21081da177e4SLinus Torvalds 	case AF_INET: {
21091da177e4SLinus Torvalds 		u32 addr;
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds 		rc = -EINVAL;
21124b02b524SEric Paris 		if (addrlen != sizeof(u32))
21131da177e4SLinus Torvalds 			goto out;
21141da177e4SLinus Torvalds 
21151da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
21161da177e4SLinus Torvalds 
21171da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE];
21181da177e4SLinus Torvalds 		while (c) {
21191da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
21201da177e4SLinus Torvalds 				break;
21211da177e4SLinus Torvalds 			c = c->next;
21221da177e4SLinus Torvalds 		}
21231da177e4SLinus Torvalds 		break;
21241da177e4SLinus Torvalds 	}
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds 	case AF_INET6:
21271da177e4SLinus Torvalds 		rc = -EINVAL;
21284b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
21291da177e4SLinus Torvalds 			goto out;
21301da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE6];
21311da177e4SLinus Torvalds 		while (c) {
21321da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
21331da177e4SLinus Torvalds 						c->u.node6.mask))
21341da177e4SLinus Torvalds 				break;
21351da177e4SLinus Torvalds 			c = c->next;
21361da177e4SLinus Torvalds 		}
21371da177e4SLinus Torvalds 		break;
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds 	default:
21404b02b524SEric Paris 		rc = 0;
21411da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
21421da177e4SLinus Torvalds 		goto out;
21431da177e4SLinus Torvalds 	}
21441da177e4SLinus Torvalds 
21451da177e4SLinus Torvalds 	if (c) {
21461da177e4SLinus Torvalds 		if (!c->sid[0]) {
21471da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
21481da177e4SLinus Torvalds 						   &c->context[0],
21491da177e4SLinus Torvalds 						   &c->sid[0]);
21501da177e4SLinus Torvalds 			if (rc)
21511da177e4SLinus Torvalds 				goto out;
21521da177e4SLinus Torvalds 		}
21531da177e4SLinus Torvalds 		*out_sid = c->sid[0];
21541da177e4SLinus Torvalds 	} else {
21551da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
21561da177e4SLinus Torvalds 	}
21571da177e4SLinus Torvalds 
21584b02b524SEric Paris 	rc = 0;
21591da177e4SLinus Torvalds out:
21600804d113SJames Morris 	read_unlock(&policy_rwlock);
21611da177e4SLinus Torvalds 	return rc;
21621da177e4SLinus Torvalds }
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds #define SIDS_NEL 25
21651da177e4SLinus Torvalds 
21661da177e4SLinus Torvalds /**
21671da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
21681da177e4SLinus Torvalds  * @fromsid: starting SID
21691da177e4SLinus Torvalds  * @username: username
21701da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
21711da177e4SLinus Torvalds  * @nel: number of elements in @sids
21721da177e4SLinus Torvalds  *
21731da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
21741da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
21751da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
21761da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
21771da177e4SLinus Torvalds  * number of elements in the array.
21781da177e4SLinus Torvalds  */
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid,
21811da177e4SLinus Torvalds 			   char *username,
21821da177e4SLinus Torvalds 			   u32 **sids,
21831da177e4SLinus Torvalds 			   u32 *nel)
21841da177e4SLinus Torvalds {
21851da177e4SLinus Torvalds 	struct context *fromcon, usercon;
21862c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
21871da177e4SLinus Torvalds 	u32 mynel = 0, maxnel = SIDS_NEL;
21881da177e4SLinus Torvalds 	struct user_datum *user;
21891da177e4SLinus Torvalds 	struct role_datum *role;
2190782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
21911da177e4SLinus Torvalds 	int rc = 0, i, j;
21921da177e4SLinus Torvalds 
21931da177e4SLinus Torvalds 	*sids = NULL;
21941da177e4SLinus Torvalds 	*nel = 0;
21952c3c05dbSStephen Smalley 
21962c3c05dbSStephen Smalley 	if (!ss_initialized)
21971da177e4SLinus Torvalds 		goto out;
21981da177e4SLinus Torvalds 
21990804d113SJames Morris 	read_lock(&policy_rwlock);
22001da177e4SLinus Torvalds 
220112b29f34SStephen Smalley 	context_init(&usercon);
220212b29f34SStephen Smalley 
22034b02b524SEric Paris 	rc = -EINVAL;
22041da177e4SLinus Torvalds 	fromcon = sidtab_search(&sidtab, fromsid);
22054b02b524SEric Paris 	if (!fromcon)
22061da177e4SLinus Torvalds 		goto out_unlock;
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds 	rc = -EINVAL;
22094b02b524SEric Paris 	user = hashtab_search(policydb.p_users.table, username);
22104b02b524SEric Paris 	if (!user)
22111da177e4SLinus Torvalds 		goto out_unlock;
22124b02b524SEric Paris 
22131da177e4SLinus Torvalds 	usercon.user = user->value;
22141da177e4SLinus Torvalds 
22151da177e4SLinus Torvalds 	rc = -ENOMEM;
22164b02b524SEric Paris 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
22174b02b524SEric Paris 	if (!mysids)
22181da177e4SLinus Torvalds 		goto out_unlock;
22191da177e4SLinus Torvalds 
22209fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
22211da177e4SLinus Torvalds 		role = policydb.role_val_to_struct[i];
22221da177e4SLinus Torvalds 		usercon.role = i + 1;
22239fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
22241da177e4SLinus Torvalds 			usercon.type = j + 1;
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 			if (mls_setup_user_range(fromcon, user, &usercon))
22271da177e4SLinus Torvalds 				continue;
22281da177e4SLinus Torvalds 
22291da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
22302c3c05dbSStephen Smalley 			if (rc)
22311da177e4SLinus Torvalds 				goto out_unlock;
22321da177e4SLinus Torvalds 			if (mynel < maxnel) {
22331da177e4SLinus Torvalds 				mysids[mynel++] = sid;
22341da177e4SLinus Torvalds 			} else {
22354b02b524SEric Paris 				rc = -ENOMEM;
22361da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
223789d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
22384b02b524SEric Paris 				if (!mysids2)
22391da177e4SLinus Torvalds 					goto out_unlock;
22401da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
22411da177e4SLinus Torvalds 				kfree(mysids);
22421da177e4SLinus Torvalds 				mysids = mysids2;
22431da177e4SLinus Torvalds 				mysids[mynel++] = sid;
22441da177e4SLinus Torvalds 			}
22451da177e4SLinus Torvalds 		}
22461da177e4SLinus Torvalds 	}
22474b02b524SEric Paris 	rc = 0;
22481da177e4SLinus Torvalds out_unlock:
22490804d113SJames Morris 	read_unlock(&policy_rwlock);
22502c3c05dbSStephen Smalley 	if (rc || !mynel) {
22512c3c05dbSStephen Smalley 		kfree(mysids);
22522c3c05dbSStephen Smalley 		goto out;
22532c3c05dbSStephen Smalley 	}
22542c3c05dbSStephen Smalley 
22554b02b524SEric Paris 	rc = -ENOMEM;
22562c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
22572c3c05dbSStephen Smalley 	if (!mysids2) {
22582c3c05dbSStephen Smalley 		kfree(mysids);
22592c3c05dbSStephen Smalley 		goto out;
22602c3c05dbSStephen Smalley 	}
22612c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
2262f01e1af4SLinus Torvalds 		struct av_decision dummy_avd;
22632c3c05dbSStephen Smalley 		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2264c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
22652c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
2266f01e1af4SLinus Torvalds 					  &dummy_avd);
22672c3c05dbSStephen Smalley 		if (!rc)
22682c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
22692c3c05dbSStephen Smalley 		cond_resched();
22702c3c05dbSStephen Smalley 	}
22712c3c05dbSStephen Smalley 	rc = 0;
22722c3c05dbSStephen Smalley 	kfree(mysids);
22732c3c05dbSStephen Smalley 	*sids = mysids2;
22742c3c05dbSStephen Smalley 	*nel = j;
22751da177e4SLinus Torvalds out:
22761da177e4SLinus Torvalds 	return rc;
22771da177e4SLinus Torvalds }
22781da177e4SLinus Torvalds 
22791da177e4SLinus Torvalds /**
2280*f31e7994SWaiman Long  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
22811da177e4SLinus Torvalds  * @fstype: filesystem type
22821da177e4SLinus Torvalds  * @path: path from root of mount
22831da177e4SLinus Torvalds  * @sclass: file security class
22841da177e4SLinus Torvalds  * @sid: SID for path
22851da177e4SLinus Torvalds  *
22861da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
22871da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
22881da177e4SLinus Torvalds  * transition SIDs or task SIDs.
2289*f31e7994SWaiman Long  *
2290*f31e7994SWaiman Long  * The caller must acquire the policy_rwlock before calling this function.
22911da177e4SLinus Torvalds  */
2292*f31e7994SWaiman Long static inline int __security_genfs_sid(const char *fstype,
22931da177e4SLinus Torvalds 				       char *path,
2294c6d3aaa4SStephen Smalley 				       u16 orig_sclass,
22951da177e4SLinus Torvalds 				       u32 *sid)
22961da177e4SLinus Torvalds {
22971da177e4SLinus Torvalds 	int len;
2298c6d3aaa4SStephen Smalley 	u16 sclass;
22991da177e4SLinus Torvalds 	struct genfs *genfs;
23001da177e4SLinus Torvalds 	struct ocontext *c;
23014b02b524SEric Paris 	int rc, cmp = 0;
23021da177e4SLinus Torvalds 
2303b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2304b1aa5301SStephen Smalley 		path++;
2305b1aa5301SStephen Smalley 
2306c6d3aaa4SStephen Smalley 	sclass = unmap_class(orig_sclass);
23074b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2308c6d3aaa4SStephen Smalley 
23091da177e4SLinus Torvalds 	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
23101da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
23111da177e4SLinus Torvalds 		if (cmp <= 0)
23121da177e4SLinus Torvalds 			break;
23131da177e4SLinus Torvalds 	}
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds 	rc = -ENOENT;
23164b02b524SEric Paris 	if (!genfs || cmp)
23171da177e4SLinus Torvalds 		goto out;
23181da177e4SLinus Torvalds 
23191da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
23201da177e4SLinus Torvalds 		len = strlen(c->u.name);
23211da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
23221da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
23231da177e4SLinus Torvalds 			break;
23241da177e4SLinus Torvalds 	}
23251da177e4SLinus Torvalds 
23261da177e4SLinus Torvalds 	rc = -ENOENT;
23274b02b524SEric Paris 	if (!c)
23281da177e4SLinus Torvalds 		goto out;
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds 	if (!c->sid[0]) {
23314b02b524SEric Paris 		rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
23321da177e4SLinus Torvalds 		if (rc)
23331da177e4SLinus Torvalds 			goto out;
23341da177e4SLinus Torvalds 	}
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds 	*sid = c->sid[0];
23374b02b524SEric Paris 	rc = 0;
23381da177e4SLinus Torvalds out:
23391da177e4SLinus Torvalds 	return rc;
23401da177e4SLinus Torvalds }
23411da177e4SLinus Torvalds 
23421da177e4SLinus Torvalds /**
2343*f31e7994SWaiman Long  * security_genfs_sid - Obtain a SID for a file in a filesystem
2344*f31e7994SWaiman Long  * @fstype: filesystem type
2345*f31e7994SWaiman Long  * @path: path from root of mount
2346*f31e7994SWaiman Long  * @sclass: file security class
2347*f31e7994SWaiman Long  * @sid: SID for path
2348*f31e7994SWaiman Long  *
2349*f31e7994SWaiman Long  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2350*f31e7994SWaiman Long  * it afterward.
2351*f31e7994SWaiman Long  */
2352*f31e7994SWaiman Long int security_genfs_sid(const char *fstype,
2353*f31e7994SWaiman Long 		       char *path,
2354*f31e7994SWaiman Long 		       u16 orig_sclass,
2355*f31e7994SWaiman Long 		       u32 *sid)
2356*f31e7994SWaiman Long {
2357*f31e7994SWaiman Long 	int retval;
2358*f31e7994SWaiman Long 
2359*f31e7994SWaiman Long 	read_lock(&policy_rwlock);
2360*f31e7994SWaiman Long 	retval = __security_genfs_sid(fstype, path, orig_sclass, sid);
2361*f31e7994SWaiman Long 	read_unlock(&policy_rwlock);
2362*f31e7994SWaiman Long 	return retval;
2363*f31e7994SWaiman Long }
2364*f31e7994SWaiman Long 
2365*f31e7994SWaiman Long /**
23661da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
2367a64c54cfSEric Paris  * @sb: superblock in question
23681da177e4SLinus Torvalds  */
2369a64c54cfSEric Paris int security_fs_use(struct super_block *sb)
23701da177e4SLinus Torvalds {
23711da177e4SLinus Torvalds 	int rc = 0;
23721da177e4SLinus Torvalds 	struct ocontext *c;
2373a64c54cfSEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
2374a64c54cfSEric Paris 	const char *fstype = sb->s_type->name;
23751da177e4SLinus Torvalds 
23760804d113SJames Morris 	read_lock(&policy_rwlock);
23771da177e4SLinus Torvalds 
23784d546f81SPaul Moore 	c = policydb.ocontexts[OCON_FSUSE];
23794d546f81SPaul Moore 	while (c) {
23804d546f81SPaul Moore 		if (strcmp(fstype, c->u.name) == 0)
23811da177e4SLinus Torvalds 			break;
23824d546f81SPaul Moore 		c = c->next;
23831da177e4SLinus Torvalds 	}
23841da177e4SLinus Torvalds 
23851da177e4SLinus Torvalds 	if (c) {
2386a64c54cfSEric Paris 		sbsec->behavior = c->v.behavior;
23871da177e4SLinus Torvalds 		if (!c->sid[0]) {
23884b02b524SEric Paris 			rc = sidtab_context_to_sid(&sidtab, &c->context[0],
23891da177e4SLinus Torvalds 						   &c->sid[0]);
23901da177e4SLinus Torvalds 			if (rc)
23911da177e4SLinus Torvalds 				goto out;
23921da177e4SLinus Torvalds 		}
2393a64c54cfSEric Paris 		sbsec->sid = c->sid[0];
2394089be43eSJames Morris 	} else {
2395*f31e7994SWaiman Long 		rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR,
2396*f31e7994SWaiman Long 					  &sbsec->sid);
23971da177e4SLinus Torvalds 		if (rc) {
2398a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_NONE;
23991da177e4SLinus Torvalds 			rc = 0;
24001da177e4SLinus Torvalds 		} else {
2401a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_GENFS;
24021da177e4SLinus Torvalds 		}
2403089be43eSJames Morris 	}
24041da177e4SLinus Torvalds 
24051da177e4SLinus Torvalds out:
24060804d113SJames Morris 	read_unlock(&policy_rwlock);
24071da177e4SLinus Torvalds 	return rc;
24081da177e4SLinus Torvalds }
24091da177e4SLinus Torvalds 
24101da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values)
24111da177e4SLinus Torvalds {
24124b02b524SEric Paris 	int i, rc;
24131da177e4SLinus Torvalds 
24140804d113SJames Morris 	read_lock(&policy_rwlock);
24151da177e4SLinus Torvalds 	*names = NULL;
24161da177e4SLinus Torvalds 	*values = NULL;
24171da177e4SLinus Torvalds 
24181da177e4SLinus Torvalds 	rc = 0;
24194b02b524SEric Paris 	*len = policydb.p_bools.nprim;
24204b02b524SEric Paris 	if (!*len)
24211da177e4SLinus Torvalds 		goto out;
24221da177e4SLinus Torvalds 
24234b02b524SEric Paris 	rc = -ENOMEM;
2424e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
24251da177e4SLinus Torvalds 	if (!*names)
24261da177e4SLinus Torvalds 		goto err;
24271da177e4SLinus Torvalds 
24284b02b524SEric Paris 	rc = -ENOMEM;
2429e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
24301da177e4SLinus Torvalds 	if (!*values)
24311da177e4SLinus Torvalds 		goto err;
24321da177e4SLinus Torvalds 
24331da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
24341da177e4SLinus Torvalds 		size_t name_len;
24354b02b524SEric Paris 
24361da177e4SLinus Torvalds 		(*values)[i] = policydb.bool_val_to_struct[i]->state;
2437ac76c05bSEric Paris 		name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
24384b02b524SEric Paris 
24394b02b524SEric Paris 		rc = -ENOMEM;
2440e0795cf4SJesper Juhl 		(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
24411da177e4SLinus Torvalds 		if (!(*names)[i])
24421da177e4SLinus Torvalds 			goto err;
24434b02b524SEric Paris 
2444ac76c05bSEric Paris 		strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
24451da177e4SLinus Torvalds 		(*names)[i][name_len - 1] = 0;
24461da177e4SLinus Torvalds 	}
24471da177e4SLinus Torvalds 	rc = 0;
24481da177e4SLinus Torvalds out:
24490804d113SJames Morris 	read_unlock(&policy_rwlock);
24501da177e4SLinus Torvalds 	return rc;
24511da177e4SLinus Torvalds err:
24521da177e4SLinus Torvalds 	if (*names) {
24531da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
24541da177e4SLinus Torvalds 			kfree((*names)[i]);
24551da177e4SLinus Torvalds 	}
24561da177e4SLinus Torvalds 	kfree(*values);
24571da177e4SLinus Torvalds 	goto out;
24581da177e4SLinus Torvalds }
24591da177e4SLinus Torvalds 
24601da177e4SLinus Torvalds 
24611da177e4SLinus Torvalds int security_set_bools(int len, int *values)
24621da177e4SLinus Torvalds {
24634b02b524SEric Paris 	int i, rc;
24641da177e4SLinus Torvalds 	int lenp, seqno = 0;
24651da177e4SLinus Torvalds 	struct cond_node *cur;
24661da177e4SLinus Torvalds 
24670804d113SJames Morris 	write_lock_irq(&policy_rwlock);
24681da177e4SLinus Torvalds 
24691da177e4SLinus Torvalds 	rc = -EFAULT;
24704b02b524SEric Paris 	lenp = policydb.p_bools.nprim;
24714b02b524SEric Paris 	if (len != lenp)
24721da177e4SLinus Torvalds 		goto out;
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
2475af601e46SSteve Grubb 		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
2476af601e46SSteve Grubb 			audit_log(current->audit_context, GFP_ATOMIC,
2477af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
24784746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
2479ac76c05bSEric Paris 				sym_name(&policydb, SYM_BOOLS, i),
2480af601e46SSteve Grubb 				!!values[i],
2481af601e46SSteve Grubb 				policydb.bool_val_to_struct[i]->state,
2482581abc09SEric W. Biederman 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
24834746ec5bSEric Paris 				audit_get_sessionid(current));
2484af601e46SSteve Grubb 		}
24855d55a345SEric Paris 		if (values[i])
24861da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 1;
24875d55a345SEric Paris 		else
24881da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 0;
24891da177e4SLinus Torvalds 	}
24901da177e4SLinus Torvalds 
2491dbc74c65SVesa-Matti Kari 	for (cur = policydb.cond_list; cur; cur = cur->next) {
24921da177e4SLinus Torvalds 		rc = evaluate_cond_node(&policydb, cur);
24931da177e4SLinus Torvalds 		if (rc)
24941da177e4SLinus Torvalds 			goto out;
24951da177e4SLinus Torvalds 	}
24961da177e4SLinus Torvalds 
24971da177e4SLinus Torvalds 	seqno = ++latest_granting;
24984b02b524SEric Paris 	rc = 0;
24991da177e4SLinus Torvalds out:
25000804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
25011da177e4SLinus Torvalds 	if (!rc) {
25021da177e4SLinus Torvalds 		avc_ss_reset(seqno);
25031da177e4SLinus Torvalds 		selnl_notify_policyload(seqno);
250411904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
2505342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
25061da177e4SLinus Torvalds 	}
25071da177e4SLinus Torvalds 	return rc;
25081da177e4SLinus Torvalds }
25091da177e4SLinus Torvalds 
25101da177e4SLinus Torvalds int security_get_bool_value(int bool)
25111da177e4SLinus Torvalds {
25124b02b524SEric Paris 	int rc;
25131da177e4SLinus Torvalds 	int len;
25141da177e4SLinus Torvalds 
25150804d113SJames Morris 	read_lock(&policy_rwlock);
25161da177e4SLinus Torvalds 
25171da177e4SLinus Torvalds 	rc = -EFAULT;
25184b02b524SEric Paris 	len = policydb.p_bools.nprim;
25194b02b524SEric Paris 	if (bool >= len)
25201da177e4SLinus Torvalds 		goto out;
25211da177e4SLinus Torvalds 
25221da177e4SLinus Torvalds 	rc = policydb.bool_val_to_struct[bool]->state;
25231da177e4SLinus Torvalds out:
25240804d113SJames Morris 	read_unlock(&policy_rwlock);
25251da177e4SLinus Torvalds 	return rc;
25261da177e4SLinus Torvalds }
2527376bd9cbSDarrel Goeddel 
2528e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p)
2529e900a7d9SStephen Smalley {
2530e900a7d9SStephen Smalley 	int rc, nbools = 0, *bvalues = NULL, i;
2531e900a7d9SStephen Smalley 	char **bnames = NULL;
2532e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
2533e900a7d9SStephen Smalley 	struct cond_node *cur;
2534e900a7d9SStephen Smalley 
2535e900a7d9SStephen Smalley 	rc = security_get_bools(&nbools, &bnames, &bvalues);
2536e900a7d9SStephen Smalley 	if (rc)
2537e900a7d9SStephen Smalley 		goto out;
2538e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
2539e900a7d9SStephen Smalley 		booldatum = hashtab_search(p->p_bools.table, bnames[i]);
2540e900a7d9SStephen Smalley 		if (booldatum)
2541e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
2542e900a7d9SStephen Smalley 	}
2543dbc74c65SVesa-Matti Kari 	for (cur = p->cond_list; cur; cur = cur->next) {
2544e900a7d9SStephen Smalley 		rc = evaluate_cond_node(p, cur);
2545e900a7d9SStephen Smalley 		if (rc)
2546e900a7d9SStephen Smalley 			goto out;
2547e900a7d9SStephen Smalley 	}
2548e900a7d9SStephen Smalley 
2549e900a7d9SStephen Smalley out:
2550e900a7d9SStephen Smalley 	if (bnames) {
2551e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
2552e900a7d9SStephen Smalley 			kfree(bnames[i]);
2553e900a7d9SStephen Smalley 	}
2554e900a7d9SStephen Smalley 	kfree(bnames);
2555e900a7d9SStephen Smalley 	kfree(bvalues);
2556e900a7d9SStephen Smalley 	return rc;
2557e900a7d9SStephen Smalley }
2558e900a7d9SStephen Smalley 
255908554d6bSVenkat Yekkirala /*
256008554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
256108554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
256208554d6bSVenkat Yekkirala  */
256308554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
256408554d6bSVenkat Yekkirala {
256508554d6bSVenkat Yekkirala 	struct context *context1;
256608554d6bSVenkat Yekkirala 	struct context *context2;
256708554d6bSVenkat Yekkirala 	struct context newcon;
256808554d6bSVenkat Yekkirala 	char *s;
256908554d6bSVenkat Yekkirala 	u32 len;
25704b02b524SEric Paris 	int rc;
257108554d6bSVenkat Yekkirala 
25724b02b524SEric Paris 	rc = 0;
25730719aaf5SGuido Trentalancia 	if (!ss_initialized || !policydb.mls_enabled) {
257408554d6bSVenkat Yekkirala 		*new_sid = sid;
257508554d6bSVenkat Yekkirala 		goto out;
257608554d6bSVenkat Yekkirala 	}
257708554d6bSVenkat Yekkirala 
257808554d6bSVenkat Yekkirala 	context_init(&newcon);
257908554d6bSVenkat Yekkirala 
25800804d113SJames Morris 	read_lock(&policy_rwlock);
25814b02b524SEric Paris 
25824b02b524SEric Paris 	rc = -EINVAL;
258308554d6bSVenkat Yekkirala 	context1 = sidtab_search(&sidtab, sid);
258408554d6bSVenkat Yekkirala 	if (!context1) {
2585744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2586744ba35eSEric Paris 			__func__, sid);
258708554d6bSVenkat Yekkirala 		goto out_unlock;
258808554d6bSVenkat Yekkirala 	}
258908554d6bSVenkat Yekkirala 
25904b02b524SEric Paris 	rc = -EINVAL;
259108554d6bSVenkat Yekkirala 	context2 = sidtab_search(&sidtab, mls_sid);
259208554d6bSVenkat Yekkirala 	if (!context2) {
2593744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2594744ba35eSEric Paris 			__func__, mls_sid);
259508554d6bSVenkat Yekkirala 		goto out_unlock;
259608554d6bSVenkat Yekkirala 	}
259708554d6bSVenkat Yekkirala 
259808554d6bSVenkat Yekkirala 	newcon.user = context1->user;
259908554d6bSVenkat Yekkirala 	newcon.role = context1->role;
260008554d6bSVenkat Yekkirala 	newcon.type = context1->type;
26010efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
260208554d6bSVenkat Yekkirala 	if (rc)
260308554d6bSVenkat Yekkirala 		goto out_unlock;
260408554d6bSVenkat Yekkirala 
260508554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
260608554d6bSVenkat Yekkirala 	if (!policydb_context_isvalid(&policydb, &newcon)) {
260708554d6bSVenkat Yekkirala 		rc = convert_context_handle_invalid_context(&newcon);
26084b02b524SEric Paris 		if (rc) {
260908554d6bSVenkat Yekkirala 			if (!context_struct_to_string(&newcon, &s, &len)) {
261008554d6bSVenkat Yekkirala 				audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
261108554d6bSVenkat Yekkirala 					  "security_sid_mls_copy: invalid context %s", s);
261208554d6bSVenkat Yekkirala 				kfree(s);
261308554d6bSVenkat Yekkirala 			}
26144b02b524SEric Paris 			goto out_unlock;
26154b02b524SEric Paris 		}
26164b02b524SEric Paris 	}
261708554d6bSVenkat Yekkirala 
26184b02b524SEric Paris 	rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
261908554d6bSVenkat Yekkirala out_unlock:
26200804d113SJames Morris 	read_unlock(&policy_rwlock);
262108554d6bSVenkat Yekkirala 	context_destroy(&newcon);
262208554d6bSVenkat Yekkirala out:
262308554d6bSVenkat Yekkirala 	return rc;
262408554d6bSVenkat Yekkirala }
262508554d6bSVenkat Yekkirala 
2626220deb96SPaul Moore /**
2627220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
2628220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
2629220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
2630220deb96SPaul Moore  * @xfrm_sid: XFRM SID
2631220deb96SPaul Moore  *
2632220deb96SPaul Moore  * Description:
2633220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
2634220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
2635220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
2636220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
2637220deb96SPaul Moore  *
2638220deb96SPaul Moore  *                                 | function return |      @sid
2639220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
2640220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
2641220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
2642220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
2643220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
2644220deb96SPaul Moore  *
2645220deb96SPaul Moore  */
2646220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
2647220deb96SPaul Moore 				 u32 xfrm_sid,
2648220deb96SPaul Moore 				 u32 *peer_sid)
2649220deb96SPaul Moore {
2650220deb96SPaul Moore 	int rc;
2651220deb96SPaul Moore 	struct context *nlbl_ctx;
2652220deb96SPaul Moore 	struct context *xfrm_ctx;
2653220deb96SPaul Moore 
26544b02b524SEric Paris 	*peer_sid = SECSID_NULL;
26554b02b524SEric Paris 
2656220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
2657220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
2658220deb96SPaul Moore 	 * single or absent peer SID/label */
2659220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
2660220deb96SPaul Moore 		*peer_sid = nlbl_sid;
2661220deb96SPaul Moore 		return 0;
2662220deb96SPaul Moore 	}
2663220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
2664220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
2665220deb96SPaul Moore 	 * is present */
2666220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
2667220deb96SPaul Moore 		*peer_sid = xfrm_sid;
2668220deb96SPaul Moore 		return 0;
2669220deb96SPaul Moore 	}
2670220deb96SPaul Moore 
2671220deb96SPaul Moore 	/* we don't need to check ss_initialized here since the only way both
2672220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
2673220deb96SPaul Moore 	 * security server was initialized and ss_initialized was true */
26744b02b524SEric Paris 	if (!policydb.mls_enabled)
2675220deb96SPaul Moore 		return 0;
2676220deb96SPaul Moore 
26770804d113SJames Morris 	read_lock(&policy_rwlock);
2678220deb96SPaul Moore 
26794b02b524SEric Paris 	rc = -EINVAL;
2680220deb96SPaul Moore 	nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
2681220deb96SPaul Moore 	if (!nlbl_ctx) {
2682744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2683744ba35eSEric Paris 		       __func__, nlbl_sid);
26844b02b524SEric Paris 		goto out;
2685220deb96SPaul Moore 	}
26864b02b524SEric Paris 	rc = -EINVAL;
2687220deb96SPaul Moore 	xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
2688220deb96SPaul Moore 	if (!xfrm_ctx) {
2689744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2690744ba35eSEric Paris 		       __func__, xfrm_sid);
26914b02b524SEric Paris 		goto out;
2692220deb96SPaul Moore 	}
2693220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
26944b02b524SEric Paris 	if (rc)
26954b02b524SEric Paris 		goto out;
2696220deb96SPaul Moore 
2697220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
2698220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
2699220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
2700220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
2701220deb96SPaul Moore 	 * expressive */
2702220deb96SPaul Moore 	*peer_sid = xfrm_sid;
27034b02b524SEric Paris out:
27044b02b524SEric Paris 	read_unlock(&policy_rwlock);
2705220deb96SPaul Moore 	return rc;
2706220deb96SPaul Moore }
2707220deb96SPaul Moore 
270855fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
270955fcf09bSChristopher J. PeBenito {
271055fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
271155fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
271255fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
271355fcf09bSChristopher J. PeBenito 
271455fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
271555fcf09bSChristopher J. PeBenito 	if (!classes[value])
271655fcf09bSChristopher J. PeBenito 		return -ENOMEM;
271755fcf09bSChristopher J. PeBenito 
271855fcf09bSChristopher J. PeBenito 	return 0;
271955fcf09bSChristopher J. PeBenito }
272055fcf09bSChristopher J. PeBenito 
272155fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses)
272255fcf09bSChristopher J. PeBenito {
27234b02b524SEric Paris 	int rc;
272455fcf09bSChristopher J. PeBenito 
27250804d113SJames Morris 	read_lock(&policy_rwlock);
272655fcf09bSChristopher J. PeBenito 
27274b02b524SEric Paris 	rc = -ENOMEM;
272855fcf09bSChristopher J. PeBenito 	*nclasses = policydb.p_classes.nprim;
27299f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
273055fcf09bSChristopher J. PeBenito 	if (!*classes)
273155fcf09bSChristopher J. PeBenito 		goto out;
273255fcf09bSChristopher J. PeBenito 
273355fcf09bSChristopher J. PeBenito 	rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
273455fcf09bSChristopher J. PeBenito 			*classes);
27354b02b524SEric Paris 	if (rc) {
273655fcf09bSChristopher J. PeBenito 		int i;
273755fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
273855fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
273955fcf09bSChristopher J. PeBenito 		kfree(*classes);
274055fcf09bSChristopher J. PeBenito 	}
274155fcf09bSChristopher J. PeBenito 
274255fcf09bSChristopher J. PeBenito out:
27430804d113SJames Morris 	read_unlock(&policy_rwlock);
274455fcf09bSChristopher J. PeBenito 	return rc;
274555fcf09bSChristopher J. PeBenito }
274655fcf09bSChristopher J. PeBenito 
274755fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
274855fcf09bSChristopher J. PeBenito {
274955fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
275055fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
275155fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
275255fcf09bSChristopher J. PeBenito 
275355fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
275455fcf09bSChristopher J. PeBenito 	if (!perms[value])
275555fcf09bSChristopher J. PeBenito 		return -ENOMEM;
275655fcf09bSChristopher J. PeBenito 
275755fcf09bSChristopher J. PeBenito 	return 0;
275855fcf09bSChristopher J. PeBenito }
275955fcf09bSChristopher J. PeBenito 
276055fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms)
276155fcf09bSChristopher J. PeBenito {
27624b02b524SEric Paris 	int rc, i;
276355fcf09bSChristopher J. PeBenito 	struct class_datum *match;
276455fcf09bSChristopher J. PeBenito 
27650804d113SJames Morris 	read_lock(&policy_rwlock);
276655fcf09bSChristopher J. PeBenito 
27674b02b524SEric Paris 	rc = -EINVAL;
276855fcf09bSChristopher J. PeBenito 	match = hashtab_search(policydb.p_classes.table, class);
276955fcf09bSChristopher J. PeBenito 	if (!match) {
2770744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
2771dd6f953aSHarvey Harrison 			__func__, class);
277255fcf09bSChristopher J. PeBenito 		goto out;
277355fcf09bSChristopher J. PeBenito 	}
277455fcf09bSChristopher J. PeBenito 
27754b02b524SEric Paris 	rc = -ENOMEM;
277655fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
27779f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
277855fcf09bSChristopher J. PeBenito 	if (!*perms)
277955fcf09bSChristopher J. PeBenito 		goto out;
278055fcf09bSChristopher J. PeBenito 
278155fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
278255fcf09bSChristopher J. PeBenito 		rc = hashtab_map(match->comdatum->permissions.table,
278355fcf09bSChristopher J. PeBenito 				get_permissions_callback, *perms);
27844b02b524SEric Paris 		if (rc)
278555fcf09bSChristopher J. PeBenito 			goto err;
278655fcf09bSChristopher J. PeBenito 	}
278755fcf09bSChristopher J. PeBenito 
278855fcf09bSChristopher J. PeBenito 	rc = hashtab_map(match->permissions.table, get_permissions_callback,
278955fcf09bSChristopher J. PeBenito 			*perms);
27904b02b524SEric Paris 	if (rc)
279155fcf09bSChristopher J. PeBenito 		goto err;
279255fcf09bSChristopher J. PeBenito 
279355fcf09bSChristopher J. PeBenito out:
27940804d113SJames Morris 	read_unlock(&policy_rwlock);
279555fcf09bSChristopher J. PeBenito 	return rc;
279655fcf09bSChristopher J. PeBenito 
279755fcf09bSChristopher J. PeBenito err:
27980804d113SJames Morris 	read_unlock(&policy_rwlock);
279955fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
280055fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
280155fcf09bSChristopher J. PeBenito 	kfree(*perms);
280255fcf09bSChristopher J. PeBenito 	return rc;
280355fcf09bSChristopher J. PeBenito }
280455fcf09bSChristopher J. PeBenito 
28053f12070eSEric Paris int security_get_reject_unknown(void)
28063f12070eSEric Paris {
28073f12070eSEric Paris 	return policydb.reject_unknown;
28083f12070eSEric Paris }
28093f12070eSEric Paris 
28103f12070eSEric Paris int security_get_allow_unknown(void)
28113f12070eSEric Paris {
28123f12070eSEric Paris 	return policydb.allow_unknown;
28133f12070eSEric Paris }
28143f12070eSEric Paris 
28153bb56b25SPaul Moore /**
28163bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
28173bb56b25SPaul Moore  * @req_cap: capability
28183bb56b25SPaul Moore  *
28193bb56b25SPaul Moore  * Description:
28203bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
28213bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
28223bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
28233bb56b25SPaul Moore  *
28243bb56b25SPaul Moore  */
28253bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap)
28263bb56b25SPaul Moore {
28273bb56b25SPaul Moore 	int rc;
28283bb56b25SPaul Moore 
28290804d113SJames Morris 	read_lock(&policy_rwlock);
28303bb56b25SPaul Moore 	rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
28310804d113SJames Morris 	read_unlock(&policy_rwlock);
28323bb56b25SPaul Moore 
28333bb56b25SPaul Moore 	return rc;
28343bb56b25SPaul Moore }
28353bb56b25SPaul Moore 
2836376bd9cbSDarrel Goeddel struct selinux_audit_rule {
2837376bd9cbSDarrel Goeddel 	u32 au_seqno;
2838376bd9cbSDarrel Goeddel 	struct context au_ctxt;
2839376bd9cbSDarrel Goeddel };
2840376bd9cbSDarrel Goeddel 
28419d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
2842376bd9cbSDarrel Goeddel {
28439d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
28449d57a7f9SAhmed S. Darwish 
2845376bd9cbSDarrel Goeddel 	if (rule) {
2846376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
2847376bd9cbSDarrel Goeddel 		kfree(rule);
2848376bd9cbSDarrel Goeddel 	}
2849376bd9cbSDarrel Goeddel }
2850376bd9cbSDarrel Goeddel 
28519d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
2852376bd9cbSDarrel Goeddel {
2853376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
2854376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
2855376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
2856376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
28579d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
2858376bd9cbSDarrel Goeddel 	int rc = 0;
2859376bd9cbSDarrel Goeddel 
2860376bd9cbSDarrel Goeddel 	*rule = NULL;
2861376bd9cbSDarrel Goeddel 
2862376bd9cbSDarrel Goeddel 	if (!ss_initialized)
28633ad40d64SSteve G 		return -EOPNOTSUPP;
2864376bd9cbSDarrel Goeddel 
2865376bd9cbSDarrel Goeddel 	switch (field) {
28663a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
28673a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
28683a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
28696e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
28706e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
28716e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
2872376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
28735af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
2874376bd9cbSDarrel Goeddel 			return -EINVAL;
2875376bd9cbSDarrel Goeddel 		break;
28763a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
28773a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
28786e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
28796e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
288025985edcSLucas De Marchi 		/* we do not allow a range, indicated by the presence of '-' */
2881376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
2882376bd9cbSDarrel Goeddel 			return -EINVAL;
2883376bd9cbSDarrel Goeddel 		break;
2884376bd9cbSDarrel Goeddel 	default:
2885376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
2886376bd9cbSDarrel Goeddel 		return -EINVAL;
2887376bd9cbSDarrel Goeddel 	}
2888376bd9cbSDarrel Goeddel 
2889376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
2890376bd9cbSDarrel Goeddel 	if (!tmprule)
2891376bd9cbSDarrel Goeddel 		return -ENOMEM;
2892376bd9cbSDarrel Goeddel 
2893376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
2894376bd9cbSDarrel Goeddel 
28950804d113SJames Morris 	read_lock(&policy_rwlock);
2896376bd9cbSDarrel Goeddel 
2897376bd9cbSDarrel Goeddel 	tmprule->au_seqno = latest_granting;
2898376bd9cbSDarrel Goeddel 
2899376bd9cbSDarrel Goeddel 	switch (field) {
29003a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
29016e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
29024b02b524SEric Paris 		rc = -EINVAL;
2903376bd9cbSDarrel Goeddel 		userdatum = hashtab_search(policydb.p_users.table, rulestr);
2904376bd9cbSDarrel Goeddel 		if (!userdatum)
29054b02b524SEric Paris 			goto out;
2906376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
2907376bd9cbSDarrel Goeddel 		break;
29083a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
29096e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
29104b02b524SEric Paris 		rc = -EINVAL;
2911376bd9cbSDarrel Goeddel 		roledatum = hashtab_search(policydb.p_roles.table, rulestr);
2912376bd9cbSDarrel Goeddel 		if (!roledatum)
29134b02b524SEric Paris 			goto out;
2914376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
2915376bd9cbSDarrel Goeddel 		break;
29163a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
29176e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
29184b02b524SEric Paris 		rc = -EINVAL;
2919376bd9cbSDarrel Goeddel 		typedatum = hashtab_search(policydb.p_types.table, rulestr);
2920376bd9cbSDarrel Goeddel 		if (!typedatum)
29214b02b524SEric Paris 			goto out;
2922376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
2923376bd9cbSDarrel Goeddel 		break;
29243a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
29253a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
29266e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
29276e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
2928376bd9cbSDarrel Goeddel 		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
29294b02b524SEric Paris 		if (rc)
29304b02b524SEric Paris 			goto out;
2931376bd9cbSDarrel Goeddel 		break;
2932376bd9cbSDarrel Goeddel 	}
29334b02b524SEric Paris 	rc = 0;
29344b02b524SEric Paris out:
29350804d113SJames Morris 	read_unlock(&policy_rwlock);
2936376bd9cbSDarrel Goeddel 
2937376bd9cbSDarrel Goeddel 	if (rc) {
2938376bd9cbSDarrel Goeddel 		selinux_audit_rule_free(tmprule);
2939376bd9cbSDarrel Goeddel 		tmprule = NULL;
2940376bd9cbSDarrel Goeddel 	}
2941376bd9cbSDarrel Goeddel 
2942376bd9cbSDarrel Goeddel 	*rule = tmprule;
2943376bd9cbSDarrel Goeddel 
2944376bd9cbSDarrel Goeddel 	return rc;
2945376bd9cbSDarrel Goeddel }
2946376bd9cbSDarrel Goeddel 
29479d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
29489d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
29499d57a7f9SAhmed S. Darwish {
29509d57a7f9SAhmed S. Darwish 	int i;
29519d57a7f9SAhmed S. Darwish 
29529d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
29539d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
29549d57a7f9SAhmed S. Darwish 		switch (f->type) {
29559d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
29569d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
29579d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
29589d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
29599d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
29609d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
29619d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
29629d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
29639d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
29649d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
29659d57a7f9SAhmed S. Darwish 			return 1;
29669d57a7f9SAhmed S. Darwish 		}
29679d57a7f9SAhmed S. Darwish 	}
29689d57a7f9SAhmed S. Darwish 
29699d57a7f9SAhmed S. Darwish 	return 0;
29709d57a7f9SAhmed S. Darwish }
29719d57a7f9SAhmed S. Darwish 
29729d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
2973376bd9cbSDarrel Goeddel 			     struct audit_context *actx)
2974376bd9cbSDarrel Goeddel {
2975376bd9cbSDarrel Goeddel 	struct context *ctxt;
2976376bd9cbSDarrel Goeddel 	struct mls_level *level;
29779d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
2978376bd9cbSDarrel Goeddel 	int match = 0;
2979376bd9cbSDarrel Goeddel 
29809ad42a79SRichard Guy Briggs 	if (unlikely(!rule)) {
29819ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
2982376bd9cbSDarrel Goeddel 		return -ENOENT;
2983376bd9cbSDarrel Goeddel 	}
2984376bd9cbSDarrel Goeddel 
29850804d113SJames Morris 	read_lock(&policy_rwlock);
2986376bd9cbSDarrel Goeddel 
2987376bd9cbSDarrel Goeddel 	if (rule->au_seqno < latest_granting) {
2988376bd9cbSDarrel Goeddel 		match = -ESTALE;
2989376bd9cbSDarrel Goeddel 		goto out;
2990376bd9cbSDarrel Goeddel 	}
2991376bd9cbSDarrel Goeddel 
29929a2f44f0SStephen Smalley 	ctxt = sidtab_search(&sidtab, sid);
29939ad42a79SRichard Guy Briggs 	if (unlikely(!ctxt)) {
29949ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
29959a2f44f0SStephen Smalley 			  sid);
2996376bd9cbSDarrel Goeddel 		match = -ENOENT;
2997376bd9cbSDarrel Goeddel 		goto out;
2998376bd9cbSDarrel Goeddel 	}
2999376bd9cbSDarrel Goeddel 
3000376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
3001376bd9cbSDarrel Goeddel 	   without a match */
3002376bd9cbSDarrel Goeddel 	switch (field) {
30033a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
30046e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3005376bd9cbSDarrel Goeddel 		switch (op) {
30065af75d8dSAl Viro 		case Audit_equal:
3007376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
3008376bd9cbSDarrel Goeddel 			break;
30095af75d8dSAl Viro 		case Audit_not_equal:
3010376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
3011376bd9cbSDarrel Goeddel 			break;
3012376bd9cbSDarrel Goeddel 		}
3013376bd9cbSDarrel Goeddel 		break;
30143a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
30156e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3016376bd9cbSDarrel Goeddel 		switch (op) {
30175af75d8dSAl Viro 		case Audit_equal:
3018376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
3019376bd9cbSDarrel Goeddel 			break;
30205af75d8dSAl Viro 		case Audit_not_equal:
3021376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
3022376bd9cbSDarrel Goeddel 			break;
3023376bd9cbSDarrel Goeddel 		}
3024376bd9cbSDarrel Goeddel 		break;
30253a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
30266e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3027376bd9cbSDarrel Goeddel 		switch (op) {
30285af75d8dSAl Viro 		case Audit_equal:
3029376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
3030376bd9cbSDarrel Goeddel 			break;
30315af75d8dSAl Viro 		case Audit_not_equal:
3032376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
3033376bd9cbSDarrel Goeddel 			break;
3034376bd9cbSDarrel Goeddel 		}
3035376bd9cbSDarrel Goeddel 		break;
30363a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
30373a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
30386e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
30396e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
30406e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
30416e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
3042376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3043376bd9cbSDarrel Goeddel 		switch (op) {
30445af75d8dSAl Viro 		case Audit_equal:
3045376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3046376bd9cbSDarrel Goeddel 					     level);
3047376bd9cbSDarrel Goeddel 			break;
30485af75d8dSAl Viro 		case Audit_not_equal:
3049376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3050376bd9cbSDarrel Goeddel 					      level);
3051376bd9cbSDarrel Goeddel 			break;
30525af75d8dSAl Viro 		case Audit_lt:
3053376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3054376bd9cbSDarrel Goeddel 					       level) &&
3055376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3056376bd9cbSDarrel Goeddel 					       level));
3057376bd9cbSDarrel Goeddel 			break;
30585af75d8dSAl Viro 		case Audit_le:
3059376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3060376bd9cbSDarrel Goeddel 					      level);
3061376bd9cbSDarrel Goeddel 			break;
30625af75d8dSAl Viro 		case Audit_gt:
3063376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
3064376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
3065376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
3066376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
3067376bd9cbSDarrel Goeddel 			break;
30685af75d8dSAl Viro 		case Audit_ge:
3069376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
3070376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
3071376bd9cbSDarrel Goeddel 			break;
3072376bd9cbSDarrel Goeddel 		}
3073376bd9cbSDarrel Goeddel 	}
3074376bd9cbSDarrel Goeddel 
3075376bd9cbSDarrel Goeddel out:
30760804d113SJames Morris 	read_unlock(&policy_rwlock);
3077376bd9cbSDarrel Goeddel 	return match;
3078376bd9cbSDarrel Goeddel }
3079376bd9cbSDarrel Goeddel 
30809d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules;
3081376bd9cbSDarrel Goeddel 
3082562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3083376bd9cbSDarrel Goeddel {
3084376bd9cbSDarrel Goeddel 	int err = 0;
3085376bd9cbSDarrel Goeddel 
3086376bd9cbSDarrel Goeddel 	if (event == AVC_CALLBACK_RESET && aurule_callback)
3087376bd9cbSDarrel Goeddel 		err = aurule_callback();
3088376bd9cbSDarrel Goeddel 	return err;
3089376bd9cbSDarrel Goeddel }
3090376bd9cbSDarrel Goeddel 
3091376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3092376bd9cbSDarrel Goeddel {
3093376bd9cbSDarrel Goeddel 	int err;
3094376bd9cbSDarrel Goeddel 
3095562c99f2SWanlong Gao 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3096376bd9cbSDarrel Goeddel 	if (err)
3097376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
3098376bd9cbSDarrel Goeddel 
3099376bd9cbSDarrel Goeddel 	return err;
3100376bd9cbSDarrel Goeddel }
3101376bd9cbSDarrel Goeddel __initcall(aurule_init);
3102376bd9cbSDarrel Goeddel 
31037420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
31047420ed23SVenkat Yekkirala /**
31055778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
31065778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
31075dbe1eb0SPaul Moore  * @sid: the SELinux SID
31087420ed23SVenkat Yekkirala  *
31097420ed23SVenkat Yekkirala  * Description:
31107420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
31115778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
31125778eabdSPaul Moore  * already been initialized.
31137420ed23SVenkat Yekkirala  *
31147420ed23SVenkat Yekkirala  */
31155778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
31165dbe1eb0SPaul Moore 				      u32 sid)
31177420ed23SVenkat Yekkirala {
31185dbe1eb0SPaul Moore 	u32 *sid_cache;
31197420ed23SVenkat Yekkirala 
31205dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
31215dbe1eb0SPaul Moore 	if (sid_cache == NULL)
31225dbe1eb0SPaul Moore 		return;
31235778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
31245dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
31255dbe1eb0SPaul Moore 		kfree(sid_cache);
31265778eabdSPaul Moore 		return;
31270ec8abd7SJesper Juhl 	}
31287420ed23SVenkat Yekkirala 
31295dbe1eb0SPaul Moore 	*sid_cache = sid;
31305dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
31315dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
31325778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
31337420ed23SVenkat Yekkirala }
31347420ed23SVenkat Yekkirala 
31357420ed23SVenkat Yekkirala /**
31365778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
31377420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
31387420ed23SVenkat Yekkirala  * @sid: the SELinux SID
31397420ed23SVenkat Yekkirala  *
31407420ed23SVenkat Yekkirala  * Description:
31415778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
31427420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
314325985edcSLucas De Marchi  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
31445dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
31455dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
31465dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
31475dbe1eb0SPaul Moore  * failure.
31487420ed23SVenkat Yekkirala  *
31497420ed23SVenkat Yekkirala  */
31505778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
31517420ed23SVenkat Yekkirala 				   u32 *sid)
31527420ed23SVenkat Yekkirala {
31537ae9f23cSEric Paris 	int rc;
31547420ed23SVenkat Yekkirala 	struct context *ctx;
31557420ed23SVenkat Yekkirala 	struct context ctx_new;
31565778eabdSPaul Moore 
31575778eabdSPaul Moore 	if (!ss_initialized) {
31585778eabdSPaul Moore 		*sid = SECSID_NULL;
31595778eabdSPaul Moore 		return 0;
31605778eabdSPaul Moore 	}
31617420ed23SVenkat Yekkirala 
31620804d113SJames Morris 	read_lock(&policy_rwlock);
31637420ed23SVenkat Yekkirala 
31647ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
31655dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
31667ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
316716efd454SPaul Moore 		*sid = secattr->attr.secid;
31687ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
31697ae9f23cSEric Paris 		rc = -EIDRM;
31705dbe1eb0SPaul Moore 		ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
31717420ed23SVenkat Yekkirala 		if (ctx == NULL)
31727ae9f23cSEric Paris 			goto out;
31737420ed23SVenkat Yekkirala 
317481990fbdSPaul Moore 		context_init(&ctx_new);
31757420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
31767420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
31777420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
317802752760SPaul Moore 		mls_import_netlbl_lvl(&ctx_new, secattr);
3179701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
31807ae9f23cSEric Paris 			rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
31817ae9f23cSEric Paris 						   secattr->attr.mls.cat);
31827ae9f23cSEric Paris 			if (rc)
31837ae9f23cSEric Paris 				goto out;
318481990fbdSPaul Moore 			memcpy(&ctx_new.range.level[1].cat,
318581990fbdSPaul Moore 			       &ctx_new.range.level[0].cat,
318681990fbdSPaul Moore 			       sizeof(ctx_new.range.level[0].cat));
31877420ed23SVenkat Yekkirala 		}
31887ae9f23cSEric Paris 		rc = -EIDRM;
31897ae9f23cSEric Paris 		if (!mls_context_isvalid(&policydb, &ctx_new))
31907ae9f23cSEric Paris 			goto out_free;
31917420ed23SVenkat Yekkirala 
31927420ed23SVenkat Yekkirala 		rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
31937ae9f23cSEric Paris 		if (rc)
31947ae9f23cSEric Paris 			goto out_free;
31957420ed23SVenkat Yekkirala 
31965dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
31975778eabdSPaul Moore 
31987420ed23SVenkat Yekkirala 		ebitmap_destroy(&ctx_new.range.level[0].cat);
31997ae9f23cSEric Paris 	} else
3200388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
32017420ed23SVenkat Yekkirala 
32027ae9f23cSEric Paris 	read_unlock(&policy_rwlock);
32037ae9f23cSEric Paris 	return 0;
32047ae9f23cSEric Paris out_free:
32057ae9f23cSEric Paris 	ebitmap_destroy(&ctx_new.range.level[0].cat);
32067ae9f23cSEric Paris out:
32070804d113SJames Morris 	read_unlock(&policy_rwlock);
32087420ed23SVenkat Yekkirala 	return rc;
32097420ed23SVenkat Yekkirala }
32107420ed23SVenkat Yekkirala 
32117420ed23SVenkat Yekkirala /**
32125778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
32135778eabdSPaul Moore  * @sid: the SELinux SID
32145778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
32157420ed23SVenkat Yekkirala  *
32167420ed23SVenkat Yekkirala  * Description:
32175778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
32185778eabdSPaul Moore  * Returns zero on success, negative values on failure.
32197420ed23SVenkat Yekkirala  *
32207420ed23SVenkat Yekkirala  */
32215778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
32227420ed23SVenkat Yekkirala {
322399d854d2SPaul Moore 	int rc;
32247420ed23SVenkat Yekkirala 	struct context *ctx;
32257420ed23SVenkat Yekkirala 
32267420ed23SVenkat Yekkirala 	if (!ss_initialized)
32277420ed23SVenkat Yekkirala 		return 0;
32287420ed23SVenkat Yekkirala 
32290804d113SJames Morris 	read_lock(&policy_rwlock);
32304b02b524SEric Paris 
323199d854d2SPaul Moore 	rc = -ENOENT;
32324b02b524SEric Paris 	ctx = sidtab_search(&sidtab, sid);
32334b02b524SEric Paris 	if (ctx == NULL)
32344b02b524SEric Paris 		goto out;
32354b02b524SEric Paris 
32364b02b524SEric Paris 	rc = -ENOMEM;
3237ac76c05bSEric Paris 	secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
32387420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
32394b02b524SEric Paris 	if (secattr->domain == NULL)
32404b02b524SEric Paris 		goto out;
32414b02b524SEric Paris 
32428d75899dSPaul Moore 	secattr->attr.secid = sid;
32438d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
32445778eabdSPaul Moore 	mls_export_netlbl_lvl(ctx, secattr);
32455778eabdSPaul Moore 	rc = mls_export_netlbl_cat(ctx, secattr);
32464b02b524SEric Paris out:
32470804d113SJames Morris 	read_unlock(&policy_rwlock);
3248f8687afeSPaul Moore 	return rc;
3249f8687afeSPaul Moore }
32507420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3251cee74f47SEric Paris 
3252cee74f47SEric Paris /**
3253cee74f47SEric Paris  * security_read_policy - read the policy.
3254cee74f47SEric Paris  * @data: binary policy data
3255cee74f47SEric Paris  * @len: length of data in bytes
3256cee74f47SEric Paris  *
3257cee74f47SEric Paris  */
32586b697323SEric Paris int security_read_policy(void **data, size_t *len)
3259cee74f47SEric Paris {
3260cee74f47SEric Paris 	int rc;
3261cee74f47SEric Paris 	struct policy_file fp;
3262cee74f47SEric Paris 
3263cee74f47SEric Paris 	if (!ss_initialized)
3264cee74f47SEric Paris 		return -EINVAL;
3265cee74f47SEric Paris 
3266cee74f47SEric Paris 	*len = security_policydb_len();
3267cee74f47SEric Paris 
3268845ca30fSEric Paris 	*data = vmalloc_user(*len);
3269cee74f47SEric Paris 	if (!*data)
3270cee74f47SEric Paris 		return -ENOMEM;
3271cee74f47SEric Paris 
3272cee74f47SEric Paris 	fp.data = *data;
3273cee74f47SEric Paris 	fp.len = *len;
3274cee74f47SEric Paris 
3275cee74f47SEric Paris 	read_lock(&policy_rwlock);
3276cee74f47SEric Paris 	rc = policydb_write(&policydb, &fp);
3277cee74f47SEric Paris 	read_unlock(&policy_rwlock);
3278cee74f47SEric Paris 
3279cee74f47SEric Paris 	if (rc)
3280cee74f47SEric Paris 		return rc;
3281cee74f47SEric Paris 
3282cee74f47SEric Paris 	*len = (unsigned long)fp.data - (unsigned long)*data;
3283cee74f47SEric Paris 	return 0;
3284cee74f47SEric Paris 
3285cee74f47SEric Paris }
3286