xref: /openbmc/linux/security/selinux/ss/services.c (revision 0fd71a62)
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,
98fa1aa143SJeff Vander Stoep 					struct av_decision *avd,
99fa1aa143SJeff Vander Stoep 					struct extended_perms *xperms);
100c6d3aaa4SStephen Smalley 
101c6d3aaa4SStephen Smalley struct selinux_mapping {
102c6d3aaa4SStephen Smalley 	u16 value; /* policy value */
103c6d3aaa4SStephen Smalley 	unsigned num_perms;
104c6d3aaa4SStephen Smalley 	u32 perms[sizeof(u32) * 8];
105c6d3aaa4SStephen Smalley };
106c6d3aaa4SStephen Smalley 
107c6d3aaa4SStephen Smalley static struct selinux_mapping *current_mapping;
108c6d3aaa4SStephen Smalley static u16 current_mapping_size;
109c6d3aaa4SStephen Smalley 
110c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol,
111c6d3aaa4SStephen Smalley 			       struct security_class_mapping *map,
112c6d3aaa4SStephen Smalley 			       struct selinux_mapping **out_map_p,
113c6d3aaa4SStephen Smalley 			       u16 *out_map_size)
114c6d3aaa4SStephen Smalley {
115c6d3aaa4SStephen Smalley 	struct selinux_mapping *out_map = NULL;
116c6d3aaa4SStephen Smalley 	size_t size = sizeof(struct selinux_mapping);
117c6d3aaa4SStephen Smalley 	u16 i, j;
118c6d3aaa4SStephen Smalley 	unsigned k;
119c6d3aaa4SStephen Smalley 	bool print_unknown_handle = false;
120c6d3aaa4SStephen Smalley 
121c6d3aaa4SStephen Smalley 	/* Find number of classes in the input mapping */
122c6d3aaa4SStephen Smalley 	if (!map)
123c6d3aaa4SStephen Smalley 		return -EINVAL;
124c6d3aaa4SStephen Smalley 	i = 0;
125c6d3aaa4SStephen Smalley 	while (map[i].name)
126c6d3aaa4SStephen Smalley 		i++;
127c6d3aaa4SStephen Smalley 
128c6d3aaa4SStephen Smalley 	/* Allocate space for the class records, plus one for class zero */
129c6d3aaa4SStephen Smalley 	out_map = kcalloc(++i, size, GFP_ATOMIC);
130c6d3aaa4SStephen Smalley 	if (!out_map)
131c6d3aaa4SStephen Smalley 		return -ENOMEM;
132c6d3aaa4SStephen Smalley 
133c6d3aaa4SStephen Smalley 	/* Store the raw class and permission values */
134c6d3aaa4SStephen Smalley 	j = 0;
135c6d3aaa4SStephen Smalley 	while (map[j].name) {
136c6d3aaa4SStephen Smalley 		struct security_class_mapping *p_in = map + (j++);
137c6d3aaa4SStephen Smalley 		struct selinux_mapping *p_out = out_map + j;
138c6d3aaa4SStephen Smalley 
139c6d3aaa4SStephen Smalley 		/* An empty class string skips ahead */
140c6d3aaa4SStephen Smalley 		if (!strcmp(p_in->name, "")) {
141c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
142c6d3aaa4SStephen Smalley 			continue;
143c6d3aaa4SStephen Smalley 		}
144c6d3aaa4SStephen Smalley 
145c6d3aaa4SStephen Smalley 		p_out->value = string_to_security_class(pol, p_in->name);
146c6d3aaa4SStephen Smalley 		if (!p_out->value) {
147c6d3aaa4SStephen Smalley 			printk(KERN_INFO
148c6d3aaa4SStephen Smalley 			       "SELinux:  Class %s not defined in policy.\n",
149c6d3aaa4SStephen Smalley 			       p_in->name);
150c6d3aaa4SStephen Smalley 			if (pol->reject_unknown)
151c6d3aaa4SStephen Smalley 				goto err;
152c6d3aaa4SStephen Smalley 			p_out->num_perms = 0;
153c6d3aaa4SStephen Smalley 			print_unknown_handle = true;
154c6d3aaa4SStephen Smalley 			continue;
155c6d3aaa4SStephen Smalley 		}
156c6d3aaa4SStephen Smalley 
157c6d3aaa4SStephen Smalley 		k = 0;
158c6d3aaa4SStephen Smalley 		while (p_in->perms && p_in->perms[k]) {
159c6d3aaa4SStephen Smalley 			/* An empty permission string skips ahead */
160c6d3aaa4SStephen Smalley 			if (!*p_in->perms[k]) {
161c6d3aaa4SStephen Smalley 				k++;
162c6d3aaa4SStephen Smalley 				continue;
163c6d3aaa4SStephen Smalley 			}
164c6d3aaa4SStephen Smalley 			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
165c6d3aaa4SStephen Smalley 							    p_in->perms[k]);
166c6d3aaa4SStephen Smalley 			if (!p_out->perms[k]) {
167c6d3aaa4SStephen Smalley 				printk(KERN_INFO
168c6d3aaa4SStephen Smalley 				       "SELinux:  Permission %s in class %s not defined in policy.\n",
169c6d3aaa4SStephen Smalley 				       p_in->perms[k], p_in->name);
170c6d3aaa4SStephen Smalley 				if (pol->reject_unknown)
171c6d3aaa4SStephen Smalley 					goto err;
172c6d3aaa4SStephen Smalley 				print_unknown_handle = true;
173c6d3aaa4SStephen Smalley 			}
174c6d3aaa4SStephen Smalley 
175c6d3aaa4SStephen Smalley 			k++;
176c6d3aaa4SStephen Smalley 		}
177c6d3aaa4SStephen Smalley 		p_out->num_perms = k;
178c6d3aaa4SStephen Smalley 	}
179c6d3aaa4SStephen Smalley 
180c6d3aaa4SStephen Smalley 	if (print_unknown_handle)
181c6d3aaa4SStephen Smalley 		printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
182c6d3aaa4SStephen Smalley 		       pol->allow_unknown ? "allowed" : "denied");
183c6d3aaa4SStephen Smalley 
184c6d3aaa4SStephen Smalley 	*out_map_p = out_map;
185c6d3aaa4SStephen Smalley 	*out_map_size = i;
186c6d3aaa4SStephen Smalley 	return 0;
187c6d3aaa4SStephen Smalley err:
188c6d3aaa4SStephen Smalley 	kfree(out_map);
189c6d3aaa4SStephen Smalley 	return -EINVAL;
190c6d3aaa4SStephen Smalley }
191c6d3aaa4SStephen Smalley 
192c6d3aaa4SStephen Smalley /*
193c6d3aaa4SStephen Smalley  * Get real, policy values from mapped values
194c6d3aaa4SStephen Smalley  */
195c6d3aaa4SStephen Smalley 
196c6d3aaa4SStephen Smalley static u16 unmap_class(u16 tclass)
197c6d3aaa4SStephen Smalley {
198c6d3aaa4SStephen Smalley 	if (tclass < current_mapping_size)
199c6d3aaa4SStephen Smalley 		return current_mapping[tclass].value;
200c6d3aaa4SStephen Smalley 
201c6d3aaa4SStephen Smalley 	return tclass;
202c6d3aaa4SStephen Smalley }
203c6d3aaa4SStephen Smalley 
2046f5317e7SHarry Ciao /*
2056f5317e7SHarry Ciao  * Get kernel value for class from its policy value
2066f5317e7SHarry Ciao  */
2076f5317e7SHarry Ciao static u16 map_class(u16 pol_value)
2086f5317e7SHarry Ciao {
2096f5317e7SHarry Ciao 	u16 i;
2106f5317e7SHarry Ciao 
2116f5317e7SHarry Ciao 	for (i = 1; i < current_mapping_size; i++) {
2126f5317e7SHarry Ciao 		if (current_mapping[i].value == pol_value)
2136f5317e7SHarry Ciao 			return i;
2146f5317e7SHarry Ciao 	}
2156f5317e7SHarry Ciao 
21685cd6da5SStephen Smalley 	return SECCLASS_NULL;
2176f5317e7SHarry Ciao }
2186f5317e7SHarry Ciao 
219c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd,
220c6d3aaa4SStephen Smalley 			 int allow_unknown)
221c6d3aaa4SStephen Smalley {
222c6d3aaa4SStephen Smalley 	if (tclass < current_mapping_size) {
223c6d3aaa4SStephen Smalley 		unsigned i, n = current_mapping[tclass].num_perms;
224c6d3aaa4SStephen Smalley 		u32 result;
225c6d3aaa4SStephen Smalley 
226c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
227c6d3aaa4SStephen Smalley 			if (avd->allowed & current_mapping[tclass].perms[i])
228c6d3aaa4SStephen Smalley 				result |= 1<<i;
229c6d3aaa4SStephen Smalley 			if (allow_unknown && !current_mapping[tclass].perms[i])
230c6d3aaa4SStephen Smalley 				result |= 1<<i;
231c6d3aaa4SStephen Smalley 		}
232c6d3aaa4SStephen Smalley 		avd->allowed = result;
233c6d3aaa4SStephen Smalley 
234c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++)
235c6d3aaa4SStephen Smalley 			if (avd->auditallow & current_mapping[tclass].perms[i])
236c6d3aaa4SStephen Smalley 				result |= 1<<i;
237c6d3aaa4SStephen Smalley 		avd->auditallow = result;
238c6d3aaa4SStephen Smalley 
239c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
240c6d3aaa4SStephen Smalley 			if (avd->auditdeny & current_mapping[tclass].perms[i])
241c6d3aaa4SStephen Smalley 				result |= 1<<i;
242c6d3aaa4SStephen Smalley 			if (!allow_unknown && !current_mapping[tclass].perms[i])
243c6d3aaa4SStephen Smalley 				result |= 1<<i;
244c6d3aaa4SStephen Smalley 		}
2450bce9527SEric Paris 		/*
2460bce9527SEric Paris 		 * In case the kernel has a bug and requests a permission
2470bce9527SEric Paris 		 * between num_perms and the maximum permission number, we
2480bce9527SEric Paris 		 * should audit that denial
2490bce9527SEric Paris 		 */
2500bce9527SEric Paris 		for (; i < (sizeof(u32)*8); i++)
2510bce9527SEric Paris 			result |= 1<<i;
252c6d3aaa4SStephen Smalley 		avd->auditdeny = result;
253c6d3aaa4SStephen Smalley 	}
254c6d3aaa4SStephen Smalley }
255c6d3aaa4SStephen Smalley 
2560719aaf5SGuido Trentalancia int security_mls_enabled(void)
2570719aaf5SGuido Trentalancia {
2580719aaf5SGuido Trentalancia 	return policydb.mls_enabled;
2590719aaf5SGuido Trentalancia }
260c6d3aaa4SStephen Smalley 
2611da177e4SLinus Torvalds /*
2621da177e4SLinus Torvalds  * Return the boolean value of a constraint expression
2631da177e4SLinus Torvalds  * when it is applied to the specified source and target
2641da177e4SLinus Torvalds  * security contexts.
2651da177e4SLinus Torvalds  *
2661da177e4SLinus Torvalds  * xcontext is a special beast...  It is used by the validatetrans rules
2671da177e4SLinus Torvalds  * only.  For these rules, scontext is the context before the transition,
2681da177e4SLinus Torvalds  * tcontext is the context after the transition, and xcontext is the context
2691da177e4SLinus Torvalds  * of the process performing the transition.  All other callers of
2701da177e4SLinus Torvalds  * constraint_expr_eval should pass in NULL for xcontext.
2711da177e4SLinus Torvalds  */
2721da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext,
2731da177e4SLinus Torvalds 				struct context *tcontext,
2741da177e4SLinus Torvalds 				struct context *xcontext,
2751da177e4SLinus Torvalds 				struct constraint_expr *cexpr)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	u32 val1, val2;
2781da177e4SLinus Torvalds 	struct context *c;
2791da177e4SLinus Torvalds 	struct role_datum *r1, *r2;
2801da177e4SLinus Torvalds 	struct mls_level *l1, *l2;
2811da177e4SLinus Torvalds 	struct constraint_expr *e;
2821da177e4SLinus Torvalds 	int s[CEXPR_MAXDEPTH];
2831da177e4SLinus Torvalds 	int sp = -1;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	for (e = cexpr; e; e = e->next) {
2861da177e4SLinus Torvalds 		switch (e->expr_type) {
2871da177e4SLinus Torvalds 		case CEXPR_NOT:
2881da177e4SLinus Torvalds 			BUG_ON(sp < 0);
2891da177e4SLinus Torvalds 			s[sp] = !s[sp];
2901da177e4SLinus Torvalds 			break;
2911da177e4SLinus Torvalds 		case CEXPR_AND:
2921da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2931da177e4SLinus Torvalds 			sp--;
2941da177e4SLinus Torvalds 			s[sp] &= s[sp + 1];
2951da177e4SLinus Torvalds 			break;
2961da177e4SLinus Torvalds 		case CEXPR_OR:
2971da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2981da177e4SLinus Torvalds 			sp--;
2991da177e4SLinus Torvalds 			s[sp] |= s[sp + 1];
3001da177e4SLinus Torvalds 			break;
3011da177e4SLinus Torvalds 		case CEXPR_ATTR:
3021da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH - 1))
3031da177e4SLinus Torvalds 				return 0;
3041da177e4SLinus Torvalds 			switch (e->attr) {
3051da177e4SLinus Torvalds 			case CEXPR_USER:
3061da177e4SLinus Torvalds 				val1 = scontext->user;
3071da177e4SLinus Torvalds 				val2 = tcontext->user;
3081da177e4SLinus Torvalds 				break;
3091da177e4SLinus Torvalds 			case CEXPR_TYPE:
3101da177e4SLinus Torvalds 				val1 = scontext->type;
3111da177e4SLinus Torvalds 				val2 = tcontext->type;
3121da177e4SLinus Torvalds 				break;
3131da177e4SLinus Torvalds 			case CEXPR_ROLE:
3141da177e4SLinus Torvalds 				val1 = scontext->role;
3151da177e4SLinus Torvalds 				val2 = tcontext->role;
3161da177e4SLinus Torvalds 				r1 = policydb.role_val_to_struct[val1 - 1];
3171da177e4SLinus Torvalds 				r2 = policydb.role_val_to_struct[val2 - 1];
3181da177e4SLinus Torvalds 				switch (e->op) {
3191da177e4SLinus Torvalds 				case CEXPR_DOM:
3201da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r1->dominates,
3211da177e4SLinus Torvalds 								  val2 - 1);
3221da177e4SLinus Torvalds 					continue;
3231da177e4SLinus Torvalds 				case CEXPR_DOMBY:
3241da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r2->dominates,
3251da177e4SLinus Torvalds 								  val1 - 1);
3261da177e4SLinus Torvalds 					continue;
3271da177e4SLinus Torvalds 				case CEXPR_INCOMP:
3281da177e4SLinus Torvalds 					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
3291da177e4SLinus Torvalds 								    val2 - 1) &&
3301da177e4SLinus Torvalds 						   !ebitmap_get_bit(&r2->dominates,
3311da177e4SLinus Torvalds 								    val1 - 1));
3321da177e4SLinus Torvalds 					continue;
3331da177e4SLinus Torvalds 				default:
3341da177e4SLinus Torvalds 					break;
3351da177e4SLinus Torvalds 				}
3361da177e4SLinus Torvalds 				break;
3371da177e4SLinus Torvalds 			case CEXPR_L1L2:
3381da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3391da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3401da177e4SLinus Torvalds 				goto mls_ops;
3411da177e4SLinus Torvalds 			case CEXPR_L1H2:
3421da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3431da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3441da177e4SLinus Torvalds 				goto mls_ops;
3451da177e4SLinus Torvalds 			case CEXPR_H1L2:
3461da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3471da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3481da177e4SLinus Torvalds 				goto mls_ops;
3491da177e4SLinus Torvalds 			case CEXPR_H1H2:
3501da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3511da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3521da177e4SLinus Torvalds 				goto mls_ops;
3531da177e4SLinus Torvalds 			case CEXPR_L1H1:
3541da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3551da177e4SLinus Torvalds 				l2 = &(scontext->range.level[1]);
3561da177e4SLinus Torvalds 				goto mls_ops;
3571da177e4SLinus Torvalds 			case CEXPR_L2H2:
3581da177e4SLinus Torvalds 				l1 = &(tcontext->range.level[0]);
3591da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3601da177e4SLinus Torvalds 				goto mls_ops;
3611da177e4SLinus Torvalds mls_ops:
3621da177e4SLinus Torvalds 			switch (e->op) {
3631da177e4SLinus Torvalds 			case CEXPR_EQ:
3641da177e4SLinus Torvalds 				s[++sp] = mls_level_eq(l1, l2);
3651da177e4SLinus Torvalds 				continue;
3661da177e4SLinus Torvalds 			case CEXPR_NEQ:
3671da177e4SLinus Torvalds 				s[++sp] = !mls_level_eq(l1, l2);
3681da177e4SLinus Torvalds 				continue;
3691da177e4SLinus Torvalds 			case CEXPR_DOM:
3701da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l1, l2);
3711da177e4SLinus Torvalds 				continue;
3721da177e4SLinus Torvalds 			case CEXPR_DOMBY:
3731da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l2, l1);
3741da177e4SLinus Torvalds 				continue;
3751da177e4SLinus Torvalds 			case CEXPR_INCOMP:
3761da177e4SLinus Torvalds 				s[++sp] = mls_level_incomp(l2, l1);
3771da177e4SLinus Torvalds 				continue;
3781da177e4SLinus Torvalds 			default:
3791da177e4SLinus Torvalds 				BUG();
3801da177e4SLinus Torvalds 				return 0;
3811da177e4SLinus Torvalds 			}
3821da177e4SLinus Torvalds 			break;
3831da177e4SLinus Torvalds 			default:
3841da177e4SLinus Torvalds 				BUG();
3851da177e4SLinus Torvalds 				return 0;
3861da177e4SLinus Torvalds 			}
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 			switch (e->op) {
3891da177e4SLinus Torvalds 			case CEXPR_EQ:
3901da177e4SLinus Torvalds 				s[++sp] = (val1 == val2);
3911da177e4SLinus Torvalds 				break;
3921da177e4SLinus Torvalds 			case CEXPR_NEQ:
3931da177e4SLinus Torvalds 				s[++sp] = (val1 != val2);
3941da177e4SLinus Torvalds 				break;
3951da177e4SLinus Torvalds 			default:
3961da177e4SLinus Torvalds 				BUG();
3971da177e4SLinus Torvalds 				return 0;
3981da177e4SLinus Torvalds 			}
3991da177e4SLinus Torvalds 			break;
4001da177e4SLinus Torvalds 		case CEXPR_NAMES:
4011da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH-1))
4021da177e4SLinus Torvalds 				return 0;
4031da177e4SLinus Torvalds 			c = scontext;
4041da177e4SLinus Torvalds 			if (e->attr & CEXPR_TARGET)
4051da177e4SLinus Torvalds 				c = tcontext;
4061da177e4SLinus Torvalds 			else if (e->attr & CEXPR_XTARGET) {
4071da177e4SLinus Torvalds 				c = xcontext;
4081da177e4SLinus Torvalds 				if (!c) {
4091da177e4SLinus Torvalds 					BUG();
4101da177e4SLinus Torvalds 					return 0;
4111da177e4SLinus Torvalds 				}
4121da177e4SLinus Torvalds 			}
4131da177e4SLinus Torvalds 			if (e->attr & CEXPR_USER)
4141da177e4SLinus Torvalds 				val1 = c->user;
4151da177e4SLinus Torvalds 			else if (e->attr & CEXPR_ROLE)
4161da177e4SLinus Torvalds 				val1 = c->role;
4171da177e4SLinus Torvalds 			else if (e->attr & CEXPR_TYPE)
4181da177e4SLinus Torvalds 				val1 = c->type;
4191da177e4SLinus Torvalds 			else {
4201da177e4SLinus Torvalds 				BUG();
4211da177e4SLinus Torvalds 				return 0;
4221da177e4SLinus Torvalds 			}
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 			switch (e->op) {
4251da177e4SLinus Torvalds 			case CEXPR_EQ:
4261da177e4SLinus Torvalds 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
4271da177e4SLinus Torvalds 				break;
4281da177e4SLinus Torvalds 			case CEXPR_NEQ:
4291da177e4SLinus Torvalds 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
4301da177e4SLinus Torvalds 				break;
4311da177e4SLinus Torvalds 			default:
4321da177e4SLinus Torvalds 				BUG();
4331da177e4SLinus Torvalds 				return 0;
4341da177e4SLinus Torvalds 			}
4351da177e4SLinus Torvalds 			break;
4361da177e4SLinus Torvalds 		default:
4371da177e4SLinus Torvalds 			BUG();
4381da177e4SLinus Torvalds 			return 0;
4391da177e4SLinus Torvalds 		}
4401da177e4SLinus Torvalds 	}
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	BUG_ON(sp != 0);
4431da177e4SLinus Torvalds 	return s[0];
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds /*
44744c2d9bdSKaiGai Kohei  * security_dump_masked_av - dumps masked permissions during
44844c2d9bdSKaiGai Kohei  * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
44944c2d9bdSKaiGai Kohei  */
45044c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args)
45144c2d9bdSKaiGai Kohei {
45244c2d9bdSKaiGai Kohei 	struct perm_datum *pdatum = d;
45344c2d9bdSKaiGai Kohei 	char **permission_names = args;
45444c2d9bdSKaiGai Kohei 
45544c2d9bdSKaiGai Kohei 	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
45644c2d9bdSKaiGai Kohei 
45744c2d9bdSKaiGai Kohei 	permission_names[pdatum->value - 1] = (char *)k;
45844c2d9bdSKaiGai Kohei 
45944c2d9bdSKaiGai Kohei 	return 0;
46044c2d9bdSKaiGai Kohei }
46144c2d9bdSKaiGai Kohei 
46244c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext,
46344c2d9bdSKaiGai Kohei 				    struct context *tcontext,
46444c2d9bdSKaiGai Kohei 				    u16 tclass,
46544c2d9bdSKaiGai Kohei 				    u32 permissions,
46644c2d9bdSKaiGai Kohei 				    const char *reason)
46744c2d9bdSKaiGai Kohei {
46844c2d9bdSKaiGai Kohei 	struct common_datum *common_dat;
46944c2d9bdSKaiGai Kohei 	struct class_datum *tclass_dat;
47044c2d9bdSKaiGai Kohei 	struct audit_buffer *ab;
47144c2d9bdSKaiGai Kohei 	char *tclass_name;
47244c2d9bdSKaiGai Kohei 	char *scontext_name = NULL;
47344c2d9bdSKaiGai Kohei 	char *tcontext_name = NULL;
47444c2d9bdSKaiGai Kohei 	char *permission_names[32];
4752da5d31bSJames Morris 	int index;
4762da5d31bSJames Morris 	u32 length;
47744c2d9bdSKaiGai Kohei 	bool need_comma = false;
47844c2d9bdSKaiGai Kohei 
47944c2d9bdSKaiGai Kohei 	if (!permissions)
48044c2d9bdSKaiGai Kohei 		return;
48144c2d9bdSKaiGai Kohei 
482ac76c05bSEric Paris 	tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
48344c2d9bdSKaiGai Kohei 	tclass_dat = policydb.class_val_to_struct[tclass - 1];
48444c2d9bdSKaiGai Kohei 	common_dat = tclass_dat->comdatum;
48544c2d9bdSKaiGai Kohei 
48644c2d9bdSKaiGai Kohei 	/* init permission_names */
48744c2d9bdSKaiGai Kohei 	if (common_dat &&
48844c2d9bdSKaiGai Kohei 	    hashtab_map(common_dat->permissions.table,
48944c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
49044c2d9bdSKaiGai Kohei 		goto out;
49144c2d9bdSKaiGai Kohei 
49244c2d9bdSKaiGai Kohei 	if (hashtab_map(tclass_dat->permissions.table,
49344c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
49444c2d9bdSKaiGai Kohei 		goto out;
49544c2d9bdSKaiGai Kohei 
49644c2d9bdSKaiGai Kohei 	/* get scontext/tcontext in text form */
49744c2d9bdSKaiGai Kohei 	if (context_struct_to_string(scontext,
49844c2d9bdSKaiGai Kohei 				     &scontext_name, &length) < 0)
49944c2d9bdSKaiGai Kohei 		goto out;
50044c2d9bdSKaiGai Kohei 
50144c2d9bdSKaiGai Kohei 	if (context_struct_to_string(tcontext,
50244c2d9bdSKaiGai Kohei 				     &tcontext_name, &length) < 0)
50344c2d9bdSKaiGai Kohei 		goto out;
50444c2d9bdSKaiGai Kohei 
50544c2d9bdSKaiGai Kohei 	/* audit a message */
50644c2d9bdSKaiGai Kohei 	ab = audit_log_start(current->audit_context,
50744c2d9bdSKaiGai Kohei 			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
50844c2d9bdSKaiGai Kohei 	if (!ab)
50944c2d9bdSKaiGai Kohei 		goto out;
51044c2d9bdSKaiGai Kohei 
51144c2d9bdSKaiGai Kohei 	audit_log_format(ab, "op=security_compute_av reason=%s "
51244c2d9bdSKaiGai Kohei 			 "scontext=%s tcontext=%s tclass=%s perms=",
51344c2d9bdSKaiGai Kohei 			 reason, scontext_name, tcontext_name, tclass_name);
51444c2d9bdSKaiGai Kohei 
51544c2d9bdSKaiGai Kohei 	for (index = 0; index < 32; index++) {
51644c2d9bdSKaiGai Kohei 		u32 mask = (1 << index);
51744c2d9bdSKaiGai Kohei 
51844c2d9bdSKaiGai Kohei 		if ((mask & permissions) == 0)
51944c2d9bdSKaiGai Kohei 			continue;
52044c2d9bdSKaiGai Kohei 
52144c2d9bdSKaiGai Kohei 		audit_log_format(ab, "%s%s",
52244c2d9bdSKaiGai Kohei 				 need_comma ? "," : "",
52344c2d9bdSKaiGai Kohei 				 permission_names[index]
52444c2d9bdSKaiGai Kohei 				 ? permission_names[index] : "????");
52544c2d9bdSKaiGai Kohei 		need_comma = true;
52644c2d9bdSKaiGai Kohei 	}
52744c2d9bdSKaiGai Kohei 	audit_log_end(ab);
52844c2d9bdSKaiGai Kohei out:
52944c2d9bdSKaiGai Kohei 	/* release scontext/tcontext */
53044c2d9bdSKaiGai Kohei 	kfree(tcontext_name);
53144c2d9bdSKaiGai Kohei 	kfree(scontext_name);
53244c2d9bdSKaiGai Kohei 
53344c2d9bdSKaiGai Kohei 	return;
53444c2d9bdSKaiGai Kohei }
53544c2d9bdSKaiGai Kohei 
53644c2d9bdSKaiGai Kohei /*
537d9250deaSKaiGai Kohei  * security_boundary_permission - drops violated permissions
538d9250deaSKaiGai Kohei  * on boundary constraint.
539d9250deaSKaiGai Kohei  */
540d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext,
541d9250deaSKaiGai Kohei 				     struct context *tcontext,
542d9250deaSKaiGai Kohei 				     u16 tclass,
543d9250deaSKaiGai Kohei 				     struct av_decision *avd)
544d9250deaSKaiGai Kohei {
5452ae3ba39SKaiGai Kohei 	struct context lo_scontext;
5462ae3ba39SKaiGai Kohei 	struct context lo_tcontext;
5472ae3ba39SKaiGai Kohei 	struct av_decision lo_avd;
54823bdecb0SEric Paris 	struct type_datum *source;
54923bdecb0SEric Paris 	struct type_datum *target;
5502ae3ba39SKaiGai Kohei 	u32 masked = 0;
551d9250deaSKaiGai Kohei 
55223bdecb0SEric Paris 	source = flex_array_get_ptr(policydb.type_val_to_struct_array,
55323bdecb0SEric Paris 				    scontext->type - 1);
55423bdecb0SEric Paris 	BUG_ON(!source);
55523bdecb0SEric Paris 
55623bdecb0SEric Paris 	target = flex_array_get_ptr(policydb.type_val_to_struct_array,
55723bdecb0SEric Paris 				    tcontext->type - 1);
55823bdecb0SEric Paris 	BUG_ON(!target);
55923bdecb0SEric Paris 
560d9250deaSKaiGai Kohei 	if (source->bounds) {
561d9250deaSKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
562d9250deaSKaiGai Kohei 
563d9250deaSKaiGai Kohei 		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
564d9250deaSKaiGai Kohei 		lo_scontext.type = source->bounds;
565d9250deaSKaiGai Kohei 
566d9250deaSKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
567d9250deaSKaiGai Kohei 					  tcontext,
568d9250deaSKaiGai Kohei 					  tclass,
569fa1aa143SJeff Vander Stoep 					  &lo_avd,
570fa1aa143SJeff Vander Stoep 					  NULL);
571d9250deaSKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
572d9250deaSKaiGai Kohei 			return;		/* no masked permission */
573d9250deaSKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5742ae3ba39SKaiGai Kohei 	}
575d9250deaSKaiGai Kohei 
5762ae3ba39SKaiGai Kohei 	if (target->bounds) {
5772ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5782ae3ba39SKaiGai Kohei 
5792ae3ba39SKaiGai Kohei 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5802ae3ba39SKaiGai Kohei 		lo_tcontext.type = target->bounds;
5812ae3ba39SKaiGai Kohei 
5822ae3ba39SKaiGai Kohei 		context_struct_compute_av(scontext,
5832ae3ba39SKaiGai Kohei 					  &lo_tcontext,
5842ae3ba39SKaiGai Kohei 					  tclass,
585fa1aa143SJeff Vander Stoep 					  &lo_avd,
586fa1aa143SJeff Vander Stoep 					  NULL);
5872ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
5882ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
5892ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5902ae3ba39SKaiGai Kohei 	}
5912ae3ba39SKaiGai Kohei 
5922ae3ba39SKaiGai Kohei 	if (source->bounds && target->bounds) {
5932ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5942ae3ba39SKaiGai Kohei 		/*
5952ae3ba39SKaiGai Kohei 		 * lo_scontext and lo_tcontext are already
5962ae3ba39SKaiGai Kohei 		 * set up.
5972ae3ba39SKaiGai Kohei 		 */
5982ae3ba39SKaiGai Kohei 
5992ae3ba39SKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
6002ae3ba39SKaiGai Kohei 					  &lo_tcontext,
6012ae3ba39SKaiGai Kohei 					  tclass,
602fa1aa143SJeff Vander Stoep 					  &lo_avd,
603fa1aa143SJeff Vander Stoep 					  NULL);
6042ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
6052ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
6062ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
6072ae3ba39SKaiGai Kohei 	}
6082ae3ba39SKaiGai Kohei 
6092ae3ba39SKaiGai Kohei 	if (masked) {
610d9250deaSKaiGai Kohei 		/* mask violated permissions */
611d9250deaSKaiGai Kohei 		avd->allowed &= ~masked;
612d9250deaSKaiGai Kohei 
61344c2d9bdSKaiGai Kohei 		/* audit masked permissions */
61444c2d9bdSKaiGai Kohei 		security_dump_masked_av(scontext, tcontext,
61544c2d9bdSKaiGai Kohei 					tclass, masked, "bounds");
616d9250deaSKaiGai Kohei 	}
617d9250deaSKaiGai Kohei }
618d9250deaSKaiGai Kohei 
619d9250deaSKaiGai Kohei /*
620fa1aa143SJeff Vander Stoep  * flag which drivers have permissions
621fa1aa143SJeff Vander Stoep  * only looking for ioctl based extended permssions
622fa1aa143SJeff Vander Stoep  */
623fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers(
624fa1aa143SJeff Vander Stoep 		struct extended_perms *xperms,
625fa1aa143SJeff Vander Stoep 		struct avtab_node *node)
626fa1aa143SJeff Vander Stoep {
627fa1aa143SJeff Vander Stoep 	unsigned int i;
628fa1aa143SJeff Vander Stoep 
629fa1aa143SJeff Vander Stoep 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
630fa1aa143SJeff Vander Stoep 		/* if one or more driver has all permissions allowed */
631fa1aa143SJeff Vander Stoep 		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
632fa1aa143SJeff Vander Stoep 			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
633fa1aa143SJeff Vander Stoep 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
634fa1aa143SJeff Vander Stoep 		/* if allowing permissions within a driver */
635fa1aa143SJeff Vander Stoep 		security_xperm_set(xperms->drivers.p,
636fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->driver);
637fa1aa143SJeff Vander Stoep 	}
638fa1aa143SJeff Vander Stoep 
639fa1aa143SJeff Vander Stoep 	/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
640fa1aa143SJeff Vander Stoep 	if (node->key.specified & AVTAB_XPERMS_ALLOWED)
641fa1aa143SJeff Vander Stoep 		xperms->len = 1;
642fa1aa143SJeff Vander Stoep }
643fa1aa143SJeff Vander Stoep 
644fa1aa143SJeff Vander Stoep /*
645fa1aa143SJeff Vander Stoep  * Compute access vectors and extended permissions based on a context
646fa1aa143SJeff Vander Stoep  * structure pair for the permissions in a particular class.
6471da177e4SLinus Torvalds  */
64819439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext,
6491da177e4SLinus Torvalds 					struct context *tcontext,
6501da177e4SLinus Torvalds 					u16 tclass,
651fa1aa143SJeff Vander Stoep 					struct av_decision *avd,
652fa1aa143SJeff Vander Stoep 					struct extended_perms *xperms)
6531da177e4SLinus Torvalds {
6541da177e4SLinus Torvalds 	struct constraint_node *constraint;
6551da177e4SLinus Torvalds 	struct role_allow *ra;
6561da177e4SLinus Torvalds 	struct avtab_key avkey;
657782ebb99SStephen Smalley 	struct avtab_node *node;
6581da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
659782ebb99SStephen Smalley 	struct ebitmap *sattr, *tattr;
660782ebb99SStephen Smalley 	struct ebitmap_node *snode, *tnode;
661782ebb99SStephen Smalley 	unsigned int i, j;
6621da177e4SLinus Torvalds 
6631da177e4SLinus Torvalds 	avd->allowed = 0;
6641da177e4SLinus Torvalds 	avd->auditallow = 0;
6651da177e4SLinus Torvalds 	avd->auditdeny = 0xffffffff;
666fa1aa143SJeff Vander Stoep 	if (xperms) {
667fa1aa143SJeff Vander Stoep 		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
668fa1aa143SJeff Vander Stoep 		xperms->len = 0;
669fa1aa143SJeff Vander Stoep 	}
6701da177e4SLinus Torvalds 
671c6d3aaa4SStephen Smalley 	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
672c6d3aaa4SStephen Smalley 		if (printk_ratelimit())
673c6d3aaa4SStephen Smalley 			printk(KERN_WARNING "SELinux:  Invalid class %hu\n", tclass);
67419439d05SStephen Smalley 		return;
675c6d3aaa4SStephen Smalley 	}
6763f12070eSEric Paris 
6773f12070eSEric Paris 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
6783f12070eSEric Paris 
6793f12070eSEric Paris 	/*
6801da177e4SLinus Torvalds 	 * If a specific type enforcement rule was defined for
6811da177e4SLinus Torvalds 	 * this permission check, then use it.
6821da177e4SLinus Torvalds 	 */
6831da177e4SLinus Torvalds 	avkey.target_class = tclass;
684fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
6856371dcd3SEric Paris 	sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
6866371dcd3SEric Paris 	BUG_ON(!sattr);
6876371dcd3SEric Paris 	tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
6886371dcd3SEric Paris 	BUG_ON(!tattr);
6899fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(sattr, snode, i) {
6909fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
691782ebb99SStephen Smalley 			avkey.source_type = i + 1;
692782ebb99SStephen Smalley 			avkey.target_type = j + 1;
693782ebb99SStephen Smalley 			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
694dbc74c65SVesa-Matti Kari 			     node;
695782ebb99SStephen Smalley 			     node = avtab_search_node_next(node, avkey.specified)) {
696782ebb99SStephen Smalley 				if (node->key.specified == AVTAB_ALLOWED)
697fa1aa143SJeff Vander Stoep 					avd->allowed |= node->datum.u.data;
698782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITALLOW)
699fa1aa143SJeff Vander Stoep 					avd->auditallow |= node->datum.u.data;
700782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITDENY)
701fa1aa143SJeff Vander Stoep 					avd->auditdeny &= node->datum.u.data;
702fa1aa143SJeff Vander Stoep 				else if (xperms && (node->key.specified & AVTAB_XPERMS))
703fa1aa143SJeff Vander Stoep 					services_compute_xperms_drivers(xperms, node);
7041da177e4SLinus Torvalds 			}
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds 			/* Check conditional av table for additional permissions */
707fa1aa143SJeff Vander Stoep 			cond_compute_av(&policydb.te_cond_avtab, &avkey,
708fa1aa143SJeff Vander Stoep 					avd, xperms);
7091da177e4SLinus Torvalds 
710782ebb99SStephen Smalley 		}
711782ebb99SStephen Smalley 	}
712782ebb99SStephen Smalley 
7131da177e4SLinus Torvalds 	/*
7141da177e4SLinus Torvalds 	 * Remove any permissions prohibited by a constraint (this includes
7151da177e4SLinus Torvalds 	 * the MLS policy).
7161da177e4SLinus Torvalds 	 */
7171da177e4SLinus Torvalds 	constraint = tclass_datum->constraints;
7181da177e4SLinus Torvalds 	while (constraint) {
7191da177e4SLinus Torvalds 		if ((constraint->permissions & (avd->allowed)) &&
7201da177e4SLinus Torvalds 		    !constraint_expr_eval(scontext, tcontext, NULL,
7211da177e4SLinus Torvalds 					  constraint->expr)) {
722caabbdc0SKaiGai Kohei 			avd->allowed &= ~(constraint->permissions);
7231da177e4SLinus Torvalds 		}
7241da177e4SLinus Torvalds 		constraint = constraint->next;
7251da177e4SLinus Torvalds 	}
7261da177e4SLinus Torvalds 
7271da177e4SLinus Torvalds 	/*
7281da177e4SLinus Torvalds 	 * If checking process transition permission and the
7291da177e4SLinus Torvalds 	 * role is changing, then check the (current_role, new_role)
7301da177e4SLinus Torvalds 	 * pair.
7311da177e4SLinus Torvalds 	 */
732c6d3aaa4SStephen Smalley 	if (tclass == policydb.process_class &&
733c6d3aaa4SStephen Smalley 	    (avd->allowed & policydb.process_trans_perms) &&
7341da177e4SLinus Torvalds 	    scontext->role != tcontext->role) {
7351da177e4SLinus Torvalds 		for (ra = policydb.role_allow; ra; ra = ra->next) {
7361da177e4SLinus Torvalds 			if (scontext->role == ra->role &&
7371da177e4SLinus Torvalds 			    tcontext->role == ra->new_role)
7381da177e4SLinus Torvalds 				break;
7391da177e4SLinus Torvalds 		}
7401da177e4SLinus Torvalds 		if (!ra)
741c6d3aaa4SStephen Smalley 			avd->allowed &= ~policydb.process_trans_perms;
7421da177e4SLinus Torvalds 	}
7431da177e4SLinus Torvalds 
744d9250deaSKaiGai Kohei 	/*
745d9250deaSKaiGai Kohei 	 * If the given source and target types have boundary
746d9250deaSKaiGai Kohei 	 * constraint, lazy checks have to mask any violated
747d9250deaSKaiGai Kohei 	 * permission and notice it to userspace via audit.
748d9250deaSKaiGai Kohei 	 */
749d9250deaSKaiGai Kohei 	type_attribute_bounds_av(scontext, tcontext,
75019439d05SStephen Smalley 				 tclass, avd);
75122df4adbSStephen Smalley }
75222df4adbSStephen Smalley 
7531da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext,
7541da177e4SLinus Torvalds 					   struct context *ncontext,
7551da177e4SLinus Torvalds 					   struct context *tcontext,
7561da177e4SLinus Torvalds 					   u16 tclass)
7571da177e4SLinus Torvalds {
7581da177e4SLinus Torvalds 	char *o = NULL, *n = NULL, *t = NULL;
7591da177e4SLinus Torvalds 	u32 olen, nlen, tlen;
7601da177e4SLinus Torvalds 
7614b02b524SEric Paris 	if (context_struct_to_string(ocontext, &o, &olen))
7621da177e4SLinus Torvalds 		goto out;
7634b02b524SEric Paris 	if (context_struct_to_string(ncontext, &n, &nlen))
7641da177e4SLinus Torvalds 		goto out;
7654b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
7661da177e4SLinus Torvalds 		goto out;
7679ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
7684093a844SRichard Guy Briggs 		  "op=security_validate_transition seresult=denied"
7691da177e4SLinus Torvalds 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
770ac76c05bSEric Paris 		  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
7711da177e4SLinus Torvalds out:
7721da177e4SLinus Torvalds 	kfree(o);
7731da177e4SLinus Torvalds 	kfree(n);
7741da177e4SLinus Torvalds 	kfree(t);
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 	if (!selinux_enforcing)
7771da177e4SLinus Torvalds 		return 0;
7781da177e4SLinus Torvalds 	return -EPERM;
7791da177e4SLinus Torvalds }
7801da177e4SLinus Torvalds 
781f9df6458SAndrew Perepechko static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
782f9df6458SAndrew Perepechko 					  u16 orig_tclass, bool user)
7831da177e4SLinus Torvalds {
7841da177e4SLinus Torvalds 	struct context *ocontext;
7851da177e4SLinus Torvalds 	struct context *ncontext;
7861da177e4SLinus Torvalds 	struct context *tcontext;
7871da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
7881da177e4SLinus Torvalds 	struct constraint_node *constraint;
789c6d3aaa4SStephen Smalley 	u16 tclass;
7901da177e4SLinus Torvalds 	int rc = 0;
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 	if (!ss_initialized)
7931da177e4SLinus Torvalds 		return 0;
7941da177e4SLinus Torvalds 
7950804d113SJames Morris 	read_lock(&policy_rwlock);
7961da177e4SLinus Torvalds 
797f9df6458SAndrew Perepechko 	if (!user)
798c6d3aaa4SStephen Smalley 		tclass = unmap_class(orig_tclass);
799f9df6458SAndrew Perepechko 	else
800f9df6458SAndrew Perepechko 		tclass = orig_tclass;
801c6d3aaa4SStephen Smalley 
8021da177e4SLinus Torvalds 	if (!tclass || tclass > policydb.p_classes.nprim) {
8031da177e4SLinus Torvalds 		rc = -EINVAL;
8041da177e4SLinus Torvalds 		goto out;
8051da177e4SLinus Torvalds 	}
8061da177e4SLinus Torvalds 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	ocontext = sidtab_search(&sidtab, oldsid);
8091da177e4SLinus Torvalds 	if (!ocontext) {
810744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
811744ba35eSEric Paris 			__func__, oldsid);
8121da177e4SLinus Torvalds 		rc = -EINVAL;
8131da177e4SLinus Torvalds 		goto out;
8141da177e4SLinus Torvalds 	}
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds 	ncontext = sidtab_search(&sidtab, newsid);
8171da177e4SLinus Torvalds 	if (!ncontext) {
818744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
819744ba35eSEric Paris 			__func__, newsid);
8201da177e4SLinus Torvalds 		rc = -EINVAL;
8211da177e4SLinus Torvalds 		goto out;
8221da177e4SLinus Torvalds 	}
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tasksid);
8251da177e4SLinus Torvalds 	if (!tcontext) {
826744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
827744ba35eSEric Paris 			__func__, tasksid);
8281da177e4SLinus Torvalds 		rc = -EINVAL;
8291da177e4SLinus Torvalds 		goto out;
8301da177e4SLinus Torvalds 	}
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	constraint = tclass_datum->validatetrans;
8331da177e4SLinus Torvalds 	while (constraint) {
8341da177e4SLinus Torvalds 		if (!constraint_expr_eval(ocontext, ncontext, tcontext,
8351da177e4SLinus Torvalds 					  constraint->expr)) {
836f9df6458SAndrew Perepechko 			if (user)
837f9df6458SAndrew Perepechko 				rc = -EPERM;
838f9df6458SAndrew Perepechko 			else
839f9df6458SAndrew Perepechko 				rc = security_validtrans_handle_fail(ocontext,
840f9df6458SAndrew Perepechko 								     ncontext,
841f9df6458SAndrew Perepechko 								     tcontext,
842f9df6458SAndrew Perepechko 								     tclass);
8431da177e4SLinus Torvalds 			goto out;
8441da177e4SLinus Torvalds 		}
8451da177e4SLinus Torvalds 		constraint = constraint->next;
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds out:
8490804d113SJames Morris 	read_unlock(&policy_rwlock);
8501da177e4SLinus Torvalds 	return rc;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
853f9df6458SAndrew Perepechko int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
854f9df6458SAndrew Perepechko 					u16 tclass)
855f9df6458SAndrew Perepechko {
856f9df6458SAndrew Perepechko 	return security_compute_validatetrans(oldsid, newsid, tasksid,
857f9df6458SAndrew Perepechko 						tclass, true);
858f9df6458SAndrew Perepechko }
859f9df6458SAndrew Perepechko 
860f9df6458SAndrew Perepechko int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
861f9df6458SAndrew Perepechko 				 u16 orig_tclass)
862f9df6458SAndrew Perepechko {
863f9df6458SAndrew Perepechko 	return security_compute_validatetrans(oldsid, newsid, tasksid,
864f9df6458SAndrew Perepechko 						orig_tclass, false);
865f9df6458SAndrew Perepechko }
866f9df6458SAndrew Perepechko 
867d9250deaSKaiGai Kohei /*
868d9250deaSKaiGai Kohei  * security_bounded_transition - check whether the given
869d9250deaSKaiGai Kohei  * transition is directed to bounded, or not.
870d9250deaSKaiGai Kohei  * It returns 0, if @newsid is bounded by @oldsid.
871d9250deaSKaiGai Kohei  * Otherwise, it returns error code.
872d9250deaSKaiGai Kohei  *
873d9250deaSKaiGai Kohei  * @oldsid : current security identifier
874d9250deaSKaiGai Kohei  * @newsid : destinated security identifier
875d9250deaSKaiGai Kohei  */
876d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid)
877d9250deaSKaiGai Kohei {
878d9250deaSKaiGai Kohei 	struct context *old_context, *new_context;
879d9250deaSKaiGai Kohei 	struct type_datum *type;
880d9250deaSKaiGai Kohei 	int index;
8814b02b524SEric Paris 	int rc;
882d9250deaSKaiGai Kohei 
883d9250deaSKaiGai Kohei 	read_lock(&policy_rwlock);
884d9250deaSKaiGai Kohei 
8854b02b524SEric Paris 	rc = -EINVAL;
886d9250deaSKaiGai Kohei 	old_context = sidtab_search(&sidtab, old_sid);
887d9250deaSKaiGai Kohei 	if (!old_context) {
888d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
889d9250deaSKaiGai Kohei 		       __func__, old_sid);
890d9250deaSKaiGai Kohei 		goto out;
891d9250deaSKaiGai Kohei 	}
892d9250deaSKaiGai Kohei 
8934b02b524SEric Paris 	rc = -EINVAL;
894d9250deaSKaiGai Kohei 	new_context = sidtab_search(&sidtab, new_sid);
895d9250deaSKaiGai Kohei 	if (!new_context) {
896d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
897d9250deaSKaiGai Kohei 		       __func__, new_sid);
898d9250deaSKaiGai Kohei 		goto out;
899d9250deaSKaiGai Kohei 	}
900d9250deaSKaiGai Kohei 
901d9250deaSKaiGai Kohei 	rc = 0;
9024b02b524SEric Paris 	/* type/domain unchanged */
9034b02b524SEric Paris 	if (old_context->type == new_context->type)
904d9250deaSKaiGai Kohei 		goto out;
905d9250deaSKaiGai Kohei 
906d9250deaSKaiGai Kohei 	index = new_context->type;
907d9250deaSKaiGai Kohei 	while (true) {
90823bdecb0SEric Paris 		type = flex_array_get_ptr(policydb.type_val_to_struct_array,
90923bdecb0SEric Paris 					  index - 1);
910d9250deaSKaiGai Kohei 		BUG_ON(!type);
911d9250deaSKaiGai Kohei 
912d9250deaSKaiGai Kohei 		/* not bounded anymore */
913d9250deaSKaiGai Kohei 		rc = -EPERM;
9144b02b524SEric Paris 		if (!type->bounds)
915d9250deaSKaiGai Kohei 			break;
916d9250deaSKaiGai Kohei 
917d9250deaSKaiGai Kohei 		/* @newsid is bounded by @oldsid */
918d9250deaSKaiGai Kohei 		rc = 0;
9194b02b524SEric Paris 		if (type->bounds == old_context->type)
920d9250deaSKaiGai Kohei 			break;
9214b02b524SEric Paris 
922d9250deaSKaiGai Kohei 		index = type->bounds;
923d9250deaSKaiGai Kohei 	}
92444c2d9bdSKaiGai Kohei 
92544c2d9bdSKaiGai Kohei 	if (rc) {
92644c2d9bdSKaiGai Kohei 		char *old_name = NULL;
92744c2d9bdSKaiGai Kohei 		char *new_name = NULL;
9282da5d31bSJames Morris 		u32 length;
92944c2d9bdSKaiGai Kohei 
93044c2d9bdSKaiGai Kohei 		if (!context_struct_to_string(old_context,
93144c2d9bdSKaiGai Kohei 					      &old_name, &length) &&
93244c2d9bdSKaiGai Kohei 		    !context_struct_to_string(new_context,
93344c2d9bdSKaiGai Kohei 					      &new_name, &length)) {
93444c2d9bdSKaiGai Kohei 			audit_log(current->audit_context,
93544c2d9bdSKaiGai Kohei 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
93644c2d9bdSKaiGai Kohei 				  "op=security_bounded_transition "
9374093a844SRichard Guy Briggs 				  "seresult=denied "
93844c2d9bdSKaiGai Kohei 				  "oldcontext=%s newcontext=%s",
93944c2d9bdSKaiGai Kohei 				  old_name, new_name);
94044c2d9bdSKaiGai Kohei 		}
94144c2d9bdSKaiGai Kohei 		kfree(new_name);
94244c2d9bdSKaiGai Kohei 		kfree(old_name);
94344c2d9bdSKaiGai Kohei 	}
944d9250deaSKaiGai Kohei out:
945d9250deaSKaiGai Kohei 	read_unlock(&policy_rwlock);
946d9250deaSKaiGai Kohei 
947d9250deaSKaiGai Kohei 	return rc;
948d9250deaSKaiGai Kohei }
949d9250deaSKaiGai Kohei 
95019439d05SStephen Smalley static void avd_init(struct av_decision *avd)
951c6d3aaa4SStephen Smalley {
95219439d05SStephen Smalley 	avd->allowed = 0;
95319439d05SStephen Smalley 	avd->auditallow = 0;
95419439d05SStephen Smalley 	avd->auditdeny = 0xffffffff;
95519439d05SStephen Smalley 	avd->seqno = latest_granting;
95619439d05SStephen Smalley 	avd->flags = 0;
957c6d3aaa4SStephen Smalley }
958c6d3aaa4SStephen Smalley 
959fa1aa143SJeff Vander Stoep void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
960fa1aa143SJeff Vander Stoep 					struct avtab_node *node)
961fa1aa143SJeff Vander Stoep {
962fa1aa143SJeff Vander Stoep 	unsigned int i;
963fa1aa143SJeff Vander Stoep 
964fa1aa143SJeff Vander Stoep 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
965fa1aa143SJeff Vander Stoep 		if (xpermd->driver != node->datum.u.xperms->driver)
966fa1aa143SJeff Vander Stoep 			return;
967fa1aa143SJeff Vander Stoep 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
968fa1aa143SJeff Vander Stoep 		if (!security_xperm_test(node->datum.u.xperms->perms.p,
969fa1aa143SJeff Vander Stoep 					xpermd->driver))
970fa1aa143SJeff Vander Stoep 			return;
971fa1aa143SJeff Vander Stoep 	} else {
972fa1aa143SJeff Vander Stoep 		BUG();
973fa1aa143SJeff Vander Stoep 	}
974fa1aa143SJeff Vander Stoep 
975fa1aa143SJeff Vander Stoep 	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
976fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_ALLOWED;
977fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
978fa1aa143SJeff Vander Stoep 			memset(xpermd->allowed->p, 0xff,
979fa1aa143SJeff Vander Stoep 					sizeof(xpermd->allowed->p));
980fa1aa143SJeff Vander Stoep 		}
981fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
982fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
983fa1aa143SJeff Vander Stoep 				xpermd->allowed->p[i] |=
984fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
985fa1aa143SJeff Vander Stoep 		}
986fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
987fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_AUDITALLOW;
988fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
989fa1aa143SJeff Vander Stoep 			memset(xpermd->auditallow->p, 0xff,
990fa1aa143SJeff Vander Stoep 					sizeof(xpermd->auditallow->p));
991fa1aa143SJeff Vander Stoep 		}
992fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
993fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
994fa1aa143SJeff Vander Stoep 				xpermd->auditallow->p[i] |=
995fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
996fa1aa143SJeff Vander Stoep 		}
997fa1aa143SJeff Vander Stoep 	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
998fa1aa143SJeff Vander Stoep 		xpermd->used |= XPERMS_DONTAUDIT;
999fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
1000fa1aa143SJeff Vander Stoep 			memset(xpermd->dontaudit->p, 0xff,
1001fa1aa143SJeff Vander Stoep 					sizeof(xpermd->dontaudit->p));
1002fa1aa143SJeff Vander Stoep 		}
1003fa1aa143SJeff Vander Stoep 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
1004fa1aa143SJeff Vander Stoep 			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
1005fa1aa143SJeff Vander Stoep 				xpermd->dontaudit->p[i] |=
1006fa1aa143SJeff Vander Stoep 					node->datum.u.xperms->perms.p[i];
1007fa1aa143SJeff Vander Stoep 		}
1008fa1aa143SJeff Vander Stoep 	} else {
1009fa1aa143SJeff Vander Stoep 		BUG();
1010fa1aa143SJeff Vander Stoep 	}
1011fa1aa143SJeff Vander Stoep }
1012fa1aa143SJeff Vander Stoep 
1013fa1aa143SJeff Vander Stoep void security_compute_xperms_decision(u32 ssid,
1014fa1aa143SJeff Vander Stoep 				u32 tsid,
1015fa1aa143SJeff Vander Stoep 				u16 orig_tclass,
1016fa1aa143SJeff Vander Stoep 				u8 driver,
1017fa1aa143SJeff Vander Stoep 				struct extended_perms_decision *xpermd)
1018fa1aa143SJeff Vander Stoep {
1019fa1aa143SJeff Vander Stoep 	u16 tclass;
1020fa1aa143SJeff Vander Stoep 	struct context *scontext, *tcontext;
1021fa1aa143SJeff Vander Stoep 	struct avtab_key avkey;
1022fa1aa143SJeff Vander Stoep 	struct avtab_node *node;
1023fa1aa143SJeff Vander Stoep 	struct ebitmap *sattr, *tattr;
1024fa1aa143SJeff Vander Stoep 	struct ebitmap_node *snode, *tnode;
1025fa1aa143SJeff Vander Stoep 	unsigned int i, j;
1026fa1aa143SJeff Vander Stoep 
1027fa1aa143SJeff Vander Stoep 	xpermd->driver = driver;
1028fa1aa143SJeff Vander Stoep 	xpermd->used = 0;
1029fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1030fa1aa143SJeff Vander Stoep 	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1031fa1aa143SJeff Vander Stoep 	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1032fa1aa143SJeff Vander Stoep 
1033fa1aa143SJeff Vander Stoep 	read_lock(&policy_rwlock);
1034fa1aa143SJeff Vander Stoep 	if (!ss_initialized)
1035fa1aa143SJeff Vander Stoep 		goto allow;
1036fa1aa143SJeff Vander Stoep 
1037fa1aa143SJeff Vander Stoep 	scontext = sidtab_search(&sidtab, ssid);
1038fa1aa143SJeff Vander Stoep 	if (!scontext) {
1039fa1aa143SJeff Vander Stoep 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1040fa1aa143SJeff Vander Stoep 		       __func__, ssid);
1041fa1aa143SJeff Vander Stoep 		goto out;
1042fa1aa143SJeff Vander Stoep 	}
1043fa1aa143SJeff Vander Stoep 
1044fa1aa143SJeff Vander Stoep 	tcontext = sidtab_search(&sidtab, tsid);
1045fa1aa143SJeff Vander Stoep 	if (!tcontext) {
1046fa1aa143SJeff Vander Stoep 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1047fa1aa143SJeff Vander Stoep 		       __func__, tsid);
1048fa1aa143SJeff Vander Stoep 		goto out;
1049fa1aa143SJeff Vander Stoep 	}
1050fa1aa143SJeff Vander Stoep 
1051fa1aa143SJeff Vander Stoep 	tclass = unmap_class(orig_tclass);
1052fa1aa143SJeff Vander Stoep 	if (unlikely(orig_tclass && !tclass)) {
1053fa1aa143SJeff Vander Stoep 		if (policydb.allow_unknown)
1054fa1aa143SJeff Vander Stoep 			goto allow;
1055fa1aa143SJeff Vander Stoep 		goto out;
1056fa1aa143SJeff Vander Stoep 	}
1057fa1aa143SJeff Vander Stoep 
1058fa1aa143SJeff Vander Stoep 
1059fa1aa143SJeff Vander Stoep 	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
1060fa1aa143SJeff Vander Stoep 		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
1061fa1aa143SJeff Vander Stoep 		goto out;
1062fa1aa143SJeff Vander Stoep 	}
1063fa1aa143SJeff Vander Stoep 
1064fa1aa143SJeff Vander Stoep 	avkey.target_class = tclass;
1065fa1aa143SJeff Vander Stoep 	avkey.specified = AVTAB_XPERMS;
1066fa1aa143SJeff Vander Stoep 	sattr = flex_array_get(policydb.type_attr_map_array,
1067fa1aa143SJeff Vander Stoep 				scontext->type - 1);
1068fa1aa143SJeff Vander Stoep 	BUG_ON(!sattr);
1069fa1aa143SJeff Vander Stoep 	tattr = flex_array_get(policydb.type_attr_map_array,
1070fa1aa143SJeff Vander Stoep 				tcontext->type - 1);
1071fa1aa143SJeff Vander Stoep 	BUG_ON(!tattr);
1072fa1aa143SJeff Vander Stoep 	ebitmap_for_each_positive_bit(sattr, snode, i) {
1073fa1aa143SJeff Vander Stoep 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1074fa1aa143SJeff Vander Stoep 			avkey.source_type = i + 1;
1075fa1aa143SJeff Vander Stoep 			avkey.target_type = j + 1;
1076fa1aa143SJeff Vander Stoep 			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
1077fa1aa143SJeff Vander Stoep 			     node;
1078fa1aa143SJeff Vander Stoep 			     node = avtab_search_node_next(node, avkey.specified))
1079fa1aa143SJeff Vander Stoep 				services_compute_xperms_decision(xpermd, node);
1080fa1aa143SJeff Vander Stoep 
1081fa1aa143SJeff Vander Stoep 			cond_compute_xperms(&policydb.te_cond_avtab,
1082fa1aa143SJeff Vander Stoep 						&avkey, xpermd);
1083fa1aa143SJeff Vander Stoep 		}
1084fa1aa143SJeff Vander Stoep 	}
1085fa1aa143SJeff Vander Stoep out:
1086fa1aa143SJeff Vander Stoep 	read_unlock(&policy_rwlock);
1087fa1aa143SJeff Vander Stoep 	return;
1088fa1aa143SJeff Vander Stoep allow:
1089fa1aa143SJeff Vander Stoep 	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1090fa1aa143SJeff Vander Stoep 	goto out;
1091fa1aa143SJeff Vander Stoep }
1092c6d3aaa4SStephen Smalley 
10931da177e4SLinus Torvalds /**
10941da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
10951da177e4SLinus Torvalds  * @ssid: source security identifier
10961da177e4SLinus Torvalds  * @tsid: target security identifier
10971da177e4SLinus Torvalds  * @tclass: target security class
10981da177e4SLinus Torvalds  * @avd: access vector decisions
1099fa1aa143SJeff Vander Stoep  * @xperms: extended permissions
11001da177e4SLinus Torvalds  *
11011da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
11021da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
11031da177e4SLinus Torvalds  */
110419439d05SStephen Smalley void security_compute_av(u32 ssid,
11051da177e4SLinus Torvalds 			 u32 tsid,
1106c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
1107fa1aa143SJeff Vander Stoep 			 struct av_decision *avd,
1108fa1aa143SJeff Vander Stoep 			 struct extended_perms *xperms)
1109c6d3aaa4SStephen Smalley {
1110c6d3aaa4SStephen Smalley 	u16 tclass;
111119439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
1112c6d3aaa4SStephen Smalley 
1113b7f3008aSStephen Smalley 	read_lock(&policy_rwlock);
111419439d05SStephen Smalley 	avd_init(avd);
1115fa1aa143SJeff Vander Stoep 	xperms->len = 0;
1116c6d3aaa4SStephen Smalley 	if (!ss_initialized)
1117c6d3aaa4SStephen Smalley 		goto allow;
1118c6d3aaa4SStephen Smalley 
111919439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
112019439d05SStephen Smalley 	if (!scontext) {
112119439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
112219439d05SStephen Smalley 		       __func__, ssid);
112319439d05SStephen Smalley 		goto out;
112419439d05SStephen Smalley 	}
112519439d05SStephen Smalley 
112619439d05SStephen Smalley 	/* permissive domain? */
112719439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
112819439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
112919439d05SStephen Smalley 
113019439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
113119439d05SStephen Smalley 	if (!tcontext) {
113219439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
113319439d05SStephen Smalley 		       __func__, tsid);
113419439d05SStephen Smalley 		goto out;
113519439d05SStephen Smalley 	}
113619439d05SStephen Smalley 
1137c6d3aaa4SStephen Smalley 	tclass = unmap_class(orig_tclass);
1138c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
1139c6d3aaa4SStephen Smalley 		if (policydb.allow_unknown)
1140c6d3aaa4SStephen Smalley 			goto allow;
1141b7f3008aSStephen Smalley 		goto out;
1142c6d3aaa4SStephen Smalley 	}
1143fa1aa143SJeff Vander Stoep 	context_struct_compute_av(scontext, tcontext, tclass, avd, xperms);
1144c6d3aaa4SStephen Smalley 	map_decision(orig_tclass, avd, policydb.allow_unknown);
1145b7f3008aSStephen Smalley out:
1146c6d3aaa4SStephen Smalley 	read_unlock(&policy_rwlock);
114719439d05SStephen Smalley 	return;
1148c6d3aaa4SStephen Smalley allow:
1149c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
1150b7f3008aSStephen Smalley 	goto out;
1151c6d3aaa4SStephen Smalley }
1152c6d3aaa4SStephen Smalley 
115319439d05SStephen Smalley void security_compute_av_user(u32 ssid,
1154c6d3aaa4SStephen Smalley 			      u32 tsid,
11551da177e4SLinus Torvalds 			      u16 tclass,
11561da177e4SLinus Torvalds 			      struct av_decision *avd)
11571da177e4SLinus Torvalds {
115819439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
11591da177e4SLinus Torvalds 
11600804d113SJames Morris 	read_lock(&policy_rwlock);
116119439d05SStephen Smalley 	avd_init(avd);
116219439d05SStephen Smalley 	if (!ss_initialized)
116319439d05SStephen Smalley 		goto allow;
116419439d05SStephen Smalley 
116519439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
116619439d05SStephen Smalley 	if (!scontext) {
116719439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
116819439d05SStephen Smalley 		       __func__, ssid);
116919439d05SStephen Smalley 		goto out;
117019439d05SStephen Smalley 	}
117119439d05SStephen Smalley 
117219439d05SStephen Smalley 	/* permissive domain? */
117319439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
117419439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
117519439d05SStephen Smalley 
117619439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
117719439d05SStephen Smalley 	if (!tcontext) {
117819439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
117919439d05SStephen Smalley 		       __func__, tsid);
118019439d05SStephen Smalley 		goto out;
118119439d05SStephen Smalley 	}
118219439d05SStephen Smalley 
118319439d05SStephen Smalley 	if (unlikely(!tclass)) {
118419439d05SStephen Smalley 		if (policydb.allow_unknown)
118519439d05SStephen Smalley 			goto allow;
118619439d05SStephen Smalley 		goto out;
118719439d05SStephen Smalley 	}
118819439d05SStephen Smalley 
1189fa1aa143SJeff Vander Stoep 	context_struct_compute_av(scontext, tcontext, tclass, avd, NULL);
119019439d05SStephen Smalley  out:
11910804d113SJames Morris 	read_unlock(&policy_rwlock);
119219439d05SStephen Smalley 	return;
119319439d05SStephen Smalley allow:
119419439d05SStephen Smalley 	avd->allowed = 0xffffffff;
119519439d05SStephen Smalley 	goto out;
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds /*
11991da177e4SLinus Torvalds  * Write the security context string representation of
12001da177e4SLinus Torvalds  * the context structure `context' into a dynamically
12011da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
12021da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
12031da177e4SLinus Torvalds  * the length of the string.
12041da177e4SLinus Torvalds  */
12051da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
12061da177e4SLinus Torvalds {
12071da177e4SLinus Torvalds 	char *scontextp;
12081da177e4SLinus Torvalds 
1209d5630b9dSEric Paris 	if (scontext)
12101da177e4SLinus Torvalds 		*scontext = NULL;
12111da177e4SLinus Torvalds 	*scontext_len = 0;
12121da177e4SLinus Torvalds 
121312b29f34SStephen Smalley 	if (context->len) {
121412b29f34SStephen Smalley 		*scontext_len = context->len;
1215bb7081abSEric Paris 		if (scontext) {
121612b29f34SStephen Smalley 			*scontext = kstrdup(context->str, GFP_ATOMIC);
121712b29f34SStephen Smalley 			if (!(*scontext))
121812b29f34SStephen Smalley 				return -ENOMEM;
1219bb7081abSEric Paris 		}
122012b29f34SStephen Smalley 		return 0;
122112b29f34SStephen Smalley 	}
122212b29f34SStephen Smalley 
12231da177e4SLinus Torvalds 	/* Compute the size of the context. */
1224ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
1225ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
1226ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
12271da177e4SLinus Torvalds 	*scontext_len += mls_compute_context_len(context);
12281da177e4SLinus Torvalds 
1229d5630b9dSEric Paris 	if (!scontext)
1230d5630b9dSEric Paris 		return 0;
1231d5630b9dSEric Paris 
12321da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
12331da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12345d55a345SEric Paris 	if (!scontextp)
12351da177e4SLinus Torvalds 		return -ENOMEM;
12361da177e4SLinus Torvalds 	*scontext = scontextp;
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds 	/*
12391da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
12401da177e4SLinus Torvalds 	 */
12419529c788SRasmus Villemoes 	scontextp += sprintf(scontextp, "%s:%s:%s",
1242ac76c05bSEric Paris 		sym_name(&policydb, SYM_USERS, context->user - 1),
1243ac76c05bSEric Paris 		sym_name(&policydb, SYM_ROLES, context->role - 1),
1244ac76c05bSEric Paris 		sym_name(&policydb, SYM_TYPES, context->type - 1));
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds 	mls_sid_to_context(context, &scontextp);
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	*scontextp = 0;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	return 0;
12511da177e4SLinus Torvalds }
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12541da177e4SLinus Torvalds 
1255f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1256f0ee2e46SJames Carter {
1257f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1258f0ee2e46SJames Carter 		return NULL;
1259f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1260f0ee2e46SJames Carter }
1261f0ee2e46SJames Carter 
126212b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
126312b29f34SStephen Smalley 					u32 *scontext_len, int force)
12641da177e4SLinus Torvalds {
12651da177e4SLinus Torvalds 	struct context *context;
12661da177e4SLinus Torvalds 	int rc = 0;
12671da177e4SLinus Torvalds 
1268d5630b9dSEric Paris 	if (scontext)
12694f4acf3aSStephen Smalley 		*scontext = NULL;
12704f4acf3aSStephen Smalley 	*scontext_len  = 0;
12714f4acf3aSStephen Smalley 
12721da177e4SLinus Torvalds 	if (!ss_initialized) {
12731da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
12741da177e4SLinus Torvalds 			char *scontextp;
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
1277d5630b9dSEric Paris 			if (!scontext)
1278d5630b9dSEric Paris 				goto out;
1279aa736c36SRasmus Villemoes 			scontextp = kmemdup(initial_sid_to_string[sid],
1280aa736c36SRasmus Villemoes 					    *scontext_len, GFP_ATOMIC);
12810cccca06SSerge E. Hallyn 			if (!scontextp) {
12820cccca06SSerge E. Hallyn 				rc = -ENOMEM;
12830cccca06SSerge E. Hallyn 				goto out;
12840cccca06SSerge E. Hallyn 			}
12851da177e4SLinus Torvalds 			*scontext = scontextp;
12861da177e4SLinus Torvalds 			goto out;
12871da177e4SLinus Torvalds 		}
1288744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  called before initial "
1289744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
12901da177e4SLinus Torvalds 		rc = -EINVAL;
12911da177e4SLinus Torvalds 		goto out;
12921da177e4SLinus Torvalds 	}
12930804d113SJames Morris 	read_lock(&policy_rwlock);
129412b29f34SStephen Smalley 	if (force)
129512b29f34SStephen Smalley 		context = sidtab_search_force(&sidtab, sid);
129612b29f34SStephen Smalley 	else
12971da177e4SLinus Torvalds 		context = sidtab_search(&sidtab, sid);
12981da177e4SLinus Torvalds 	if (!context) {
1299744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1300744ba35eSEric Paris 			__func__, sid);
13011da177e4SLinus Torvalds 		rc = -EINVAL;
13021da177e4SLinus Torvalds 		goto out_unlock;
13031da177e4SLinus Torvalds 	}
13041da177e4SLinus Torvalds 	rc = context_struct_to_string(context, scontext, scontext_len);
13051da177e4SLinus Torvalds out_unlock:
13060804d113SJames Morris 	read_unlock(&policy_rwlock);
13071da177e4SLinus Torvalds out:
13081da177e4SLinus Torvalds 	return rc;
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds }
13111da177e4SLinus Torvalds 
131212b29f34SStephen Smalley /**
131312b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
131412b29f34SStephen Smalley  * @sid: security identifier, SID
131512b29f34SStephen Smalley  * @scontext: security context
131612b29f34SStephen Smalley  * @scontext_len: length in bytes
131712b29f34SStephen Smalley  *
131812b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
131912b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
132012b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
132112b29f34SStephen Smalley  */
132212b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
13231da177e4SLinus Torvalds {
132412b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 0);
132512b29f34SStephen Smalley }
132612b29f34SStephen Smalley 
132712b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
132812b29f34SStephen Smalley {
132912b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 1);
133012b29f34SStephen Smalley }
133112b29f34SStephen Smalley 
13329a59daa0SStephen Smalley /*
13339a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
13349a59daa0SStephen Smalley  */
133512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
133612b29f34SStephen Smalley 				    struct sidtab *sidtabp,
13379a59daa0SStephen Smalley 				    char *scontext,
133812b29f34SStephen Smalley 				    u32 scontext_len,
133912b29f34SStephen Smalley 				    struct context *ctx,
13409a59daa0SStephen Smalley 				    u32 def_sid)
134112b29f34SStephen Smalley {
13421da177e4SLinus Torvalds 	struct role_datum *role;
13431da177e4SLinus Torvalds 	struct type_datum *typdatum;
13441da177e4SLinus Torvalds 	struct user_datum *usrdatum;
13451da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
13461da177e4SLinus Torvalds 	int rc = 0;
13471da177e4SLinus Torvalds 
134812b29f34SStephen Smalley 	context_init(ctx);
134912b29f34SStephen Smalley 
135012b29f34SStephen Smalley 	/* Parse the security context. */
135112b29f34SStephen Smalley 
135212b29f34SStephen Smalley 	rc = -EINVAL;
13539a59daa0SStephen Smalley 	scontextp = (char *) scontext;
135412b29f34SStephen Smalley 
135512b29f34SStephen Smalley 	/* Extract the user. */
135612b29f34SStephen Smalley 	p = scontextp;
135712b29f34SStephen Smalley 	while (*p && *p != ':')
135812b29f34SStephen Smalley 		p++;
135912b29f34SStephen Smalley 
136012b29f34SStephen Smalley 	if (*p == 0)
136112b29f34SStephen Smalley 		goto out;
136212b29f34SStephen Smalley 
136312b29f34SStephen Smalley 	*p++ = 0;
136412b29f34SStephen Smalley 
136512b29f34SStephen Smalley 	usrdatum = hashtab_search(pol->p_users.table, scontextp);
136612b29f34SStephen Smalley 	if (!usrdatum)
136712b29f34SStephen Smalley 		goto out;
136812b29f34SStephen Smalley 
136912b29f34SStephen Smalley 	ctx->user = usrdatum->value;
137012b29f34SStephen Smalley 
137112b29f34SStephen Smalley 	/* Extract role. */
137212b29f34SStephen Smalley 	scontextp = p;
137312b29f34SStephen Smalley 	while (*p && *p != ':')
137412b29f34SStephen Smalley 		p++;
137512b29f34SStephen Smalley 
137612b29f34SStephen Smalley 	if (*p == 0)
137712b29f34SStephen Smalley 		goto out;
137812b29f34SStephen Smalley 
137912b29f34SStephen Smalley 	*p++ = 0;
138012b29f34SStephen Smalley 
138112b29f34SStephen Smalley 	role = hashtab_search(pol->p_roles.table, scontextp);
138212b29f34SStephen Smalley 	if (!role)
138312b29f34SStephen Smalley 		goto out;
138412b29f34SStephen Smalley 	ctx->role = role->value;
138512b29f34SStephen Smalley 
138612b29f34SStephen Smalley 	/* Extract type. */
138712b29f34SStephen Smalley 	scontextp = p;
138812b29f34SStephen Smalley 	while (*p && *p != ':')
138912b29f34SStephen Smalley 		p++;
139012b29f34SStephen Smalley 	oldc = *p;
139112b29f34SStephen Smalley 	*p++ = 0;
139212b29f34SStephen Smalley 
139312b29f34SStephen Smalley 	typdatum = hashtab_search(pol->p_types.table, scontextp);
1394d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
139512b29f34SStephen Smalley 		goto out;
139612b29f34SStephen Smalley 
139712b29f34SStephen Smalley 	ctx->type = typdatum->value;
139812b29f34SStephen Smalley 
139912b29f34SStephen Smalley 	rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
140012b29f34SStephen Smalley 	if (rc)
140112b29f34SStephen Smalley 		goto out;
140212b29f34SStephen Smalley 
140312b29f34SStephen Smalley 	rc = -EINVAL;
14044b02b524SEric Paris 	if ((p - scontext) < scontext_len)
140512b29f34SStephen Smalley 		goto out;
140612b29f34SStephen Smalley 
140712b29f34SStephen Smalley 	/* Check the validity of the new context. */
14084b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
140912b29f34SStephen Smalley 		goto out;
141012b29f34SStephen Smalley 	rc = 0;
141112b29f34SStephen Smalley out:
14128e531af9SEric Paris 	if (rc)
14138e531af9SEric Paris 		context_destroy(ctx);
141412b29f34SStephen Smalley 	return rc;
141512b29f34SStephen Smalley }
141612b29f34SStephen Smalley 
141712b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
141812b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
141912b29f34SStephen Smalley 					int force)
142012b29f34SStephen Smalley {
14219a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
142212b29f34SStephen Smalley 	struct context context;
142312b29f34SStephen Smalley 	int rc = 0;
142412b29f34SStephen Smalley 
14252172fa70SStephen Smalley 	/* An empty security context is never valid. */
14262172fa70SStephen Smalley 	if (!scontext_len)
14272172fa70SStephen Smalley 		return -EINVAL;
14282172fa70SStephen Smalley 
14291da177e4SLinus Torvalds 	if (!ss_initialized) {
14301da177e4SLinus Torvalds 		int i;
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
14331da177e4SLinus Torvalds 			if (!strcmp(initial_sid_to_string[i], scontext)) {
14341da177e4SLinus Torvalds 				*sid = i;
14359a59daa0SStephen Smalley 				return 0;
14361da177e4SLinus Torvalds 			}
14371da177e4SLinus Torvalds 		}
14381da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
14399a59daa0SStephen Smalley 		return 0;
14401da177e4SLinus Torvalds 	}
14411da177e4SLinus Torvalds 	*sid = SECSID_NULL;
14421da177e4SLinus Torvalds 
14439a59daa0SStephen Smalley 	/* Copy the string so that we can modify the copy as we parse it. */
14449a59daa0SStephen Smalley 	scontext2 = kmalloc(scontext_len + 1, gfp_flags);
14459a59daa0SStephen Smalley 	if (!scontext2)
14469a59daa0SStephen Smalley 		return -ENOMEM;
14479a59daa0SStephen Smalley 	memcpy(scontext2, scontext, scontext_len);
14489a59daa0SStephen Smalley 	scontext2[scontext_len] = 0;
14499a59daa0SStephen Smalley 
14509a59daa0SStephen Smalley 	if (force) {
14519a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
14524b02b524SEric Paris 		rc = -ENOMEM;
14539a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
14544b02b524SEric Paris 		if (!str)
14554b02b524SEric Paris 			goto out;
14569a59daa0SStephen Smalley 	}
14579a59daa0SStephen Smalley 
14580804d113SJames Morris 	read_lock(&policy_rwlock);
14594b02b524SEric Paris 	rc = string_to_context_struct(&policydb, &sidtab, scontext2,
14604b02b524SEric Paris 				      scontext_len, &context, def_sid);
146112b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
14629a59daa0SStephen Smalley 		context.str = str;
146312b29f34SStephen Smalley 		context.len = scontext_len;
14649a59daa0SStephen Smalley 		str = NULL;
146512b29f34SStephen Smalley 	} else if (rc)
14664b02b524SEric Paris 		goto out_unlock;
14671da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &context, sid);
14681da177e4SLinus Torvalds 	context_destroy(&context);
14694b02b524SEric Paris out_unlock:
14700804d113SJames Morris 	read_unlock(&policy_rwlock);
14714b02b524SEric Paris out:
14729a59daa0SStephen Smalley 	kfree(scontext2);
14739a59daa0SStephen Smalley 	kfree(str);
14741da177e4SLinus Torvalds 	return rc;
14751da177e4SLinus Torvalds }
14761da177e4SLinus Torvalds 
1477f5c1d5b2SJames Morris /**
1478f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1479f5c1d5b2SJames Morris  * @scontext: security context
1480f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1481f5c1d5b2SJames Morris  * @sid: security identifier, SID
148252a4c640SNikolay Aleksandrov  * @gfp: context for the allocation
1483f5c1d5b2SJames Morris  *
1484f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1485f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1486f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1487f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1488f5c1d5b2SJames Morris  */
148952a4c640SNikolay Aleksandrov int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
149052a4c640SNikolay Aleksandrov 			    gfp_t gfp)
1491f5c1d5b2SJames Morris {
1492f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
149352a4c640SNikolay Aleksandrov 					    sid, SECSID_NULL, gfp, 0);
1494f5c1d5b2SJames Morris }
1495f5c1d5b2SJames Morris 
149644be2f65SRasmus Villemoes int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
149744be2f65SRasmus Villemoes {
149844be2f65SRasmus Villemoes 	return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
149944be2f65SRasmus Villemoes }
150044be2f65SRasmus Villemoes 
1501f5c1d5b2SJames Morris /**
1502f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1503f5c1d5b2SJames Morris  * falling back to specified default if needed.
1504f5c1d5b2SJames Morris  *
1505f5c1d5b2SJames Morris  * @scontext: security context
1506f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1507f5c1d5b2SJames Morris  * @sid: security identifier, SID
1508d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1509f5c1d5b2SJames Morris  *
1510f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1511f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1512f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1513f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1514f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
151512b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1516f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1517f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1518f5c1d5b2SJames Morris  */
15197bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len,
15207bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1521f5c1d5b2SJames Morris {
1522f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
152312b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
152412b29f34SStephen Smalley }
152512b29f34SStephen Smalley 
152612b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
152712b29f34SStephen Smalley 				  u32 *sid)
152812b29f34SStephen Smalley {
152912b29f34SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
153012b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1531f5c1d5b2SJames Morris }
1532f5c1d5b2SJames Morris 
15331da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
15341da177e4SLinus Torvalds 	struct context *scontext,
15351da177e4SLinus Torvalds 	struct context *tcontext,
15361da177e4SLinus Torvalds 	u16 tclass,
15371da177e4SLinus Torvalds 	struct context *newcontext)
15381da177e4SLinus Torvalds {
15391da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
15401da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
15411da177e4SLinus Torvalds 
15424b02b524SEric Paris 	if (context_struct_to_string(scontext, &s, &slen))
15431da177e4SLinus Torvalds 		goto out;
15444b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
15451da177e4SLinus Torvalds 		goto out;
15464b02b524SEric Paris 	if (context_struct_to_string(newcontext, &n, &nlen))
15471da177e4SLinus Torvalds 		goto out;
15489ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
15494093a844SRichard Guy Briggs 		  "op=security_compute_sid invalid_context=%s"
15504093a844SRichard Guy Briggs 		  " scontext=%s"
15511da177e4SLinus Torvalds 		  " tcontext=%s"
15521da177e4SLinus Torvalds 		  " tclass=%s",
1553ac76c05bSEric Paris 		  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
15541da177e4SLinus Torvalds out:
15551da177e4SLinus Torvalds 	kfree(s);
15561da177e4SLinus Torvalds 	kfree(t);
15571da177e4SLinus Torvalds 	kfree(n);
15581da177e4SLinus Torvalds 	if (!selinux_enforcing)
15591da177e4SLinus Torvalds 		return 0;
15601da177e4SLinus Torvalds 	return -EACCES;
15611da177e4SLinus Torvalds }
15621da177e4SLinus Torvalds 
1563652bb9b0SEric Paris static void filename_compute_type(struct policydb *p, struct context *newcontext,
15642667991fSEric Paris 				  u32 stype, u32 ttype, u16 tclass,
1565f50a3ec9SKohei Kaigai 				  const char *objname)
1566652bb9b0SEric Paris {
15672463c26dSEric Paris 	struct filename_trans ft;
15682463c26dSEric Paris 	struct filename_trans_datum *otype;
156903a4c018SEric Paris 
157003a4c018SEric Paris 	/*
157103a4c018SEric Paris 	 * Most filename trans rules are going to live in specific directories
157203a4c018SEric Paris 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
157303a4c018SEric Paris 	 * if the ttype does not contain any rules.
157403a4c018SEric Paris 	 */
157503a4c018SEric Paris 	if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
1576652bb9b0SEric Paris 		return;
157703a4c018SEric Paris 
15782463c26dSEric Paris 	ft.stype = stype;
15792463c26dSEric Paris 	ft.ttype = ttype;
15802463c26dSEric Paris 	ft.tclass = tclass;
15812463c26dSEric Paris 	ft.name = objname;
15822463c26dSEric Paris 
15832463c26dSEric Paris 	otype = hashtab_search(p->filename_trans, &ft);
15842463c26dSEric Paris 	if (otype)
15852463c26dSEric Paris 		newcontext->type = otype->otype;
1586652bb9b0SEric Paris }
1587652bb9b0SEric Paris 
15881da177e4SLinus Torvalds static int security_compute_sid(u32 ssid,
15891da177e4SLinus Torvalds 				u32 tsid,
1590c6d3aaa4SStephen Smalley 				u16 orig_tclass,
15911da177e4SLinus Torvalds 				u32 specified,
1592f50a3ec9SKohei Kaigai 				const char *objname,
1593c6d3aaa4SStephen Smalley 				u32 *out_sid,
1594c6d3aaa4SStephen Smalley 				bool kern)
15951da177e4SLinus Torvalds {
1596aa893269SEric Paris 	struct class_datum *cladatum = NULL;
15971da177e4SLinus Torvalds 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
15981da177e4SLinus Torvalds 	struct role_trans *roletr = NULL;
15991da177e4SLinus Torvalds 	struct avtab_key avkey;
16001da177e4SLinus Torvalds 	struct avtab_datum *avdatum;
16011da177e4SLinus Torvalds 	struct avtab_node *node;
1602c6d3aaa4SStephen Smalley 	u16 tclass;
16031da177e4SLinus Torvalds 	int rc = 0;
16046f5317e7SHarry Ciao 	bool sock;
16051da177e4SLinus Torvalds 
16061da177e4SLinus Torvalds 	if (!ss_initialized) {
1607c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1608c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
16091da177e4SLinus Torvalds 			*out_sid = ssid;
16101da177e4SLinus Torvalds 			break;
16111da177e4SLinus Torvalds 		default:
16121da177e4SLinus Torvalds 			*out_sid = tsid;
16131da177e4SLinus Torvalds 			break;
16141da177e4SLinus Torvalds 		}
16151da177e4SLinus Torvalds 		goto out;
16161da177e4SLinus Torvalds 	}
16171da177e4SLinus Torvalds 
1618851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1619851f8a69SVenkat Yekkirala 
16200804d113SJames Morris 	read_lock(&policy_rwlock);
16211da177e4SLinus Torvalds 
16226f5317e7SHarry Ciao 	if (kern) {
1623c6d3aaa4SStephen Smalley 		tclass = unmap_class(orig_tclass);
16246f5317e7SHarry Ciao 		sock = security_is_socket_class(orig_tclass);
16256f5317e7SHarry Ciao 	} else {
1626c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
16276f5317e7SHarry Ciao 		sock = security_is_socket_class(map_class(tclass));
16286f5317e7SHarry Ciao 	}
1629c6d3aaa4SStephen Smalley 
16301da177e4SLinus Torvalds 	scontext = sidtab_search(&sidtab, ssid);
16311da177e4SLinus Torvalds 	if (!scontext) {
1632744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1633744ba35eSEric Paris 		       __func__, ssid);
16341da177e4SLinus Torvalds 		rc = -EINVAL;
16351da177e4SLinus Torvalds 		goto out_unlock;
16361da177e4SLinus Torvalds 	}
16371da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tsid);
16381da177e4SLinus Torvalds 	if (!tcontext) {
1639744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1640744ba35eSEric Paris 		       __func__, tsid);
16411da177e4SLinus Torvalds 		rc = -EINVAL;
16421da177e4SLinus Torvalds 		goto out_unlock;
16431da177e4SLinus Torvalds 	}
16441da177e4SLinus Torvalds 
1645aa893269SEric Paris 	if (tclass && tclass <= policydb.p_classes.nprim)
1646aa893269SEric Paris 		cladatum = policydb.class_val_to_struct[tclass - 1];
1647aa893269SEric Paris 
16481da177e4SLinus Torvalds 	/* Set the user identity. */
16491da177e4SLinus Torvalds 	switch (specified) {
16501da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
16511da177e4SLinus Torvalds 	case AVTAB_CHANGE:
1652aa893269SEric Paris 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1653aa893269SEric Paris 			newcontext.user = tcontext->user;
1654aa893269SEric Paris 		} else {
1655aa893269SEric Paris 			/* notice this gets both DEFAULT_SOURCE and unset */
16561da177e4SLinus Torvalds 			/* Use the process user identity. */
16571da177e4SLinus Torvalds 			newcontext.user = scontext->user;
1658aa893269SEric Paris 		}
16591da177e4SLinus Torvalds 		break;
16601da177e4SLinus Torvalds 	case AVTAB_MEMBER:
16611da177e4SLinus Torvalds 		/* Use the related object owner. */
16621da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
16631da177e4SLinus Torvalds 		break;
16641da177e4SLinus Torvalds 	}
16651da177e4SLinus Torvalds 
1666aa893269SEric Paris 	/* Set the role to default values. */
1667aa893269SEric Paris 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
16681da177e4SLinus Torvalds 		newcontext.role = scontext->role;
1669aa893269SEric Paris 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1670aa893269SEric Paris 		newcontext.role = tcontext->role;
1671aa893269SEric Paris 	} else {
1672aa893269SEric Paris 		if ((tclass == policydb.process_class) || (sock == true))
1673aa893269SEric Paris 			newcontext.role = scontext->role;
1674aa893269SEric Paris 		else
1675aa893269SEric Paris 			newcontext.role = OBJECT_R_VAL;
1676aa893269SEric Paris 	}
1677aa893269SEric Paris 
1678aa893269SEric Paris 	/* Set the type to default values. */
1679eed7795dSEric Paris 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1680eed7795dSEric Paris 		newcontext.type = scontext->type;
1681eed7795dSEric Paris 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1682eed7795dSEric Paris 		newcontext.type = tcontext->type;
1683eed7795dSEric Paris 	} else {
1684aa893269SEric Paris 		if ((tclass == policydb.process_class) || (sock == true)) {
1685aa893269SEric Paris 			/* Use the type of process. */
16861da177e4SLinus Torvalds 			newcontext.type = scontext->type;
1687c6d3aaa4SStephen Smalley 		} else {
16881da177e4SLinus Torvalds 			/* Use the type of the related object. */
16891da177e4SLinus Torvalds 			newcontext.type = tcontext->type;
16901da177e4SLinus Torvalds 		}
1691eed7795dSEric Paris 	}
16921da177e4SLinus Torvalds 
16931da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
16941da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
16951da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
16961da177e4SLinus Torvalds 	avkey.target_class = tclass;
1697782ebb99SStephen Smalley 	avkey.specified = specified;
1698782ebb99SStephen Smalley 	avdatum = avtab_search(&policydb.te_avtab, &avkey);
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
17011da177e4SLinus Torvalds 	if (!avdatum) {
1702782ebb99SStephen Smalley 		node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
1703dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1704782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
17051da177e4SLinus Torvalds 				avdatum = &node->datum;
17061da177e4SLinus Torvalds 				break;
17071da177e4SLinus Torvalds 			}
17081da177e4SLinus Torvalds 		}
17091da177e4SLinus Torvalds 	}
17101da177e4SLinus Torvalds 
1711782ebb99SStephen Smalley 	if (avdatum) {
17121da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
1713fa1aa143SJeff Vander Stoep 		newcontext.type = avdatum->u.data;
17141da177e4SLinus Torvalds 	}
17151da177e4SLinus Torvalds 
17164742600cSEric Paris 	/* if we have a objname this is a file trans check so check those rules */
1717f50a3ec9SKohei Kaigai 	if (objname)
1718652bb9b0SEric Paris 		filename_compute_type(&policydb, &newcontext, scontext->type,
1719f50a3ec9SKohei Kaigai 				      tcontext->type, tclass, objname);
1720652bb9b0SEric Paris 
17211da177e4SLinus Torvalds 	/* Check for class-specific changes. */
17221da177e4SLinus Torvalds 	if (specified & AVTAB_TRANSITION) {
17231da177e4SLinus Torvalds 		/* Look for a role transition rule. */
172463a312caSHarry Ciao 		for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
172563a312caSHarry Ciao 			if ((roletr->role == scontext->role) &&
172663a312caSHarry Ciao 			    (roletr->type == tcontext->type) &&
172763a312caSHarry Ciao 			    (roletr->tclass == tclass)) {
17281da177e4SLinus Torvalds 				/* Use the role transition rule. */
17291da177e4SLinus Torvalds 				newcontext.role = roletr->new_role;
17301da177e4SLinus Torvalds 				break;
17311da177e4SLinus Torvalds 			}
17321da177e4SLinus Torvalds 		}
17331da177e4SLinus Torvalds 	}
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	/* Set the MLS attributes.
17361da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
17376f5317e7SHarry Ciao 	rc = mls_compute_sid(scontext, tcontext, tclass, specified,
17386f5317e7SHarry Ciao 			     &newcontext, sock);
17391da177e4SLinus Torvalds 	if (rc)
17401da177e4SLinus Torvalds 		goto out_unlock;
17411da177e4SLinus Torvalds 
17421da177e4SLinus Torvalds 	/* Check the validity of the context. */
17431da177e4SLinus Torvalds 	if (!policydb_context_isvalid(&policydb, &newcontext)) {
17441da177e4SLinus Torvalds 		rc = compute_sid_handle_invalid_context(scontext,
17451da177e4SLinus Torvalds 							tcontext,
17461da177e4SLinus Torvalds 							tclass,
17471da177e4SLinus Torvalds 							&newcontext);
17481da177e4SLinus Torvalds 		if (rc)
17491da177e4SLinus Torvalds 			goto out_unlock;
17501da177e4SLinus Torvalds 	}
17511da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
17521da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
17531da177e4SLinus Torvalds out_unlock:
17540804d113SJames Morris 	read_unlock(&policy_rwlock);
17551da177e4SLinus Torvalds 	context_destroy(&newcontext);
17561da177e4SLinus Torvalds out:
17571da177e4SLinus Torvalds 	return rc;
17581da177e4SLinus Torvalds }
17591da177e4SLinus Torvalds 
17601da177e4SLinus Torvalds /**
17611da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
17621da177e4SLinus Torvalds  * @ssid: source security identifier
17631da177e4SLinus Torvalds  * @tsid: target security identifier
17641da177e4SLinus Torvalds  * @tclass: target security class
17651da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
17661da177e4SLinus Torvalds  *
17671da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
17681da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
17691da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
17701da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
17711da177e4SLinus Torvalds  * computed successfully.
17721da177e4SLinus Torvalds  */
1773652bb9b0SEric Paris int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1774652bb9b0SEric Paris 			    const struct qstr *qstr, u32 *out_sid)
17751da177e4SLinus Torvalds {
1776c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1777f50a3ec9SKohei Kaigai 				    qstr ? qstr->name : NULL, out_sid, true);
1778c6d3aaa4SStephen Smalley }
1779c6d3aaa4SStephen Smalley 
1780f50a3ec9SKohei Kaigai int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1781f50a3ec9SKohei Kaigai 				 const char *objname, u32 *out_sid)
1782c6d3aaa4SStephen Smalley {
1783c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1784f50a3ec9SKohei Kaigai 				    objname, out_sid, false);
17851da177e4SLinus Torvalds }
17861da177e4SLinus Torvalds 
17871da177e4SLinus Torvalds /**
17881da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
17891da177e4SLinus Torvalds  * @ssid: source security identifier
17901da177e4SLinus Torvalds  * @tsid: target security identifier
17911da177e4SLinus Torvalds  * @tclass: target security class
17921da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
17931da177e4SLinus Torvalds  *
17941da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
17951da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
17961da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
17971da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
17981da177e4SLinus Torvalds  * computed successfully.
17991da177e4SLinus Torvalds  */
18001da177e4SLinus Torvalds int security_member_sid(u32 ssid,
18011da177e4SLinus Torvalds 			u32 tsid,
18021da177e4SLinus Torvalds 			u16 tclass,
18031da177e4SLinus Torvalds 			u32 *out_sid)
18041da177e4SLinus Torvalds {
1805652bb9b0SEric Paris 	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL,
1806652bb9b0SEric Paris 				    out_sid, false);
18071da177e4SLinus Torvalds }
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds /**
18101da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
18111da177e4SLinus Torvalds  * @ssid: source security identifier
18121da177e4SLinus Torvalds  * @tsid: target security identifier
18131da177e4SLinus Torvalds  * @tclass: target security class
18141da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
18151da177e4SLinus Torvalds  *
18161da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
18171da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
18181da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18191da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
18201da177e4SLinus Torvalds  * computed successfully.
18211da177e4SLinus Torvalds  */
18221da177e4SLinus Torvalds int security_change_sid(u32 ssid,
18231da177e4SLinus Torvalds 			u32 tsid,
18241da177e4SLinus Torvalds 			u16 tclass,
18251da177e4SLinus Torvalds 			u32 *out_sid)
18261da177e4SLinus Torvalds {
1827652bb9b0SEric Paris 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1828652bb9b0SEric Paris 				    out_sid, false);
1829b94c7e67SChad Sellers }
1830b94c7e67SChad Sellers 
18311da177e4SLinus Torvalds /* Clone the SID into the new SID table. */
18321da177e4SLinus Torvalds static int clone_sid(u32 sid,
18331da177e4SLinus Torvalds 		     struct context *context,
18341da177e4SLinus Torvalds 		     void *arg)
18351da177e4SLinus Torvalds {
18361da177e4SLinus Torvalds 	struct sidtab *s = arg;
18371da177e4SLinus Torvalds 
183842596eafSGuido Trentalancia 	if (sid > SECINITSID_NUM)
18391da177e4SLinus Torvalds 		return sidtab_insert(s, sid, context);
184042596eafSGuido Trentalancia 	else
184142596eafSGuido Trentalancia 		return 0;
18421da177e4SLinus Torvalds }
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context)
18451da177e4SLinus Torvalds {
18461da177e4SLinus Torvalds 	char *s;
18471da177e4SLinus Torvalds 	u32 len;
18481da177e4SLinus Torvalds 
18494b02b524SEric Paris 	if (selinux_enforcing)
18504b02b524SEric Paris 		return -EINVAL;
18514b02b524SEric Paris 
185212b29f34SStephen Smalley 	if (!context_struct_to_string(context, &s, &len)) {
18534b02b524SEric Paris 		printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
18541da177e4SLinus Torvalds 		kfree(s);
18551da177e4SLinus Torvalds 	}
18564b02b524SEric Paris 	return 0;
18571da177e4SLinus Torvalds }
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds struct convert_context_args {
18601da177e4SLinus Torvalds 	struct policydb *oldp;
18611da177e4SLinus Torvalds 	struct policydb *newp;
18621da177e4SLinus Torvalds };
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds /*
18651da177e4SLinus Torvalds  * Convert the values in the security context
18661da177e4SLinus Torvalds  * structure `c' from the values specified
18671da177e4SLinus Torvalds  * in the policy `p->oldp' to the values specified
18681da177e4SLinus Torvalds  * in the policy `p->newp'.  Verify that the
18691da177e4SLinus Torvalds  * context is valid under the new policy.
18701da177e4SLinus Torvalds  */
18711da177e4SLinus Torvalds static int convert_context(u32 key,
18721da177e4SLinus Torvalds 			   struct context *c,
18731da177e4SLinus Torvalds 			   void *p)
18741da177e4SLinus Torvalds {
18751da177e4SLinus Torvalds 	struct convert_context_args *args;
18761da177e4SLinus Torvalds 	struct context oldc;
18770719aaf5SGuido Trentalancia 	struct ocontext *oc;
18780719aaf5SGuido Trentalancia 	struct mls_range *range;
18791da177e4SLinus Torvalds 	struct role_datum *role;
18801da177e4SLinus Torvalds 	struct type_datum *typdatum;
18811da177e4SLinus Torvalds 	struct user_datum *usrdatum;
18821da177e4SLinus Torvalds 	char *s;
18831da177e4SLinus Torvalds 	u32 len;
188442596eafSGuido Trentalancia 	int rc = 0;
188542596eafSGuido Trentalancia 
188642596eafSGuido Trentalancia 	if (key <= SECINITSID_NUM)
188742596eafSGuido Trentalancia 		goto out;
18881da177e4SLinus Torvalds 
18891da177e4SLinus Torvalds 	args = p;
18901da177e4SLinus Torvalds 
189112b29f34SStephen Smalley 	if (c->str) {
189212b29f34SStephen Smalley 		struct context ctx;
18934b02b524SEric Paris 
18949a59daa0SStephen Smalley 		rc = -ENOMEM;
18954b02b524SEric Paris 		s = kstrdup(c->str, GFP_KERNEL);
18964b02b524SEric Paris 		if (!s)
18979a59daa0SStephen Smalley 			goto out;
18984b02b524SEric Paris 
18999a59daa0SStephen Smalley 		rc = string_to_context_struct(args->newp, NULL, s,
19009a59daa0SStephen Smalley 					      c->len, &ctx, SECSID_NULL);
19019a59daa0SStephen Smalley 		kfree(s);
190212b29f34SStephen Smalley 		if (!rc) {
19034b02b524SEric Paris 			printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
190412b29f34SStephen Smalley 			       c->str);
190512b29f34SStephen Smalley 			/* Replace string with mapped representation. */
190612b29f34SStephen Smalley 			kfree(c->str);
190712b29f34SStephen Smalley 			memcpy(c, &ctx, sizeof(*c));
190812b29f34SStephen Smalley 			goto out;
190912b29f34SStephen Smalley 		} else if (rc == -EINVAL) {
191012b29f34SStephen Smalley 			/* Retain string representation for later mapping. */
191112b29f34SStephen Smalley 			rc = 0;
191212b29f34SStephen Smalley 			goto out;
191312b29f34SStephen Smalley 		} else {
191412b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
19154b02b524SEric Paris 			printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
191612b29f34SStephen Smalley 			       c->str, -rc);
191712b29f34SStephen Smalley 			goto out;
191812b29f34SStephen Smalley 		}
191912b29f34SStephen Smalley 	}
192012b29f34SStephen Smalley 
19211da177e4SLinus Torvalds 	rc = context_cpy(&oldc, c);
19221da177e4SLinus Torvalds 	if (rc)
19231da177e4SLinus Torvalds 		goto out;
19241da177e4SLinus Torvalds 
19251da177e4SLinus Torvalds 	/* Convert the user. */
19264b02b524SEric Paris 	rc = -EINVAL;
19271da177e4SLinus Torvalds 	usrdatum = hashtab_search(args->newp->p_users.table,
1928ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_USERS, c->user - 1));
19295d55a345SEric Paris 	if (!usrdatum)
19301da177e4SLinus Torvalds 		goto bad;
19311da177e4SLinus Torvalds 	c->user = usrdatum->value;
19321da177e4SLinus Torvalds 
19331da177e4SLinus Torvalds 	/* Convert the role. */
19344b02b524SEric Paris 	rc = -EINVAL;
19351da177e4SLinus Torvalds 	role = hashtab_search(args->newp->p_roles.table,
1936ac76c05bSEric Paris 			      sym_name(args->oldp, SYM_ROLES, c->role - 1));
19375d55a345SEric Paris 	if (!role)
19381da177e4SLinus Torvalds 		goto bad;
19391da177e4SLinus Torvalds 	c->role = role->value;
19401da177e4SLinus Torvalds 
19411da177e4SLinus Torvalds 	/* Convert the type. */
19424b02b524SEric Paris 	rc = -EINVAL;
19431da177e4SLinus Torvalds 	typdatum = hashtab_search(args->newp->p_types.table,
1944ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_TYPES, c->type - 1));
19455d55a345SEric Paris 	if (!typdatum)
19461da177e4SLinus Torvalds 		goto bad;
19471da177e4SLinus Torvalds 	c->type = typdatum->value;
19481da177e4SLinus Torvalds 
19490719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
19500719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
19511da177e4SLinus Torvalds 		rc = mls_convert_context(args->oldp, args->newp, c);
19521da177e4SLinus Torvalds 		if (rc)
19531da177e4SLinus Torvalds 			goto bad;
19540719aaf5SGuido Trentalancia 	} else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
19550719aaf5SGuido Trentalancia 		/*
19560719aaf5SGuido Trentalancia 		 * Switching between MLS and non-MLS policy:
19570719aaf5SGuido Trentalancia 		 * free any storage used by the MLS fields in the
19580719aaf5SGuido Trentalancia 		 * context for all existing entries in the sidtab.
19590719aaf5SGuido Trentalancia 		 */
19600719aaf5SGuido Trentalancia 		mls_context_destroy(c);
19610719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
19620719aaf5SGuido Trentalancia 		/*
19630719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
19640719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
19650719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
19660719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
19670719aaf5SGuido Trentalancia 		 * initial SIDs.
19680719aaf5SGuido Trentalancia 		 */
19690719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
19700719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
19710719aaf5SGuido Trentalancia 			oc = oc->next;
19724b02b524SEric Paris 		rc = -EINVAL;
19730719aaf5SGuido Trentalancia 		if (!oc) {
19740719aaf5SGuido Trentalancia 			printk(KERN_ERR "SELinux:  unable to look up"
19750719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
19760719aaf5SGuido Trentalancia 			goto bad;
19770719aaf5SGuido Trentalancia 		}
19780719aaf5SGuido Trentalancia 		range = &oc->context[0].range;
19790719aaf5SGuido Trentalancia 		rc = mls_range_set(c, range);
19800719aaf5SGuido Trentalancia 		if (rc)
19810719aaf5SGuido Trentalancia 			goto bad;
19820719aaf5SGuido Trentalancia 	}
19831da177e4SLinus Torvalds 
19841da177e4SLinus Torvalds 	/* Check the validity of the new context. */
19851da177e4SLinus Torvalds 	if (!policydb_context_isvalid(args->newp, c)) {
19861da177e4SLinus Torvalds 		rc = convert_context_handle_invalid_context(&oldc);
19871da177e4SLinus Torvalds 		if (rc)
19881da177e4SLinus Torvalds 			goto bad;
19891da177e4SLinus Torvalds 	}
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	context_destroy(&oldc);
19924b02b524SEric Paris 
199312b29f34SStephen Smalley 	rc = 0;
19941da177e4SLinus Torvalds out:
19951da177e4SLinus Torvalds 	return rc;
19961da177e4SLinus Torvalds bad:
199712b29f34SStephen Smalley 	/* Map old representation to string and save it. */
19984b02b524SEric Paris 	rc = context_struct_to_string(&oldc, &s, &len);
19994b02b524SEric Paris 	if (rc)
20004b02b524SEric Paris 		return rc;
20011da177e4SLinus Torvalds 	context_destroy(&oldc);
200212b29f34SStephen Smalley 	context_destroy(c);
200312b29f34SStephen Smalley 	c->str = s;
200412b29f34SStephen Smalley 	c->len = len;
20054b02b524SEric Paris 	printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
200612b29f34SStephen Smalley 	       c->str);
200712b29f34SStephen Smalley 	rc = 0;
20081da177e4SLinus Torvalds 	goto out;
20091da177e4SLinus Torvalds }
20101da177e4SLinus Torvalds 
20113bb56b25SPaul Moore static void security_load_policycaps(void)
20123bb56b25SPaul Moore {
20133bb56b25SPaul Moore 	selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
20143bb56b25SPaul Moore 						  POLICYDB_CAPABILITY_NETPEER);
2015b0c636b9SEric Paris 	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
2016b0c636b9SEric Paris 						  POLICYDB_CAPABILITY_OPENPERM);
20172be4d74fSChris PeBenito 	selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
20182be4d74fSChris PeBenito 						  POLICYDB_CAPABILITY_ALWAYSNETWORK);
20193bb56b25SPaul Moore }
20203bb56b25SPaul Moore 
2021e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p);
20221da177e4SLinus Torvalds 
20231da177e4SLinus Torvalds /**
20241da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
20251da177e4SLinus Torvalds  * @data: binary policy data
20261da177e4SLinus Torvalds  * @len: length of data in bytes
20271da177e4SLinus Torvalds  *
20281da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
20291da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
20301da177e4SLinus Torvalds  * This function will flush the access vector cache after
20311da177e4SLinus Torvalds  * loading the new policy.
20321da177e4SLinus Torvalds  */
20331da177e4SLinus Torvalds int security_load_policy(void *data, size_t len)
20341da177e4SLinus Torvalds {
2035b5495b42STim Gardner 	struct policydb *oldpolicydb, *newpolicydb;
20361da177e4SLinus Torvalds 	struct sidtab oldsidtab, newsidtab;
2037c6d3aaa4SStephen Smalley 	struct selinux_mapping *oldmap, *map = NULL;
20381da177e4SLinus Torvalds 	struct convert_context_args args;
20391da177e4SLinus Torvalds 	u32 seqno;
2040c6d3aaa4SStephen Smalley 	u16 map_size;
20411da177e4SLinus Torvalds 	int rc = 0;
20421da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
20431da177e4SLinus Torvalds 
2044b5495b42STim Gardner 	oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
2045b5495b42STim Gardner 	if (!oldpolicydb) {
2046b5495b42STim Gardner 		rc = -ENOMEM;
2047b5495b42STim Gardner 		goto out;
2048b5495b42STim Gardner 	}
2049b5495b42STim Gardner 	newpolicydb = oldpolicydb + 1;
2050b5495b42STim Gardner 
20511da177e4SLinus Torvalds 	if (!ss_initialized) {
20521da177e4SLinus Torvalds 		avtab_cache_init();
2053a2000050SEric Paris 		rc = policydb_read(&policydb, fp);
2054a2000050SEric Paris 		if (rc) {
20551da177e4SLinus Torvalds 			avtab_cache_destroy();
2056b5495b42STim Gardner 			goto out;
20571da177e4SLinus Torvalds 		}
2058a2000050SEric Paris 
2059cee74f47SEric Paris 		policydb.len = len;
2060a2000050SEric Paris 		rc = selinux_set_mapping(&policydb, secclass_map,
2061c6d3aaa4SStephen Smalley 					 &current_mapping,
2062a2000050SEric Paris 					 &current_mapping_size);
2063a2000050SEric Paris 		if (rc) {
20641da177e4SLinus Torvalds 			policydb_destroy(&policydb);
20651da177e4SLinus Torvalds 			avtab_cache_destroy();
2066b5495b42STim Gardner 			goto out;
20671da177e4SLinus Torvalds 		}
2068a2000050SEric Paris 
2069a2000050SEric Paris 		rc = policydb_load_isids(&policydb, &sidtab);
2070a2000050SEric Paris 		if (rc) {
2071b94c7e67SChad Sellers 			policydb_destroy(&policydb);
2072b94c7e67SChad Sellers 			avtab_cache_destroy();
2073b5495b42STim Gardner 			goto out;
2074b94c7e67SChad Sellers 		}
2075a2000050SEric Paris 
20763bb56b25SPaul Moore 		security_load_policycaps();
20771da177e4SLinus Torvalds 		ss_initialized = 1;
20784c443d1bSStephen Smalley 		seqno = ++latest_granting;
20791da177e4SLinus Torvalds 		selinux_complete_init();
20804c443d1bSStephen Smalley 		avc_ss_reset(seqno);
20814c443d1bSStephen Smalley 		selnl_notify_policyload(seqno);
208211904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
20837420ed23SVenkat Yekkirala 		selinux_netlbl_cache_invalidate();
2084342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
2085b5495b42STim Gardner 		goto out;
20861da177e4SLinus Torvalds 	}
20871da177e4SLinus Torvalds 
20881da177e4SLinus Torvalds #if 0
20891da177e4SLinus Torvalds 	sidtab_hash_eval(&sidtab, "sids");
20901da177e4SLinus Torvalds #endif
20911da177e4SLinus Torvalds 
2092b5495b42STim Gardner 	rc = policydb_read(newpolicydb, fp);
2093a2000050SEric Paris 	if (rc)
2094b5495b42STim Gardner 		goto out;
20951da177e4SLinus Torvalds 
2096b5495b42STim Gardner 	newpolicydb->len = len;
20970719aaf5SGuido Trentalancia 	/* If switching between different policy types, log MLS status */
2098b5495b42STim Gardner 	if (policydb.mls_enabled && !newpolicydb->mls_enabled)
20990719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Disabling MLS support...\n");
2100b5495b42STim Gardner 	else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
21010719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Enabling MLS support...\n");
21020719aaf5SGuido Trentalancia 
2103b5495b42STim Gardner 	rc = policydb_load_isids(newpolicydb, &newsidtab);
210442596eafSGuido Trentalancia 	if (rc) {
210542596eafSGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
2106b5495b42STim Gardner 		policydb_destroy(newpolicydb);
2107b5495b42STim Gardner 		goto out;
210812b29f34SStephen Smalley 	}
21091da177e4SLinus Torvalds 
2110b5495b42STim Gardner 	rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
2111a2000050SEric Paris 	if (rc)
2112b94c7e67SChad Sellers 		goto err;
2113b94c7e67SChad Sellers 
2114b5495b42STim Gardner 	rc = security_preserve_bools(newpolicydb);
2115e900a7d9SStephen Smalley 	if (rc) {
2116454d972cSJames Morris 		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");
2117e900a7d9SStephen Smalley 		goto err;
2118e900a7d9SStephen Smalley 	}
2119e900a7d9SStephen Smalley 
21201da177e4SLinus Torvalds 	/* Clone the SID table. */
21211da177e4SLinus Torvalds 	sidtab_shutdown(&sidtab);
2122a2000050SEric Paris 
2123a2000050SEric Paris 	rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
2124a2000050SEric Paris 	if (rc)
21251da177e4SLinus Torvalds 		goto err;
21261da177e4SLinus Torvalds 
212712b29f34SStephen Smalley 	/*
212812b29f34SStephen Smalley 	 * Convert the internal representations of contexts
212912b29f34SStephen Smalley 	 * in the new SID table.
213012b29f34SStephen Smalley 	 */
21311da177e4SLinus Torvalds 	args.oldp = &policydb;
2132b5495b42STim Gardner 	args.newp = newpolicydb;
213312b29f34SStephen Smalley 	rc = sidtab_map(&newsidtab, convert_context, &args);
21340719aaf5SGuido Trentalancia 	if (rc) {
21350719aaf5SGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to convert the internal"
21360719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
21370719aaf5SGuido Trentalancia 			" table\n");
213812b29f34SStephen Smalley 		goto err;
21390719aaf5SGuido Trentalancia 	}
21401da177e4SLinus Torvalds 
21411da177e4SLinus Torvalds 	/* Save the old policydb and SID table to free later. */
2142b5495b42STim Gardner 	memcpy(oldpolicydb, &policydb, sizeof(policydb));
21431da177e4SLinus Torvalds 	sidtab_set(&oldsidtab, &sidtab);
21441da177e4SLinus Torvalds 
21451da177e4SLinus Torvalds 	/* Install the new policydb and SID table. */
21460804d113SJames Morris 	write_lock_irq(&policy_rwlock);
2147b5495b42STim Gardner 	memcpy(&policydb, newpolicydb, sizeof(policydb));
21481da177e4SLinus Torvalds 	sidtab_set(&sidtab, &newsidtab);
21493bb56b25SPaul Moore 	security_load_policycaps();
2150c6d3aaa4SStephen Smalley 	oldmap = current_mapping;
2151c6d3aaa4SStephen Smalley 	current_mapping = map;
2152c6d3aaa4SStephen Smalley 	current_mapping_size = map_size;
21531da177e4SLinus Torvalds 	seqno = ++latest_granting;
21540804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
21551da177e4SLinus Torvalds 
21561da177e4SLinus Torvalds 	/* Free the old policydb and SID table. */
2157b5495b42STim Gardner 	policydb_destroy(oldpolicydb);
21581da177e4SLinus Torvalds 	sidtab_destroy(&oldsidtab);
2159c6d3aaa4SStephen Smalley 	kfree(oldmap);
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	avc_ss_reset(seqno);
21621da177e4SLinus Torvalds 	selnl_notify_policyload(seqno);
216311904167SKaiGai Kohei 	selinux_status_update_policyload(seqno);
21647420ed23SVenkat Yekkirala 	selinux_netlbl_cache_invalidate();
2165342a0cffSVenkat Yekkirala 	selinux_xfrm_notify_policyload();
21661da177e4SLinus Torvalds 
2167b5495b42STim Gardner 	rc = 0;
2168b5495b42STim Gardner 	goto out;
21691da177e4SLinus Torvalds 
21701da177e4SLinus Torvalds err:
2171c6d3aaa4SStephen Smalley 	kfree(map);
21721da177e4SLinus Torvalds 	sidtab_destroy(&newsidtab);
2173b5495b42STim Gardner 	policydb_destroy(newpolicydb);
21741da177e4SLinus Torvalds 
2175b5495b42STim Gardner out:
2176b5495b42STim Gardner 	kfree(oldpolicydb);
2177b5495b42STim Gardner 	return rc;
21781da177e4SLinus Torvalds }
21791da177e4SLinus Torvalds 
2180cee74f47SEric Paris size_t security_policydb_len(void)
2181cee74f47SEric Paris {
2182cee74f47SEric Paris 	size_t len;
2183cee74f47SEric Paris 
2184cee74f47SEric Paris 	read_lock(&policy_rwlock);
2185cee74f47SEric Paris 	len = policydb.len;
2186cee74f47SEric Paris 	read_unlock(&policy_rwlock);
2187cee74f47SEric Paris 
2188cee74f47SEric Paris 	return len;
2189cee74f47SEric Paris }
2190cee74f47SEric Paris 
21911da177e4SLinus Torvalds /**
21921da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
21931da177e4SLinus Torvalds  * @protocol: protocol number
21941da177e4SLinus Torvalds  * @port: port number
21951da177e4SLinus Torvalds  * @out_sid: security identifier
21961da177e4SLinus Torvalds  */
21973e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
21981da177e4SLinus Torvalds {
21991da177e4SLinus Torvalds 	struct ocontext *c;
22001da177e4SLinus Torvalds 	int rc = 0;
22011da177e4SLinus Torvalds 
22020804d113SJames Morris 	read_lock(&policy_rwlock);
22031da177e4SLinus Torvalds 
22041da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_PORT];
22051da177e4SLinus Torvalds 	while (c) {
22061da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
22071da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
22081da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
22091da177e4SLinus Torvalds 			break;
22101da177e4SLinus Torvalds 		c = c->next;
22111da177e4SLinus Torvalds 	}
22121da177e4SLinus Torvalds 
22131da177e4SLinus Torvalds 	if (c) {
22141da177e4SLinus Torvalds 		if (!c->sid[0]) {
22151da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
22161da177e4SLinus Torvalds 						   &c->context[0],
22171da177e4SLinus Torvalds 						   &c->sid[0]);
22181da177e4SLinus Torvalds 			if (rc)
22191da177e4SLinus Torvalds 				goto out;
22201da177e4SLinus Torvalds 		}
22211da177e4SLinus Torvalds 		*out_sid = c->sid[0];
22221da177e4SLinus Torvalds 	} else {
22231da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
22241da177e4SLinus Torvalds 	}
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds out:
22270804d113SJames Morris 	read_unlock(&policy_rwlock);
22281da177e4SLinus Torvalds 	return rc;
22291da177e4SLinus Torvalds }
22301da177e4SLinus Torvalds 
22311da177e4SLinus Torvalds /**
22321da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
22331da177e4SLinus Torvalds  * @name: interface name
22341da177e4SLinus Torvalds  * @if_sid: interface SID
22351da177e4SLinus Torvalds  */
2236e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid)
22371da177e4SLinus Torvalds {
22381da177e4SLinus Torvalds 	int rc = 0;
22391da177e4SLinus Torvalds 	struct ocontext *c;
22401da177e4SLinus Torvalds 
22410804d113SJames Morris 	read_lock(&policy_rwlock);
22421da177e4SLinus Torvalds 
22431da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_NETIF];
22441da177e4SLinus Torvalds 	while (c) {
22451da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
22461da177e4SLinus Torvalds 			break;
22471da177e4SLinus Torvalds 		c = c->next;
22481da177e4SLinus Torvalds 	}
22491da177e4SLinus Torvalds 
22501da177e4SLinus Torvalds 	if (c) {
22511da177e4SLinus Torvalds 		if (!c->sid[0] || !c->sid[1]) {
22521da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
22531da177e4SLinus Torvalds 						  &c->context[0],
22541da177e4SLinus Torvalds 						  &c->sid[0]);
22551da177e4SLinus Torvalds 			if (rc)
22561da177e4SLinus Torvalds 				goto out;
22571da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
22581da177e4SLinus Torvalds 						   &c->context[1],
22591da177e4SLinus Torvalds 						   &c->sid[1]);
22601da177e4SLinus Torvalds 			if (rc)
22611da177e4SLinus Torvalds 				goto out;
22621da177e4SLinus Torvalds 		}
22631da177e4SLinus Torvalds 		*if_sid = c->sid[0];
2264e8bfdb9dSPaul Moore 	} else
22651da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds out:
22680804d113SJames Morris 	read_unlock(&policy_rwlock);
22691da177e4SLinus Torvalds 	return rc;
22701da177e4SLinus Torvalds }
22711da177e4SLinus Torvalds 
22721da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
22731da177e4SLinus Torvalds {
22741da177e4SLinus Torvalds 	int i, fail = 0;
22751da177e4SLinus Torvalds 
22761da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
22771da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
22781da177e4SLinus Torvalds 			fail = 1;
22791da177e4SLinus Torvalds 			break;
22801da177e4SLinus Torvalds 		}
22811da177e4SLinus Torvalds 
22821da177e4SLinus Torvalds 	return !fail;
22831da177e4SLinus Torvalds }
22841da177e4SLinus Torvalds 
22851da177e4SLinus Torvalds /**
22861da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
22871da177e4SLinus Torvalds  * @domain: communication domain aka address family
22881da177e4SLinus Torvalds  * @addrp: address
22891da177e4SLinus Torvalds  * @addrlen: address length in bytes
22901da177e4SLinus Torvalds  * @out_sid: security identifier
22911da177e4SLinus Torvalds  */
22921da177e4SLinus Torvalds int security_node_sid(u16 domain,
22931da177e4SLinus Torvalds 		      void *addrp,
22941da177e4SLinus Torvalds 		      u32 addrlen,
22951da177e4SLinus Torvalds 		      u32 *out_sid)
22961da177e4SLinus Torvalds {
22974b02b524SEric Paris 	int rc;
22981da177e4SLinus Torvalds 	struct ocontext *c;
22991da177e4SLinus Torvalds 
23000804d113SJames Morris 	read_lock(&policy_rwlock);
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds 	switch (domain) {
23031da177e4SLinus Torvalds 	case AF_INET: {
23041da177e4SLinus Torvalds 		u32 addr;
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 		rc = -EINVAL;
23074b02b524SEric Paris 		if (addrlen != sizeof(u32))
23081da177e4SLinus Torvalds 			goto out;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
23111da177e4SLinus Torvalds 
23121da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE];
23131da177e4SLinus Torvalds 		while (c) {
23141da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
23151da177e4SLinus Torvalds 				break;
23161da177e4SLinus Torvalds 			c = c->next;
23171da177e4SLinus Torvalds 		}
23181da177e4SLinus Torvalds 		break;
23191da177e4SLinus Torvalds 	}
23201da177e4SLinus Torvalds 
23211da177e4SLinus Torvalds 	case AF_INET6:
23221da177e4SLinus Torvalds 		rc = -EINVAL;
23234b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
23241da177e4SLinus Torvalds 			goto out;
23251da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE6];
23261da177e4SLinus Torvalds 		while (c) {
23271da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
23281da177e4SLinus Torvalds 						c->u.node6.mask))
23291da177e4SLinus Torvalds 				break;
23301da177e4SLinus Torvalds 			c = c->next;
23311da177e4SLinus Torvalds 		}
23321da177e4SLinus Torvalds 		break;
23331da177e4SLinus Torvalds 
23341da177e4SLinus Torvalds 	default:
23354b02b524SEric Paris 		rc = 0;
23361da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
23371da177e4SLinus Torvalds 		goto out;
23381da177e4SLinus Torvalds 	}
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds 	if (c) {
23411da177e4SLinus Torvalds 		if (!c->sid[0]) {
23421da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
23431da177e4SLinus Torvalds 						   &c->context[0],
23441da177e4SLinus Torvalds 						   &c->sid[0]);
23451da177e4SLinus Torvalds 			if (rc)
23461da177e4SLinus Torvalds 				goto out;
23471da177e4SLinus Torvalds 		}
23481da177e4SLinus Torvalds 		*out_sid = c->sid[0];
23491da177e4SLinus Torvalds 	} else {
23501da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
23511da177e4SLinus Torvalds 	}
23521da177e4SLinus Torvalds 
23534b02b524SEric Paris 	rc = 0;
23541da177e4SLinus Torvalds out:
23550804d113SJames Morris 	read_unlock(&policy_rwlock);
23561da177e4SLinus Torvalds 	return rc;
23571da177e4SLinus Torvalds }
23581da177e4SLinus Torvalds 
23591da177e4SLinus Torvalds #define SIDS_NEL 25
23601da177e4SLinus Torvalds 
23611da177e4SLinus Torvalds /**
23621da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
23631da177e4SLinus Torvalds  * @fromsid: starting SID
23641da177e4SLinus Torvalds  * @username: username
23651da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
23661da177e4SLinus Torvalds  * @nel: number of elements in @sids
23671da177e4SLinus Torvalds  *
23681da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
23691da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
23701da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
23711da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
23721da177e4SLinus Torvalds  * number of elements in the array.
23731da177e4SLinus Torvalds  */
23741da177e4SLinus Torvalds 
23751da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid,
23761da177e4SLinus Torvalds 			   char *username,
23771da177e4SLinus Torvalds 			   u32 **sids,
23781da177e4SLinus Torvalds 			   u32 *nel)
23791da177e4SLinus Torvalds {
23801da177e4SLinus Torvalds 	struct context *fromcon, usercon;
23812c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
23821da177e4SLinus Torvalds 	u32 mynel = 0, maxnel = SIDS_NEL;
23831da177e4SLinus Torvalds 	struct user_datum *user;
23841da177e4SLinus Torvalds 	struct role_datum *role;
2385782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
23861da177e4SLinus Torvalds 	int rc = 0, i, j;
23871da177e4SLinus Torvalds 
23881da177e4SLinus Torvalds 	*sids = NULL;
23891da177e4SLinus Torvalds 	*nel = 0;
23902c3c05dbSStephen Smalley 
23912c3c05dbSStephen Smalley 	if (!ss_initialized)
23921da177e4SLinus Torvalds 		goto out;
23931da177e4SLinus Torvalds 
23940804d113SJames Morris 	read_lock(&policy_rwlock);
23951da177e4SLinus Torvalds 
239612b29f34SStephen Smalley 	context_init(&usercon);
239712b29f34SStephen Smalley 
23984b02b524SEric Paris 	rc = -EINVAL;
23991da177e4SLinus Torvalds 	fromcon = sidtab_search(&sidtab, fromsid);
24004b02b524SEric Paris 	if (!fromcon)
24011da177e4SLinus Torvalds 		goto out_unlock;
24021da177e4SLinus Torvalds 
24031da177e4SLinus Torvalds 	rc = -EINVAL;
24044b02b524SEric Paris 	user = hashtab_search(policydb.p_users.table, username);
24054b02b524SEric Paris 	if (!user)
24061da177e4SLinus Torvalds 		goto out_unlock;
24074b02b524SEric Paris 
24081da177e4SLinus Torvalds 	usercon.user = user->value;
24091da177e4SLinus Torvalds 
24101da177e4SLinus Torvalds 	rc = -ENOMEM;
24114b02b524SEric Paris 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
24124b02b524SEric Paris 	if (!mysids)
24131da177e4SLinus Torvalds 		goto out_unlock;
24141da177e4SLinus Torvalds 
24159fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
24161da177e4SLinus Torvalds 		role = policydb.role_val_to_struct[i];
24171da177e4SLinus Torvalds 		usercon.role = i + 1;
24189fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
24191da177e4SLinus Torvalds 			usercon.type = j + 1;
24201da177e4SLinus Torvalds 
24211da177e4SLinus Torvalds 			if (mls_setup_user_range(fromcon, user, &usercon))
24221da177e4SLinus Torvalds 				continue;
24231da177e4SLinus Torvalds 
24241da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
24252c3c05dbSStephen Smalley 			if (rc)
24261da177e4SLinus Torvalds 				goto out_unlock;
24271da177e4SLinus Torvalds 			if (mynel < maxnel) {
24281da177e4SLinus Torvalds 				mysids[mynel++] = sid;
24291da177e4SLinus Torvalds 			} else {
24304b02b524SEric Paris 				rc = -ENOMEM;
24311da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
243289d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
24334b02b524SEric Paris 				if (!mysids2)
24341da177e4SLinus Torvalds 					goto out_unlock;
24351da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
24361da177e4SLinus Torvalds 				kfree(mysids);
24371da177e4SLinus Torvalds 				mysids = mysids2;
24381da177e4SLinus Torvalds 				mysids[mynel++] = sid;
24391da177e4SLinus Torvalds 			}
24401da177e4SLinus Torvalds 		}
24411da177e4SLinus Torvalds 	}
24424b02b524SEric Paris 	rc = 0;
24431da177e4SLinus Torvalds out_unlock:
24440804d113SJames Morris 	read_unlock(&policy_rwlock);
24452c3c05dbSStephen Smalley 	if (rc || !mynel) {
24462c3c05dbSStephen Smalley 		kfree(mysids);
24472c3c05dbSStephen Smalley 		goto out;
24482c3c05dbSStephen Smalley 	}
24492c3c05dbSStephen Smalley 
24504b02b524SEric Paris 	rc = -ENOMEM;
24512c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
24522c3c05dbSStephen Smalley 	if (!mysids2) {
24532c3c05dbSStephen Smalley 		kfree(mysids);
24542c3c05dbSStephen Smalley 		goto out;
24552c3c05dbSStephen Smalley 	}
24562c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
2457f01e1af4SLinus Torvalds 		struct av_decision dummy_avd;
24582c3c05dbSStephen Smalley 		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2459c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
24602c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
2461f01e1af4SLinus Torvalds 					  &dummy_avd);
24622c3c05dbSStephen Smalley 		if (!rc)
24632c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
24642c3c05dbSStephen Smalley 		cond_resched();
24652c3c05dbSStephen Smalley 	}
24662c3c05dbSStephen Smalley 	rc = 0;
24672c3c05dbSStephen Smalley 	kfree(mysids);
24682c3c05dbSStephen Smalley 	*sids = mysids2;
24692c3c05dbSStephen Smalley 	*nel = j;
24701da177e4SLinus Torvalds out:
24711da177e4SLinus Torvalds 	return rc;
24721da177e4SLinus Torvalds }
24731da177e4SLinus Torvalds 
24741da177e4SLinus Torvalds /**
2475f31e7994SWaiman Long  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
24761da177e4SLinus Torvalds  * @fstype: filesystem type
24771da177e4SLinus Torvalds  * @path: path from root of mount
24781da177e4SLinus Torvalds  * @sclass: file security class
24791da177e4SLinus Torvalds  * @sid: SID for path
24801da177e4SLinus Torvalds  *
24811da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
24821da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
24831da177e4SLinus Torvalds  * transition SIDs or task SIDs.
2484f31e7994SWaiman Long  *
2485f31e7994SWaiman Long  * The caller must acquire the policy_rwlock before calling this function.
24861da177e4SLinus Torvalds  */
2487f31e7994SWaiman Long static inline int __security_genfs_sid(const char *fstype,
24881da177e4SLinus Torvalds 				       char *path,
2489c6d3aaa4SStephen Smalley 				       u16 orig_sclass,
24901da177e4SLinus Torvalds 				       u32 *sid)
24911da177e4SLinus Torvalds {
24921da177e4SLinus Torvalds 	int len;
2493c6d3aaa4SStephen Smalley 	u16 sclass;
24941da177e4SLinus Torvalds 	struct genfs *genfs;
24951da177e4SLinus Torvalds 	struct ocontext *c;
24964b02b524SEric Paris 	int rc, cmp = 0;
24971da177e4SLinus Torvalds 
2498b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2499b1aa5301SStephen Smalley 		path++;
2500b1aa5301SStephen Smalley 
2501c6d3aaa4SStephen Smalley 	sclass = unmap_class(orig_sclass);
25024b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2503c6d3aaa4SStephen Smalley 
25041da177e4SLinus Torvalds 	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
25051da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
25061da177e4SLinus Torvalds 		if (cmp <= 0)
25071da177e4SLinus Torvalds 			break;
25081da177e4SLinus Torvalds 	}
25091da177e4SLinus Torvalds 
25101da177e4SLinus Torvalds 	rc = -ENOENT;
25114b02b524SEric Paris 	if (!genfs || cmp)
25121da177e4SLinus Torvalds 		goto out;
25131da177e4SLinus Torvalds 
25141da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
25151da177e4SLinus Torvalds 		len = strlen(c->u.name);
25161da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
25171da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
25181da177e4SLinus Torvalds 			break;
25191da177e4SLinus Torvalds 	}
25201da177e4SLinus Torvalds 
25211da177e4SLinus Torvalds 	rc = -ENOENT;
25224b02b524SEric Paris 	if (!c)
25231da177e4SLinus Torvalds 		goto out;
25241da177e4SLinus Torvalds 
25251da177e4SLinus Torvalds 	if (!c->sid[0]) {
25264b02b524SEric Paris 		rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
25271da177e4SLinus Torvalds 		if (rc)
25281da177e4SLinus Torvalds 			goto out;
25291da177e4SLinus Torvalds 	}
25301da177e4SLinus Torvalds 
25311da177e4SLinus Torvalds 	*sid = c->sid[0];
25324b02b524SEric Paris 	rc = 0;
25331da177e4SLinus Torvalds out:
25341da177e4SLinus Torvalds 	return rc;
25351da177e4SLinus Torvalds }
25361da177e4SLinus Torvalds 
25371da177e4SLinus Torvalds /**
2538f31e7994SWaiman Long  * security_genfs_sid - Obtain a SID for a file in a filesystem
2539f31e7994SWaiman Long  * @fstype: filesystem type
2540f31e7994SWaiman Long  * @path: path from root of mount
2541f31e7994SWaiman Long  * @sclass: file security class
2542f31e7994SWaiman Long  * @sid: SID for path
2543f31e7994SWaiman Long  *
2544f31e7994SWaiman Long  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2545f31e7994SWaiman Long  * it afterward.
2546f31e7994SWaiman Long  */
2547f31e7994SWaiman Long int security_genfs_sid(const char *fstype,
2548f31e7994SWaiman Long 		       char *path,
2549f31e7994SWaiman Long 		       u16 orig_sclass,
2550f31e7994SWaiman Long 		       u32 *sid)
2551f31e7994SWaiman Long {
2552f31e7994SWaiman Long 	int retval;
2553f31e7994SWaiman Long 
2554f31e7994SWaiman Long 	read_lock(&policy_rwlock);
2555f31e7994SWaiman Long 	retval = __security_genfs_sid(fstype, path, orig_sclass, sid);
2556f31e7994SWaiman Long 	read_unlock(&policy_rwlock);
2557f31e7994SWaiman Long 	return retval;
2558f31e7994SWaiman Long }
2559f31e7994SWaiman Long 
2560f31e7994SWaiman Long /**
25611da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
2562a64c54cfSEric Paris  * @sb: superblock in question
25631da177e4SLinus Torvalds  */
2564a64c54cfSEric Paris int security_fs_use(struct super_block *sb)
25651da177e4SLinus Torvalds {
25661da177e4SLinus Torvalds 	int rc = 0;
25671da177e4SLinus Torvalds 	struct ocontext *c;
2568a64c54cfSEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
2569a64c54cfSEric Paris 	const char *fstype = sb->s_type->name;
25701da177e4SLinus Torvalds 
25710804d113SJames Morris 	read_lock(&policy_rwlock);
25721da177e4SLinus Torvalds 
25734d546f81SPaul Moore 	c = policydb.ocontexts[OCON_FSUSE];
25744d546f81SPaul Moore 	while (c) {
25754d546f81SPaul Moore 		if (strcmp(fstype, c->u.name) == 0)
25761da177e4SLinus Torvalds 			break;
25774d546f81SPaul Moore 		c = c->next;
25781da177e4SLinus Torvalds 	}
25791da177e4SLinus Torvalds 
25801da177e4SLinus Torvalds 	if (c) {
2581a64c54cfSEric Paris 		sbsec->behavior = c->v.behavior;
25821da177e4SLinus Torvalds 		if (!c->sid[0]) {
25834b02b524SEric Paris 			rc = sidtab_context_to_sid(&sidtab, &c->context[0],
25841da177e4SLinus Torvalds 						   &c->sid[0]);
25851da177e4SLinus Torvalds 			if (rc)
25861da177e4SLinus Torvalds 				goto out;
25871da177e4SLinus Torvalds 		}
2588a64c54cfSEric Paris 		sbsec->sid = c->sid[0];
2589089be43eSJames Morris 	} else {
2590f31e7994SWaiman Long 		rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR,
2591f31e7994SWaiman Long 					  &sbsec->sid);
25921da177e4SLinus Torvalds 		if (rc) {
2593a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_NONE;
25941da177e4SLinus Torvalds 			rc = 0;
25951da177e4SLinus Torvalds 		} else {
2596a64c54cfSEric Paris 			sbsec->behavior = SECURITY_FS_USE_GENFS;
25971da177e4SLinus Torvalds 		}
2598089be43eSJames Morris 	}
25991da177e4SLinus Torvalds 
26001da177e4SLinus Torvalds out:
26010804d113SJames Morris 	read_unlock(&policy_rwlock);
26021da177e4SLinus Torvalds 	return rc;
26031da177e4SLinus Torvalds }
26041da177e4SLinus Torvalds 
26051da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values)
26061da177e4SLinus Torvalds {
26074b02b524SEric Paris 	int i, rc;
26081da177e4SLinus Torvalds 
26090804d113SJames Morris 	read_lock(&policy_rwlock);
26101da177e4SLinus Torvalds 	*names = NULL;
26111da177e4SLinus Torvalds 	*values = NULL;
26121da177e4SLinus Torvalds 
26131da177e4SLinus Torvalds 	rc = 0;
26144b02b524SEric Paris 	*len = policydb.p_bools.nprim;
26154b02b524SEric Paris 	if (!*len)
26161da177e4SLinus Torvalds 		goto out;
26171da177e4SLinus Torvalds 
26184b02b524SEric Paris 	rc = -ENOMEM;
2619e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
26201da177e4SLinus Torvalds 	if (!*names)
26211da177e4SLinus Torvalds 		goto err;
26221da177e4SLinus Torvalds 
26234b02b524SEric Paris 	rc = -ENOMEM;
2624e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
26251da177e4SLinus Torvalds 	if (!*values)
26261da177e4SLinus Torvalds 		goto err;
26271da177e4SLinus Torvalds 
26281da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
26291da177e4SLinus Torvalds 		(*values)[i] = policydb.bool_val_to_struct[i]->state;
26304b02b524SEric Paris 
26314b02b524SEric Paris 		rc = -ENOMEM;
263221b76f19SRasmus Villemoes 		(*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
26331da177e4SLinus Torvalds 		if (!(*names)[i])
26341da177e4SLinus Torvalds 			goto err;
26351da177e4SLinus Torvalds 	}
26361da177e4SLinus Torvalds 	rc = 0;
26371da177e4SLinus Torvalds out:
26380804d113SJames Morris 	read_unlock(&policy_rwlock);
26391da177e4SLinus Torvalds 	return rc;
26401da177e4SLinus Torvalds err:
26411da177e4SLinus Torvalds 	if (*names) {
26421da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
26431da177e4SLinus Torvalds 			kfree((*names)[i]);
26441da177e4SLinus Torvalds 	}
26451da177e4SLinus Torvalds 	kfree(*values);
26461da177e4SLinus Torvalds 	goto out;
26471da177e4SLinus Torvalds }
26481da177e4SLinus Torvalds 
26491da177e4SLinus Torvalds 
26501da177e4SLinus Torvalds int security_set_bools(int len, int *values)
26511da177e4SLinus Torvalds {
26524b02b524SEric Paris 	int i, rc;
26531da177e4SLinus Torvalds 	int lenp, seqno = 0;
26541da177e4SLinus Torvalds 	struct cond_node *cur;
26551da177e4SLinus Torvalds 
26560804d113SJames Morris 	write_lock_irq(&policy_rwlock);
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds 	rc = -EFAULT;
26594b02b524SEric Paris 	lenp = policydb.p_bools.nprim;
26604b02b524SEric Paris 	if (len != lenp)
26611da177e4SLinus Torvalds 		goto out;
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
2664af601e46SSteve Grubb 		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
2665af601e46SSteve Grubb 			audit_log(current->audit_context, GFP_ATOMIC,
2666af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
26674746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
2668ac76c05bSEric Paris 				sym_name(&policydb, SYM_BOOLS, i),
2669af601e46SSteve Grubb 				!!values[i],
2670af601e46SSteve Grubb 				policydb.bool_val_to_struct[i]->state,
2671581abc09SEric W. Biederman 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
26724746ec5bSEric Paris 				audit_get_sessionid(current));
2673af601e46SSteve Grubb 		}
26745d55a345SEric Paris 		if (values[i])
26751da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 1;
26765d55a345SEric Paris 		else
26771da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 0;
26781da177e4SLinus Torvalds 	}
26791da177e4SLinus Torvalds 
2680dbc74c65SVesa-Matti Kari 	for (cur = policydb.cond_list; cur; cur = cur->next) {
26811da177e4SLinus Torvalds 		rc = evaluate_cond_node(&policydb, cur);
26821da177e4SLinus Torvalds 		if (rc)
26831da177e4SLinus Torvalds 			goto out;
26841da177e4SLinus Torvalds 	}
26851da177e4SLinus Torvalds 
26861da177e4SLinus Torvalds 	seqno = ++latest_granting;
26874b02b524SEric Paris 	rc = 0;
26881da177e4SLinus Torvalds out:
26890804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
26901da177e4SLinus Torvalds 	if (!rc) {
26911da177e4SLinus Torvalds 		avc_ss_reset(seqno);
26921da177e4SLinus Torvalds 		selnl_notify_policyload(seqno);
269311904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
2694342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
26951da177e4SLinus Torvalds 	}
26961da177e4SLinus Torvalds 	return rc;
26971da177e4SLinus Torvalds }
26981da177e4SLinus Torvalds 
26990fd71a62SPrarit Bhargava int security_get_bool_value(int index)
27001da177e4SLinus Torvalds {
27014b02b524SEric Paris 	int rc;
27021da177e4SLinus Torvalds 	int len;
27031da177e4SLinus Torvalds 
27040804d113SJames Morris 	read_lock(&policy_rwlock);
27051da177e4SLinus Torvalds 
27061da177e4SLinus Torvalds 	rc = -EFAULT;
27074b02b524SEric Paris 	len = policydb.p_bools.nprim;
27080fd71a62SPrarit Bhargava 	if (index >= len)
27091da177e4SLinus Torvalds 		goto out;
27101da177e4SLinus Torvalds 
27110fd71a62SPrarit Bhargava 	rc = policydb.bool_val_to_struct[index]->state;
27121da177e4SLinus Torvalds out:
27130804d113SJames Morris 	read_unlock(&policy_rwlock);
27141da177e4SLinus Torvalds 	return rc;
27151da177e4SLinus Torvalds }
2716376bd9cbSDarrel Goeddel 
2717e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p)
2718e900a7d9SStephen Smalley {
2719e900a7d9SStephen Smalley 	int rc, nbools = 0, *bvalues = NULL, i;
2720e900a7d9SStephen Smalley 	char **bnames = NULL;
2721e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
2722e900a7d9SStephen Smalley 	struct cond_node *cur;
2723e900a7d9SStephen Smalley 
2724e900a7d9SStephen Smalley 	rc = security_get_bools(&nbools, &bnames, &bvalues);
2725e900a7d9SStephen Smalley 	if (rc)
2726e900a7d9SStephen Smalley 		goto out;
2727e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
2728e900a7d9SStephen Smalley 		booldatum = hashtab_search(p->p_bools.table, bnames[i]);
2729e900a7d9SStephen Smalley 		if (booldatum)
2730e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
2731e900a7d9SStephen Smalley 	}
2732dbc74c65SVesa-Matti Kari 	for (cur = p->cond_list; cur; cur = cur->next) {
2733e900a7d9SStephen Smalley 		rc = evaluate_cond_node(p, cur);
2734e900a7d9SStephen Smalley 		if (rc)
2735e900a7d9SStephen Smalley 			goto out;
2736e900a7d9SStephen Smalley 	}
2737e900a7d9SStephen Smalley 
2738e900a7d9SStephen Smalley out:
2739e900a7d9SStephen Smalley 	if (bnames) {
2740e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
2741e900a7d9SStephen Smalley 			kfree(bnames[i]);
2742e900a7d9SStephen Smalley 	}
2743e900a7d9SStephen Smalley 	kfree(bnames);
2744e900a7d9SStephen Smalley 	kfree(bvalues);
2745e900a7d9SStephen Smalley 	return rc;
2746e900a7d9SStephen Smalley }
2747e900a7d9SStephen Smalley 
274808554d6bSVenkat Yekkirala /*
274908554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
275008554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
275108554d6bSVenkat Yekkirala  */
275208554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
275308554d6bSVenkat Yekkirala {
275408554d6bSVenkat Yekkirala 	struct context *context1;
275508554d6bSVenkat Yekkirala 	struct context *context2;
275608554d6bSVenkat Yekkirala 	struct context newcon;
275708554d6bSVenkat Yekkirala 	char *s;
275808554d6bSVenkat Yekkirala 	u32 len;
27594b02b524SEric Paris 	int rc;
276008554d6bSVenkat Yekkirala 
27614b02b524SEric Paris 	rc = 0;
27620719aaf5SGuido Trentalancia 	if (!ss_initialized || !policydb.mls_enabled) {
276308554d6bSVenkat Yekkirala 		*new_sid = sid;
276408554d6bSVenkat Yekkirala 		goto out;
276508554d6bSVenkat Yekkirala 	}
276608554d6bSVenkat Yekkirala 
276708554d6bSVenkat Yekkirala 	context_init(&newcon);
276808554d6bSVenkat Yekkirala 
27690804d113SJames Morris 	read_lock(&policy_rwlock);
27704b02b524SEric Paris 
27714b02b524SEric Paris 	rc = -EINVAL;
277208554d6bSVenkat Yekkirala 	context1 = sidtab_search(&sidtab, sid);
277308554d6bSVenkat Yekkirala 	if (!context1) {
2774744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2775744ba35eSEric Paris 			__func__, sid);
277608554d6bSVenkat Yekkirala 		goto out_unlock;
277708554d6bSVenkat Yekkirala 	}
277808554d6bSVenkat Yekkirala 
27794b02b524SEric Paris 	rc = -EINVAL;
278008554d6bSVenkat Yekkirala 	context2 = sidtab_search(&sidtab, mls_sid);
278108554d6bSVenkat Yekkirala 	if (!context2) {
2782744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2783744ba35eSEric Paris 			__func__, mls_sid);
278408554d6bSVenkat Yekkirala 		goto out_unlock;
278508554d6bSVenkat Yekkirala 	}
278608554d6bSVenkat Yekkirala 
278708554d6bSVenkat Yekkirala 	newcon.user = context1->user;
278808554d6bSVenkat Yekkirala 	newcon.role = context1->role;
278908554d6bSVenkat Yekkirala 	newcon.type = context1->type;
27900efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
279108554d6bSVenkat Yekkirala 	if (rc)
279208554d6bSVenkat Yekkirala 		goto out_unlock;
279308554d6bSVenkat Yekkirala 
279408554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
279508554d6bSVenkat Yekkirala 	if (!policydb_context_isvalid(&policydb, &newcon)) {
279608554d6bSVenkat Yekkirala 		rc = convert_context_handle_invalid_context(&newcon);
27974b02b524SEric Paris 		if (rc) {
279808554d6bSVenkat Yekkirala 			if (!context_struct_to_string(&newcon, &s, &len)) {
27994093a844SRichard Guy Briggs 				audit_log(current->audit_context,
28004093a844SRichard Guy Briggs 					  GFP_ATOMIC, AUDIT_SELINUX_ERR,
28014093a844SRichard Guy Briggs 					  "op=security_sid_mls_copy "
28024093a844SRichard Guy Briggs 					  "invalid_context=%s", s);
280308554d6bSVenkat Yekkirala 				kfree(s);
280408554d6bSVenkat Yekkirala 			}
28054b02b524SEric Paris 			goto out_unlock;
28064b02b524SEric Paris 		}
28074b02b524SEric Paris 	}
280808554d6bSVenkat Yekkirala 
28094b02b524SEric Paris 	rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
281008554d6bSVenkat Yekkirala out_unlock:
28110804d113SJames Morris 	read_unlock(&policy_rwlock);
281208554d6bSVenkat Yekkirala 	context_destroy(&newcon);
281308554d6bSVenkat Yekkirala out:
281408554d6bSVenkat Yekkirala 	return rc;
281508554d6bSVenkat Yekkirala }
281608554d6bSVenkat Yekkirala 
2817220deb96SPaul Moore /**
2818220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
2819220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
2820220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
2821220deb96SPaul Moore  * @xfrm_sid: XFRM SID
2822220deb96SPaul Moore  *
2823220deb96SPaul Moore  * Description:
2824220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
2825220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
2826220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
2827220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
2828220deb96SPaul Moore  *
2829220deb96SPaul Moore  *                                 | function return |      @sid
2830220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
2831220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
2832220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
2833220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
2834220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
2835220deb96SPaul Moore  *
2836220deb96SPaul Moore  */
2837220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
2838220deb96SPaul Moore 				 u32 xfrm_sid,
2839220deb96SPaul Moore 				 u32 *peer_sid)
2840220deb96SPaul Moore {
2841220deb96SPaul Moore 	int rc;
2842220deb96SPaul Moore 	struct context *nlbl_ctx;
2843220deb96SPaul Moore 	struct context *xfrm_ctx;
2844220deb96SPaul Moore 
28454b02b524SEric Paris 	*peer_sid = SECSID_NULL;
28464b02b524SEric Paris 
2847220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
2848220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
2849220deb96SPaul Moore 	 * single or absent peer SID/label */
2850220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
2851220deb96SPaul Moore 		*peer_sid = nlbl_sid;
2852220deb96SPaul Moore 		return 0;
2853220deb96SPaul Moore 	}
2854220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
2855220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
2856220deb96SPaul Moore 	 * is present */
2857220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
2858220deb96SPaul Moore 		*peer_sid = xfrm_sid;
2859220deb96SPaul Moore 		return 0;
2860220deb96SPaul Moore 	}
2861220deb96SPaul Moore 
2862220deb96SPaul Moore 	/* we don't need to check ss_initialized here since the only way both
2863220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
2864220deb96SPaul Moore 	 * security server was initialized and ss_initialized was true */
28654b02b524SEric Paris 	if (!policydb.mls_enabled)
2866220deb96SPaul Moore 		return 0;
2867220deb96SPaul Moore 
28680804d113SJames Morris 	read_lock(&policy_rwlock);
2869220deb96SPaul Moore 
28704b02b524SEric Paris 	rc = -EINVAL;
2871220deb96SPaul Moore 	nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
2872220deb96SPaul Moore 	if (!nlbl_ctx) {
2873744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2874744ba35eSEric Paris 		       __func__, nlbl_sid);
28754b02b524SEric Paris 		goto out;
2876220deb96SPaul Moore 	}
28774b02b524SEric Paris 	rc = -EINVAL;
2878220deb96SPaul Moore 	xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
2879220deb96SPaul Moore 	if (!xfrm_ctx) {
2880744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2881744ba35eSEric Paris 		       __func__, xfrm_sid);
28824b02b524SEric Paris 		goto out;
2883220deb96SPaul Moore 	}
2884220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
28854b02b524SEric Paris 	if (rc)
28864b02b524SEric Paris 		goto out;
2887220deb96SPaul Moore 
2888220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
2889220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
2890220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
2891220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
2892220deb96SPaul Moore 	 * expressive */
2893220deb96SPaul Moore 	*peer_sid = xfrm_sid;
28944b02b524SEric Paris out:
28954b02b524SEric Paris 	read_unlock(&policy_rwlock);
2896220deb96SPaul Moore 	return rc;
2897220deb96SPaul Moore }
2898220deb96SPaul Moore 
289955fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
290055fcf09bSChristopher J. PeBenito {
290155fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
290255fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
290355fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
290455fcf09bSChristopher J. PeBenito 
290555fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
290655fcf09bSChristopher J. PeBenito 	if (!classes[value])
290755fcf09bSChristopher J. PeBenito 		return -ENOMEM;
290855fcf09bSChristopher J. PeBenito 
290955fcf09bSChristopher J. PeBenito 	return 0;
291055fcf09bSChristopher J. PeBenito }
291155fcf09bSChristopher J. PeBenito 
291255fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses)
291355fcf09bSChristopher J. PeBenito {
29144b02b524SEric Paris 	int rc;
291555fcf09bSChristopher J. PeBenito 
29160804d113SJames Morris 	read_lock(&policy_rwlock);
291755fcf09bSChristopher J. PeBenito 
29184b02b524SEric Paris 	rc = -ENOMEM;
291955fcf09bSChristopher J. PeBenito 	*nclasses = policydb.p_classes.nprim;
29209f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
292155fcf09bSChristopher J. PeBenito 	if (!*classes)
292255fcf09bSChristopher J. PeBenito 		goto out;
292355fcf09bSChristopher J. PeBenito 
292455fcf09bSChristopher J. PeBenito 	rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
292555fcf09bSChristopher J. PeBenito 			*classes);
29264b02b524SEric Paris 	if (rc) {
292755fcf09bSChristopher J. PeBenito 		int i;
292855fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
292955fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
293055fcf09bSChristopher J. PeBenito 		kfree(*classes);
293155fcf09bSChristopher J. PeBenito 	}
293255fcf09bSChristopher J. PeBenito 
293355fcf09bSChristopher J. PeBenito out:
29340804d113SJames Morris 	read_unlock(&policy_rwlock);
293555fcf09bSChristopher J. PeBenito 	return rc;
293655fcf09bSChristopher J. PeBenito }
293755fcf09bSChristopher J. PeBenito 
293855fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
293955fcf09bSChristopher J. PeBenito {
294055fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
294155fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
294255fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
294355fcf09bSChristopher J. PeBenito 
294455fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
294555fcf09bSChristopher J. PeBenito 	if (!perms[value])
294655fcf09bSChristopher J. PeBenito 		return -ENOMEM;
294755fcf09bSChristopher J. PeBenito 
294855fcf09bSChristopher J. PeBenito 	return 0;
294955fcf09bSChristopher J. PeBenito }
295055fcf09bSChristopher J. PeBenito 
295155fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms)
295255fcf09bSChristopher J. PeBenito {
29534b02b524SEric Paris 	int rc, i;
295455fcf09bSChristopher J. PeBenito 	struct class_datum *match;
295555fcf09bSChristopher J. PeBenito 
29560804d113SJames Morris 	read_lock(&policy_rwlock);
295755fcf09bSChristopher J. PeBenito 
29584b02b524SEric Paris 	rc = -EINVAL;
295955fcf09bSChristopher J. PeBenito 	match = hashtab_search(policydb.p_classes.table, class);
296055fcf09bSChristopher J. PeBenito 	if (!match) {
2961744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
2962dd6f953aSHarvey Harrison 			__func__, class);
296355fcf09bSChristopher J. PeBenito 		goto out;
296455fcf09bSChristopher J. PeBenito 	}
296555fcf09bSChristopher J. PeBenito 
29664b02b524SEric Paris 	rc = -ENOMEM;
296755fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
29689f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
296955fcf09bSChristopher J. PeBenito 	if (!*perms)
297055fcf09bSChristopher J. PeBenito 		goto out;
297155fcf09bSChristopher J. PeBenito 
297255fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
297355fcf09bSChristopher J. PeBenito 		rc = hashtab_map(match->comdatum->permissions.table,
297455fcf09bSChristopher J. PeBenito 				get_permissions_callback, *perms);
29754b02b524SEric Paris 		if (rc)
297655fcf09bSChristopher J. PeBenito 			goto err;
297755fcf09bSChristopher J. PeBenito 	}
297855fcf09bSChristopher J. PeBenito 
297955fcf09bSChristopher J. PeBenito 	rc = hashtab_map(match->permissions.table, get_permissions_callback,
298055fcf09bSChristopher J. PeBenito 			*perms);
29814b02b524SEric Paris 	if (rc)
298255fcf09bSChristopher J. PeBenito 		goto err;
298355fcf09bSChristopher J. PeBenito 
298455fcf09bSChristopher J. PeBenito out:
29850804d113SJames Morris 	read_unlock(&policy_rwlock);
298655fcf09bSChristopher J. PeBenito 	return rc;
298755fcf09bSChristopher J. PeBenito 
298855fcf09bSChristopher J. PeBenito err:
29890804d113SJames Morris 	read_unlock(&policy_rwlock);
299055fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
299155fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
299255fcf09bSChristopher J. PeBenito 	kfree(*perms);
299355fcf09bSChristopher J. PeBenito 	return rc;
299455fcf09bSChristopher J. PeBenito }
299555fcf09bSChristopher J. PeBenito 
29963f12070eSEric Paris int security_get_reject_unknown(void)
29973f12070eSEric Paris {
29983f12070eSEric Paris 	return policydb.reject_unknown;
29993f12070eSEric Paris }
30003f12070eSEric Paris 
30013f12070eSEric Paris int security_get_allow_unknown(void)
30023f12070eSEric Paris {
30033f12070eSEric Paris 	return policydb.allow_unknown;
30043f12070eSEric Paris }
30053f12070eSEric Paris 
30063bb56b25SPaul Moore /**
30073bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
30083bb56b25SPaul Moore  * @req_cap: capability
30093bb56b25SPaul Moore  *
30103bb56b25SPaul Moore  * Description:
30113bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
30123bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
30133bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
30143bb56b25SPaul Moore  *
30153bb56b25SPaul Moore  */
30163bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap)
30173bb56b25SPaul Moore {
30183bb56b25SPaul Moore 	int rc;
30193bb56b25SPaul Moore 
30200804d113SJames Morris 	read_lock(&policy_rwlock);
30213bb56b25SPaul Moore 	rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
30220804d113SJames Morris 	read_unlock(&policy_rwlock);
30233bb56b25SPaul Moore 
30243bb56b25SPaul Moore 	return rc;
30253bb56b25SPaul Moore }
30263bb56b25SPaul Moore 
3027376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3028376bd9cbSDarrel Goeddel 	u32 au_seqno;
3029376bd9cbSDarrel Goeddel 	struct context au_ctxt;
3030376bd9cbSDarrel Goeddel };
3031376bd9cbSDarrel Goeddel 
30329d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3033376bd9cbSDarrel Goeddel {
30349d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
30359d57a7f9SAhmed S. Darwish 
3036376bd9cbSDarrel Goeddel 	if (rule) {
3037376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
3038376bd9cbSDarrel Goeddel 		kfree(rule);
3039376bd9cbSDarrel Goeddel 	}
3040376bd9cbSDarrel Goeddel }
3041376bd9cbSDarrel Goeddel 
30429d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3043376bd9cbSDarrel Goeddel {
3044376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
3045376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
3046376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
3047376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
30489d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3049376bd9cbSDarrel Goeddel 	int rc = 0;
3050376bd9cbSDarrel Goeddel 
3051376bd9cbSDarrel Goeddel 	*rule = NULL;
3052376bd9cbSDarrel Goeddel 
3053376bd9cbSDarrel Goeddel 	if (!ss_initialized)
30543ad40d64SSteve G 		return -EOPNOTSUPP;
3055376bd9cbSDarrel Goeddel 
3056376bd9cbSDarrel Goeddel 	switch (field) {
30573a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
30583a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
30593a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
30606e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
30616e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
30626e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3063376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
30645af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
3065376bd9cbSDarrel Goeddel 			return -EINVAL;
3066376bd9cbSDarrel Goeddel 		break;
30673a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
30683a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
30696e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
30706e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
307125985edcSLucas De Marchi 		/* we do not allow a range, indicated by the presence of '-' */
3072376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
3073376bd9cbSDarrel Goeddel 			return -EINVAL;
3074376bd9cbSDarrel Goeddel 		break;
3075376bd9cbSDarrel Goeddel 	default:
3076376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
3077376bd9cbSDarrel Goeddel 		return -EINVAL;
3078376bd9cbSDarrel Goeddel 	}
3079376bd9cbSDarrel Goeddel 
3080376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
3081376bd9cbSDarrel Goeddel 	if (!tmprule)
3082376bd9cbSDarrel Goeddel 		return -ENOMEM;
3083376bd9cbSDarrel Goeddel 
3084376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
3085376bd9cbSDarrel Goeddel 
30860804d113SJames Morris 	read_lock(&policy_rwlock);
3087376bd9cbSDarrel Goeddel 
3088376bd9cbSDarrel Goeddel 	tmprule->au_seqno = latest_granting;
3089376bd9cbSDarrel Goeddel 
3090376bd9cbSDarrel Goeddel 	switch (field) {
30913a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
30926e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
30934b02b524SEric Paris 		rc = -EINVAL;
3094376bd9cbSDarrel Goeddel 		userdatum = hashtab_search(policydb.p_users.table, rulestr);
3095376bd9cbSDarrel Goeddel 		if (!userdatum)
30964b02b524SEric Paris 			goto out;
3097376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
3098376bd9cbSDarrel Goeddel 		break;
30993a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
31006e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
31014b02b524SEric Paris 		rc = -EINVAL;
3102376bd9cbSDarrel Goeddel 		roledatum = hashtab_search(policydb.p_roles.table, rulestr);
3103376bd9cbSDarrel Goeddel 		if (!roledatum)
31044b02b524SEric Paris 			goto out;
3105376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
3106376bd9cbSDarrel Goeddel 		break;
31073a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
31086e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
31094b02b524SEric Paris 		rc = -EINVAL;
3110376bd9cbSDarrel Goeddel 		typedatum = hashtab_search(policydb.p_types.table, rulestr);
3111376bd9cbSDarrel Goeddel 		if (!typedatum)
31124b02b524SEric Paris 			goto out;
3113376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
3114376bd9cbSDarrel Goeddel 		break;
31153a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
31163a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
31176e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
31186e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
3119376bd9cbSDarrel Goeddel 		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
31204b02b524SEric Paris 		if (rc)
31214b02b524SEric Paris 			goto out;
3122376bd9cbSDarrel Goeddel 		break;
3123376bd9cbSDarrel Goeddel 	}
31244b02b524SEric Paris 	rc = 0;
31254b02b524SEric Paris out:
31260804d113SJames Morris 	read_unlock(&policy_rwlock);
3127376bd9cbSDarrel Goeddel 
3128376bd9cbSDarrel Goeddel 	if (rc) {
3129376bd9cbSDarrel Goeddel 		selinux_audit_rule_free(tmprule);
3130376bd9cbSDarrel Goeddel 		tmprule = NULL;
3131376bd9cbSDarrel Goeddel 	}
3132376bd9cbSDarrel Goeddel 
3133376bd9cbSDarrel Goeddel 	*rule = tmprule;
3134376bd9cbSDarrel Goeddel 
3135376bd9cbSDarrel Goeddel 	return rc;
3136376bd9cbSDarrel Goeddel }
3137376bd9cbSDarrel Goeddel 
31389d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
31399d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
31409d57a7f9SAhmed S. Darwish {
31419d57a7f9SAhmed S. Darwish 	int i;
31429d57a7f9SAhmed S. Darwish 
31439d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
31449d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
31459d57a7f9SAhmed S. Darwish 		switch (f->type) {
31469d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
31479d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
31489d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
31499d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
31509d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
31519d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
31529d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
31539d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
31549d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
31559d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
31569d57a7f9SAhmed S. Darwish 			return 1;
31579d57a7f9SAhmed S. Darwish 		}
31589d57a7f9SAhmed S. Darwish 	}
31599d57a7f9SAhmed S. Darwish 
31609d57a7f9SAhmed S. Darwish 	return 0;
31619d57a7f9SAhmed S. Darwish }
31629d57a7f9SAhmed S. Darwish 
31639d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
3164376bd9cbSDarrel Goeddel 			     struct audit_context *actx)
3165376bd9cbSDarrel Goeddel {
3166376bd9cbSDarrel Goeddel 	struct context *ctxt;
3167376bd9cbSDarrel Goeddel 	struct mls_level *level;
31689d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
3169376bd9cbSDarrel Goeddel 	int match = 0;
3170376bd9cbSDarrel Goeddel 
31719ad42a79SRichard Guy Briggs 	if (unlikely(!rule)) {
31729ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3173376bd9cbSDarrel Goeddel 		return -ENOENT;
3174376bd9cbSDarrel Goeddel 	}
3175376bd9cbSDarrel Goeddel 
31760804d113SJames Morris 	read_lock(&policy_rwlock);
3177376bd9cbSDarrel Goeddel 
3178376bd9cbSDarrel Goeddel 	if (rule->au_seqno < latest_granting) {
3179376bd9cbSDarrel Goeddel 		match = -ESTALE;
3180376bd9cbSDarrel Goeddel 		goto out;
3181376bd9cbSDarrel Goeddel 	}
3182376bd9cbSDarrel Goeddel 
31839a2f44f0SStephen Smalley 	ctxt = sidtab_search(&sidtab, sid);
31849ad42a79SRichard Guy Briggs 	if (unlikely(!ctxt)) {
31859ad42a79SRichard Guy Briggs 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
31869a2f44f0SStephen Smalley 			  sid);
3187376bd9cbSDarrel Goeddel 		match = -ENOENT;
3188376bd9cbSDarrel Goeddel 		goto out;
3189376bd9cbSDarrel Goeddel 	}
3190376bd9cbSDarrel Goeddel 
3191376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
3192376bd9cbSDarrel Goeddel 	   without a match */
3193376bd9cbSDarrel Goeddel 	switch (field) {
31943a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
31956e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
3196376bd9cbSDarrel Goeddel 		switch (op) {
31975af75d8dSAl Viro 		case Audit_equal:
3198376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
3199376bd9cbSDarrel Goeddel 			break;
32005af75d8dSAl Viro 		case Audit_not_equal:
3201376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
3202376bd9cbSDarrel Goeddel 			break;
3203376bd9cbSDarrel Goeddel 		}
3204376bd9cbSDarrel Goeddel 		break;
32053a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
32066e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
3207376bd9cbSDarrel Goeddel 		switch (op) {
32085af75d8dSAl Viro 		case Audit_equal:
3209376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
3210376bd9cbSDarrel Goeddel 			break;
32115af75d8dSAl Viro 		case Audit_not_equal:
3212376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
3213376bd9cbSDarrel Goeddel 			break;
3214376bd9cbSDarrel Goeddel 		}
3215376bd9cbSDarrel Goeddel 		break;
32163a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
32176e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
3218376bd9cbSDarrel Goeddel 		switch (op) {
32195af75d8dSAl Viro 		case Audit_equal:
3220376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
3221376bd9cbSDarrel Goeddel 			break;
32225af75d8dSAl Viro 		case Audit_not_equal:
3223376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
3224376bd9cbSDarrel Goeddel 			break;
3225376bd9cbSDarrel Goeddel 		}
3226376bd9cbSDarrel Goeddel 		break;
32273a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
32283a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
32296e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
32306e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
32316e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
32326e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
3233376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3234376bd9cbSDarrel Goeddel 		switch (op) {
32355af75d8dSAl Viro 		case Audit_equal:
3236376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3237376bd9cbSDarrel Goeddel 					     level);
3238376bd9cbSDarrel Goeddel 			break;
32395af75d8dSAl Viro 		case Audit_not_equal:
3240376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3241376bd9cbSDarrel Goeddel 					      level);
3242376bd9cbSDarrel Goeddel 			break;
32435af75d8dSAl Viro 		case Audit_lt:
3244376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3245376bd9cbSDarrel Goeddel 					       level) &&
3246376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3247376bd9cbSDarrel Goeddel 					       level));
3248376bd9cbSDarrel Goeddel 			break;
32495af75d8dSAl Viro 		case Audit_le:
3250376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3251376bd9cbSDarrel Goeddel 					      level);
3252376bd9cbSDarrel Goeddel 			break;
32535af75d8dSAl Viro 		case Audit_gt:
3254376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
3255376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
3256376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
3257376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
3258376bd9cbSDarrel Goeddel 			break;
32595af75d8dSAl Viro 		case Audit_ge:
3260376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
3261376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
3262376bd9cbSDarrel Goeddel 			break;
3263376bd9cbSDarrel Goeddel 		}
3264376bd9cbSDarrel Goeddel 	}
3265376bd9cbSDarrel Goeddel 
3266376bd9cbSDarrel Goeddel out:
32670804d113SJames Morris 	read_unlock(&policy_rwlock);
3268376bd9cbSDarrel Goeddel 	return match;
3269376bd9cbSDarrel Goeddel }
3270376bd9cbSDarrel Goeddel 
32719d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules;
3272376bd9cbSDarrel Goeddel 
3273562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3274376bd9cbSDarrel Goeddel {
3275376bd9cbSDarrel Goeddel 	int err = 0;
3276376bd9cbSDarrel Goeddel 
3277376bd9cbSDarrel Goeddel 	if (event == AVC_CALLBACK_RESET && aurule_callback)
3278376bd9cbSDarrel Goeddel 		err = aurule_callback();
3279376bd9cbSDarrel Goeddel 	return err;
3280376bd9cbSDarrel Goeddel }
3281376bd9cbSDarrel Goeddel 
3282376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3283376bd9cbSDarrel Goeddel {
3284376bd9cbSDarrel Goeddel 	int err;
3285376bd9cbSDarrel Goeddel 
3286562c99f2SWanlong Gao 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3287376bd9cbSDarrel Goeddel 	if (err)
3288376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
3289376bd9cbSDarrel Goeddel 
3290376bd9cbSDarrel Goeddel 	return err;
3291376bd9cbSDarrel Goeddel }
3292376bd9cbSDarrel Goeddel __initcall(aurule_init);
3293376bd9cbSDarrel Goeddel 
32947420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
32957420ed23SVenkat Yekkirala /**
32965778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
32975778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
32985dbe1eb0SPaul Moore  * @sid: the SELinux SID
32997420ed23SVenkat Yekkirala  *
33007420ed23SVenkat Yekkirala  * Description:
33017420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
33025778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
33035778eabdSPaul Moore  * already been initialized.
33047420ed23SVenkat Yekkirala  *
33057420ed23SVenkat Yekkirala  */
33065778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
33075dbe1eb0SPaul Moore 				      u32 sid)
33087420ed23SVenkat Yekkirala {
33095dbe1eb0SPaul Moore 	u32 *sid_cache;
33107420ed23SVenkat Yekkirala 
33115dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
33125dbe1eb0SPaul Moore 	if (sid_cache == NULL)
33135dbe1eb0SPaul Moore 		return;
33145778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
33155dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
33165dbe1eb0SPaul Moore 		kfree(sid_cache);
33175778eabdSPaul Moore 		return;
33180ec8abd7SJesper Juhl 	}
33197420ed23SVenkat Yekkirala 
33205dbe1eb0SPaul Moore 	*sid_cache = sid;
33215dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
33225dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
33235778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
33247420ed23SVenkat Yekkirala }
33257420ed23SVenkat Yekkirala 
33267420ed23SVenkat Yekkirala /**
33275778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
33287420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
33297420ed23SVenkat Yekkirala  * @sid: the SELinux SID
33307420ed23SVenkat Yekkirala  *
33317420ed23SVenkat Yekkirala  * Description:
33325778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
33337420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
333425985edcSLucas De Marchi  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
33355dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
33365dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
33375dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
33385dbe1eb0SPaul Moore  * failure.
33397420ed23SVenkat Yekkirala  *
33407420ed23SVenkat Yekkirala  */
33415778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
33427420ed23SVenkat Yekkirala 				   u32 *sid)
33437420ed23SVenkat Yekkirala {
33447ae9f23cSEric Paris 	int rc;
33457420ed23SVenkat Yekkirala 	struct context *ctx;
33467420ed23SVenkat Yekkirala 	struct context ctx_new;
33475778eabdSPaul Moore 
33485778eabdSPaul Moore 	if (!ss_initialized) {
33495778eabdSPaul Moore 		*sid = SECSID_NULL;
33505778eabdSPaul Moore 		return 0;
33515778eabdSPaul Moore 	}
33527420ed23SVenkat Yekkirala 
33530804d113SJames Morris 	read_lock(&policy_rwlock);
33547420ed23SVenkat Yekkirala 
33557ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
33565dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
33577ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
335816efd454SPaul Moore 		*sid = secattr->attr.secid;
33597ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
33607ae9f23cSEric Paris 		rc = -EIDRM;
33615dbe1eb0SPaul Moore 		ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
33627420ed23SVenkat Yekkirala 		if (ctx == NULL)
33637ae9f23cSEric Paris 			goto out;
33647420ed23SVenkat Yekkirala 
336581990fbdSPaul Moore 		context_init(&ctx_new);
33667420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
33677420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
33687420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
336902752760SPaul Moore 		mls_import_netlbl_lvl(&ctx_new, secattr);
3370701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3371da8026faSPaul Moore 			rc = mls_import_netlbl_cat(&ctx_new, secattr);
33727ae9f23cSEric Paris 			if (rc)
33737ae9f23cSEric Paris 				goto out;
33747420ed23SVenkat Yekkirala 		}
33757ae9f23cSEric Paris 		rc = -EIDRM;
33767ae9f23cSEric Paris 		if (!mls_context_isvalid(&policydb, &ctx_new))
33777ae9f23cSEric Paris 			goto out_free;
33787420ed23SVenkat Yekkirala 
33797420ed23SVenkat Yekkirala 		rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
33807ae9f23cSEric Paris 		if (rc)
33817ae9f23cSEric Paris 			goto out_free;
33827420ed23SVenkat Yekkirala 
33835dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
33845778eabdSPaul Moore 
33857420ed23SVenkat Yekkirala 		ebitmap_destroy(&ctx_new.range.level[0].cat);
33867ae9f23cSEric Paris 	} else
3387388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
33887420ed23SVenkat Yekkirala 
33897ae9f23cSEric Paris 	read_unlock(&policy_rwlock);
33907ae9f23cSEric Paris 	return 0;
33917ae9f23cSEric Paris out_free:
33927ae9f23cSEric Paris 	ebitmap_destroy(&ctx_new.range.level[0].cat);
33937ae9f23cSEric Paris out:
33940804d113SJames Morris 	read_unlock(&policy_rwlock);
33957420ed23SVenkat Yekkirala 	return rc;
33967420ed23SVenkat Yekkirala }
33977420ed23SVenkat Yekkirala 
33987420ed23SVenkat Yekkirala /**
33995778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
34005778eabdSPaul Moore  * @sid: the SELinux SID
34015778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
34027420ed23SVenkat Yekkirala  *
34037420ed23SVenkat Yekkirala  * Description:
34045778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
34055778eabdSPaul Moore  * Returns zero on success, negative values on failure.
34067420ed23SVenkat Yekkirala  *
34077420ed23SVenkat Yekkirala  */
34085778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
34097420ed23SVenkat Yekkirala {
341099d854d2SPaul Moore 	int rc;
34117420ed23SVenkat Yekkirala 	struct context *ctx;
34127420ed23SVenkat Yekkirala 
34137420ed23SVenkat Yekkirala 	if (!ss_initialized)
34147420ed23SVenkat Yekkirala 		return 0;
34157420ed23SVenkat Yekkirala 
34160804d113SJames Morris 	read_lock(&policy_rwlock);
34174b02b524SEric Paris 
341899d854d2SPaul Moore 	rc = -ENOENT;
34194b02b524SEric Paris 	ctx = sidtab_search(&sidtab, sid);
34204b02b524SEric Paris 	if (ctx == NULL)
34214b02b524SEric Paris 		goto out;
34224b02b524SEric Paris 
34234b02b524SEric Paris 	rc = -ENOMEM;
3424ac76c05bSEric Paris 	secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
34257420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
34264b02b524SEric Paris 	if (secattr->domain == NULL)
34274b02b524SEric Paris 		goto out;
34284b02b524SEric Paris 
34298d75899dSPaul Moore 	secattr->attr.secid = sid;
34308d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
34315778eabdSPaul Moore 	mls_export_netlbl_lvl(ctx, secattr);
34325778eabdSPaul Moore 	rc = mls_export_netlbl_cat(ctx, secattr);
34334b02b524SEric Paris out:
34340804d113SJames Morris 	read_unlock(&policy_rwlock);
3435f8687afeSPaul Moore 	return rc;
3436f8687afeSPaul Moore }
34377420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3438cee74f47SEric Paris 
3439cee74f47SEric Paris /**
3440cee74f47SEric Paris  * security_read_policy - read the policy.
3441cee74f47SEric Paris  * @data: binary policy data
3442cee74f47SEric Paris  * @len: length of data in bytes
3443cee74f47SEric Paris  *
3444cee74f47SEric Paris  */
34456b697323SEric Paris int security_read_policy(void **data, size_t *len)
3446cee74f47SEric Paris {
3447cee74f47SEric Paris 	int rc;
3448cee74f47SEric Paris 	struct policy_file fp;
3449cee74f47SEric Paris 
3450cee74f47SEric Paris 	if (!ss_initialized)
3451cee74f47SEric Paris 		return -EINVAL;
3452cee74f47SEric Paris 
3453cee74f47SEric Paris 	*len = security_policydb_len();
3454cee74f47SEric Paris 
3455845ca30fSEric Paris 	*data = vmalloc_user(*len);
3456cee74f47SEric Paris 	if (!*data)
3457cee74f47SEric Paris 		return -ENOMEM;
3458cee74f47SEric Paris 
3459cee74f47SEric Paris 	fp.data = *data;
3460cee74f47SEric Paris 	fp.len = *len;
3461cee74f47SEric Paris 
3462cee74f47SEric Paris 	read_lock(&policy_rwlock);
3463cee74f47SEric Paris 	rc = policydb_write(&policydb, &fp);
3464cee74f47SEric Paris 	read_unlock(&policy_rwlock);
3465cee74f47SEric Paris 
3466cee74f47SEric Paris 	if (rc)
3467cee74f47SEric Paris 		return rc;
3468cee74f47SEric Paris 
3469cee74f47SEric Paris 	*len = (unsigned long)fp.data - (unsigned long)*data;
3470cee74f47SEric Paris 	return 0;
3471cee74f47SEric Paris 
3472cee74f47SEric Paris }
3473