xref: /openbmc/linux/security/selinux/ss/services.c (revision ac76c05b)
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  *
167420ed23SVenkat Yekkirala  * Updated: Hewlett-Packard <paul.moore@hp.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 
731da177e4SLinus Torvalds extern void selnl_notify_policyload(u32 seqno);
741da177e4SLinus Torvalds 
753bb56b25SPaul Moore int selinux_policycap_netpeer;
76b0c636b9SEric Paris int selinux_policycap_openperm;
773bb56b25SPaul Moore 
781da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds static struct sidtab sidtab;
811da177e4SLinus Torvalds struct policydb policydb;
825d55a345SEric Paris int ss_initialized;
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds /*
851da177e4SLinus Torvalds  * The largest sequence number that has been used when
861da177e4SLinus Torvalds  * providing an access decision to the access vector cache.
871da177e4SLinus Torvalds  * The sequence number only changes when a policy change
881da177e4SLinus Torvalds  * occurs.
891da177e4SLinus Torvalds  */
905d55a345SEric Paris static u32 latest_granting;
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /* Forward declaration. */
931da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext,
941da177e4SLinus Torvalds 				    u32 *scontext_len);
951da177e4SLinus Torvalds 
9619439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext,
97d9250deaSKaiGai Kohei 				      struct context *tcontext,
98d9250deaSKaiGai Kohei 				      u16 tclass,
99d9250deaSKaiGai Kohei 				      struct av_decision *avd);
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 
204c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd,
205c6d3aaa4SStephen Smalley 			 int allow_unknown)
206c6d3aaa4SStephen Smalley {
207c6d3aaa4SStephen Smalley 	if (tclass < current_mapping_size) {
208c6d3aaa4SStephen Smalley 		unsigned i, n = current_mapping[tclass].num_perms;
209c6d3aaa4SStephen Smalley 		u32 result;
210c6d3aaa4SStephen Smalley 
211c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
212c6d3aaa4SStephen Smalley 			if (avd->allowed & current_mapping[tclass].perms[i])
213c6d3aaa4SStephen Smalley 				result |= 1<<i;
214c6d3aaa4SStephen Smalley 			if (allow_unknown && !current_mapping[tclass].perms[i])
215c6d3aaa4SStephen Smalley 				result |= 1<<i;
216c6d3aaa4SStephen Smalley 		}
217c6d3aaa4SStephen Smalley 		avd->allowed = result;
218c6d3aaa4SStephen Smalley 
219c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++)
220c6d3aaa4SStephen Smalley 			if (avd->auditallow & current_mapping[tclass].perms[i])
221c6d3aaa4SStephen Smalley 				result |= 1<<i;
222c6d3aaa4SStephen Smalley 		avd->auditallow = result;
223c6d3aaa4SStephen Smalley 
224c6d3aaa4SStephen Smalley 		for (i = 0, result = 0; i < n; i++) {
225c6d3aaa4SStephen Smalley 			if (avd->auditdeny & current_mapping[tclass].perms[i])
226c6d3aaa4SStephen Smalley 				result |= 1<<i;
227c6d3aaa4SStephen Smalley 			if (!allow_unknown && !current_mapping[tclass].perms[i])
228c6d3aaa4SStephen Smalley 				result |= 1<<i;
229c6d3aaa4SStephen Smalley 		}
2300bce9527SEric Paris 		/*
2310bce9527SEric Paris 		 * In case the kernel has a bug and requests a permission
2320bce9527SEric Paris 		 * between num_perms and the maximum permission number, we
2330bce9527SEric Paris 		 * should audit that denial
2340bce9527SEric Paris 		 */
2350bce9527SEric Paris 		for (; i < (sizeof(u32)*8); i++)
2360bce9527SEric Paris 			result |= 1<<i;
237c6d3aaa4SStephen Smalley 		avd->auditdeny = result;
238c6d3aaa4SStephen Smalley 	}
239c6d3aaa4SStephen Smalley }
240c6d3aaa4SStephen Smalley 
2410719aaf5SGuido Trentalancia int security_mls_enabled(void)
2420719aaf5SGuido Trentalancia {
2430719aaf5SGuido Trentalancia 	return policydb.mls_enabled;
2440719aaf5SGuido Trentalancia }
245c6d3aaa4SStephen Smalley 
2461da177e4SLinus Torvalds /*
2471da177e4SLinus Torvalds  * Return the boolean value of a constraint expression
2481da177e4SLinus Torvalds  * when it is applied to the specified source and target
2491da177e4SLinus Torvalds  * security contexts.
2501da177e4SLinus Torvalds  *
2511da177e4SLinus Torvalds  * xcontext is a special beast...  It is used by the validatetrans rules
2521da177e4SLinus Torvalds  * only.  For these rules, scontext is the context before the transition,
2531da177e4SLinus Torvalds  * tcontext is the context after the transition, and xcontext is the context
2541da177e4SLinus Torvalds  * of the process performing the transition.  All other callers of
2551da177e4SLinus Torvalds  * constraint_expr_eval should pass in NULL for xcontext.
2561da177e4SLinus Torvalds  */
2571da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext,
2581da177e4SLinus Torvalds 				struct context *tcontext,
2591da177e4SLinus Torvalds 				struct context *xcontext,
2601da177e4SLinus Torvalds 				struct constraint_expr *cexpr)
2611da177e4SLinus Torvalds {
2621da177e4SLinus Torvalds 	u32 val1, val2;
2631da177e4SLinus Torvalds 	struct context *c;
2641da177e4SLinus Torvalds 	struct role_datum *r1, *r2;
2651da177e4SLinus Torvalds 	struct mls_level *l1, *l2;
2661da177e4SLinus Torvalds 	struct constraint_expr *e;
2671da177e4SLinus Torvalds 	int s[CEXPR_MAXDEPTH];
2681da177e4SLinus Torvalds 	int sp = -1;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	for (e = cexpr; e; e = e->next) {
2711da177e4SLinus Torvalds 		switch (e->expr_type) {
2721da177e4SLinus Torvalds 		case CEXPR_NOT:
2731da177e4SLinus Torvalds 			BUG_ON(sp < 0);
2741da177e4SLinus Torvalds 			s[sp] = !s[sp];
2751da177e4SLinus Torvalds 			break;
2761da177e4SLinus Torvalds 		case CEXPR_AND:
2771da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2781da177e4SLinus Torvalds 			sp--;
2791da177e4SLinus Torvalds 			s[sp] &= s[sp + 1];
2801da177e4SLinus Torvalds 			break;
2811da177e4SLinus Torvalds 		case CEXPR_OR:
2821da177e4SLinus Torvalds 			BUG_ON(sp < 1);
2831da177e4SLinus Torvalds 			sp--;
2841da177e4SLinus Torvalds 			s[sp] |= s[sp + 1];
2851da177e4SLinus Torvalds 			break;
2861da177e4SLinus Torvalds 		case CEXPR_ATTR:
2871da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH - 1))
2881da177e4SLinus Torvalds 				return 0;
2891da177e4SLinus Torvalds 			switch (e->attr) {
2901da177e4SLinus Torvalds 			case CEXPR_USER:
2911da177e4SLinus Torvalds 				val1 = scontext->user;
2921da177e4SLinus Torvalds 				val2 = tcontext->user;
2931da177e4SLinus Torvalds 				break;
2941da177e4SLinus Torvalds 			case CEXPR_TYPE:
2951da177e4SLinus Torvalds 				val1 = scontext->type;
2961da177e4SLinus Torvalds 				val2 = tcontext->type;
2971da177e4SLinus Torvalds 				break;
2981da177e4SLinus Torvalds 			case CEXPR_ROLE:
2991da177e4SLinus Torvalds 				val1 = scontext->role;
3001da177e4SLinus Torvalds 				val2 = tcontext->role;
3011da177e4SLinus Torvalds 				r1 = policydb.role_val_to_struct[val1 - 1];
3021da177e4SLinus Torvalds 				r2 = policydb.role_val_to_struct[val2 - 1];
3031da177e4SLinus Torvalds 				switch (e->op) {
3041da177e4SLinus Torvalds 				case CEXPR_DOM:
3051da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r1->dominates,
3061da177e4SLinus Torvalds 								  val2 - 1);
3071da177e4SLinus Torvalds 					continue;
3081da177e4SLinus Torvalds 				case CEXPR_DOMBY:
3091da177e4SLinus Torvalds 					s[++sp] = ebitmap_get_bit(&r2->dominates,
3101da177e4SLinus Torvalds 								  val1 - 1);
3111da177e4SLinus Torvalds 					continue;
3121da177e4SLinus Torvalds 				case CEXPR_INCOMP:
3131da177e4SLinus Torvalds 					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
3141da177e4SLinus Torvalds 								    val2 - 1) &&
3151da177e4SLinus Torvalds 						   !ebitmap_get_bit(&r2->dominates,
3161da177e4SLinus Torvalds 								    val1 - 1));
3171da177e4SLinus Torvalds 					continue;
3181da177e4SLinus Torvalds 				default:
3191da177e4SLinus Torvalds 					break;
3201da177e4SLinus Torvalds 				}
3211da177e4SLinus Torvalds 				break;
3221da177e4SLinus Torvalds 			case CEXPR_L1L2:
3231da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3241da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3251da177e4SLinus Torvalds 				goto mls_ops;
3261da177e4SLinus Torvalds 			case CEXPR_L1H2:
3271da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3281da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3291da177e4SLinus Torvalds 				goto mls_ops;
3301da177e4SLinus Torvalds 			case CEXPR_H1L2:
3311da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3321da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[0]);
3331da177e4SLinus Torvalds 				goto mls_ops;
3341da177e4SLinus Torvalds 			case CEXPR_H1H2:
3351da177e4SLinus Torvalds 				l1 = &(scontext->range.level[1]);
3361da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3371da177e4SLinus Torvalds 				goto mls_ops;
3381da177e4SLinus Torvalds 			case CEXPR_L1H1:
3391da177e4SLinus Torvalds 				l1 = &(scontext->range.level[0]);
3401da177e4SLinus Torvalds 				l2 = &(scontext->range.level[1]);
3411da177e4SLinus Torvalds 				goto mls_ops;
3421da177e4SLinus Torvalds 			case CEXPR_L2H2:
3431da177e4SLinus Torvalds 				l1 = &(tcontext->range.level[0]);
3441da177e4SLinus Torvalds 				l2 = &(tcontext->range.level[1]);
3451da177e4SLinus Torvalds 				goto mls_ops;
3461da177e4SLinus Torvalds mls_ops:
3471da177e4SLinus Torvalds 			switch (e->op) {
3481da177e4SLinus Torvalds 			case CEXPR_EQ:
3491da177e4SLinus Torvalds 				s[++sp] = mls_level_eq(l1, l2);
3501da177e4SLinus Torvalds 				continue;
3511da177e4SLinus Torvalds 			case CEXPR_NEQ:
3521da177e4SLinus Torvalds 				s[++sp] = !mls_level_eq(l1, l2);
3531da177e4SLinus Torvalds 				continue;
3541da177e4SLinus Torvalds 			case CEXPR_DOM:
3551da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l1, l2);
3561da177e4SLinus Torvalds 				continue;
3571da177e4SLinus Torvalds 			case CEXPR_DOMBY:
3581da177e4SLinus Torvalds 				s[++sp] = mls_level_dom(l2, l1);
3591da177e4SLinus Torvalds 				continue;
3601da177e4SLinus Torvalds 			case CEXPR_INCOMP:
3611da177e4SLinus Torvalds 				s[++sp] = mls_level_incomp(l2, l1);
3621da177e4SLinus Torvalds 				continue;
3631da177e4SLinus Torvalds 			default:
3641da177e4SLinus Torvalds 				BUG();
3651da177e4SLinus Torvalds 				return 0;
3661da177e4SLinus Torvalds 			}
3671da177e4SLinus Torvalds 			break;
3681da177e4SLinus Torvalds 			default:
3691da177e4SLinus Torvalds 				BUG();
3701da177e4SLinus Torvalds 				return 0;
3711da177e4SLinus Torvalds 			}
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 			switch (e->op) {
3741da177e4SLinus Torvalds 			case CEXPR_EQ:
3751da177e4SLinus Torvalds 				s[++sp] = (val1 == val2);
3761da177e4SLinus Torvalds 				break;
3771da177e4SLinus Torvalds 			case CEXPR_NEQ:
3781da177e4SLinus Torvalds 				s[++sp] = (val1 != val2);
3791da177e4SLinus Torvalds 				break;
3801da177e4SLinus Torvalds 			default:
3811da177e4SLinus Torvalds 				BUG();
3821da177e4SLinus Torvalds 				return 0;
3831da177e4SLinus Torvalds 			}
3841da177e4SLinus Torvalds 			break;
3851da177e4SLinus Torvalds 		case CEXPR_NAMES:
3861da177e4SLinus Torvalds 			if (sp == (CEXPR_MAXDEPTH-1))
3871da177e4SLinus Torvalds 				return 0;
3881da177e4SLinus Torvalds 			c = scontext;
3891da177e4SLinus Torvalds 			if (e->attr & CEXPR_TARGET)
3901da177e4SLinus Torvalds 				c = tcontext;
3911da177e4SLinus Torvalds 			else if (e->attr & CEXPR_XTARGET) {
3921da177e4SLinus Torvalds 				c = xcontext;
3931da177e4SLinus Torvalds 				if (!c) {
3941da177e4SLinus Torvalds 					BUG();
3951da177e4SLinus Torvalds 					return 0;
3961da177e4SLinus Torvalds 				}
3971da177e4SLinus Torvalds 			}
3981da177e4SLinus Torvalds 			if (e->attr & CEXPR_USER)
3991da177e4SLinus Torvalds 				val1 = c->user;
4001da177e4SLinus Torvalds 			else if (e->attr & CEXPR_ROLE)
4011da177e4SLinus Torvalds 				val1 = c->role;
4021da177e4SLinus Torvalds 			else if (e->attr & CEXPR_TYPE)
4031da177e4SLinus Torvalds 				val1 = c->type;
4041da177e4SLinus Torvalds 			else {
4051da177e4SLinus Torvalds 				BUG();
4061da177e4SLinus Torvalds 				return 0;
4071da177e4SLinus Torvalds 			}
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 			switch (e->op) {
4101da177e4SLinus Torvalds 			case CEXPR_EQ:
4111da177e4SLinus Torvalds 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
4121da177e4SLinus Torvalds 				break;
4131da177e4SLinus Torvalds 			case CEXPR_NEQ:
4141da177e4SLinus Torvalds 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
4151da177e4SLinus Torvalds 				break;
4161da177e4SLinus Torvalds 			default:
4171da177e4SLinus Torvalds 				BUG();
4181da177e4SLinus Torvalds 				return 0;
4191da177e4SLinus Torvalds 			}
4201da177e4SLinus Torvalds 			break;
4211da177e4SLinus Torvalds 		default:
4221da177e4SLinus Torvalds 			BUG();
4231da177e4SLinus Torvalds 			return 0;
4241da177e4SLinus Torvalds 		}
4251da177e4SLinus Torvalds 	}
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	BUG_ON(sp != 0);
4281da177e4SLinus Torvalds 	return s[0];
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds /*
43244c2d9bdSKaiGai Kohei  * security_dump_masked_av - dumps masked permissions during
43344c2d9bdSKaiGai Kohei  * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
43444c2d9bdSKaiGai Kohei  */
43544c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args)
43644c2d9bdSKaiGai Kohei {
43744c2d9bdSKaiGai Kohei 	struct perm_datum *pdatum = d;
43844c2d9bdSKaiGai Kohei 	char **permission_names = args;
43944c2d9bdSKaiGai Kohei 
44044c2d9bdSKaiGai Kohei 	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
44144c2d9bdSKaiGai Kohei 
44244c2d9bdSKaiGai Kohei 	permission_names[pdatum->value - 1] = (char *)k;
44344c2d9bdSKaiGai Kohei 
44444c2d9bdSKaiGai Kohei 	return 0;
44544c2d9bdSKaiGai Kohei }
44644c2d9bdSKaiGai Kohei 
44744c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext,
44844c2d9bdSKaiGai Kohei 				    struct context *tcontext,
44944c2d9bdSKaiGai Kohei 				    u16 tclass,
45044c2d9bdSKaiGai Kohei 				    u32 permissions,
45144c2d9bdSKaiGai Kohei 				    const char *reason)
45244c2d9bdSKaiGai Kohei {
45344c2d9bdSKaiGai Kohei 	struct common_datum *common_dat;
45444c2d9bdSKaiGai Kohei 	struct class_datum *tclass_dat;
45544c2d9bdSKaiGai Kohei 	struct audit_buffer *ab;
45644c2d9bdSKaiGai Kohei 	char *tclass_name;
45744c2d9bdSKaiGai Kohei 	char *scontext_name = NULL;
45844c2d9bdSKaiGai Kohei 	char *tcontext_name = NULL;
45944c2d9bdSKaiGai Kohei 	char *permission_names[32];
4602da5d31bSJames Morris 	int index;
4612da5d31bSJames Morris 	u32 length;
46244c2d9bdSKaiGai Kohei 	bool need_comma = false;
46344c2d9bdSKaiGai Kohei 
46444c2d9bdSKaiGai Kohei 	if (!permissions)
46544c2d9bdSKaiGai Kohei 		return;
46644c2d9bdSKaiGai Kohei 
467ac76c05bSEric Paris 	tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1);
46844c2d9bdSKaiGai Kohei 	tclass_dat = policydb.class_val_to_struct[tclass - 1];
46944c2d9bdSKaiGai Kohei 	common_dat = tclass_dat->comdatum;
47044c2d9bdSKaiGai Kohei 
47144c2d9bdSKaiGai Kohei 	/* init permission_names */
47244c2d9bdSKaiGai Kohei 	if (common_dat &&
47344c2d9bdSKaiGai Kohei 	    hashtab_map(common_dat->permissions.table,
47444c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
47544c2d9bdSKaiGai Kohei 		goto out;
47644c2d9bdSKaiGai Kohei 
47744c2d9bdSKaiGai Kohei 	if (hashtab_map(tclass_dat->permissions.table,
47844c2d9bdSKaiGai Kohei 			dump_masked_av_helper, permission_names) < 0)
47944c2d9bdSKaiGai Kohei 		goto out;
48044c2d9bdSKaiGai Kohei 
48144c2d9bdSKaiGai Kohei 	/* get scontext/tcontext in text form */
48244c2d9bdSKaiGai Kohei 	if (context_struct_to_string(scontext,
48344c2d9bdSKaiGai Kohei 				     &scontext_name, &length) < 0)
48444c2d9bdSKaiGai Kohei 		goto out;
48544c2d9bdSKaiGai Kohei 
48644c2d9bdSKaiGai Kohei 	if (context_struct_to_string(tcontext,
48744c2d9bdSKaiGai Kohei 				     &tcontext_name, &length) < 0)
48844c2d9bdSKaiGai Kohei 		goto out;
48944c2d9bdSKaiGai Kohei 
49044c2d9bdSKaiGai Kohei 	/* audit a message */
49144c2d9bdSKaiGai Kohei 	ab = audit_log_start(current->audit_context,
49244c2d9bdSKaiGai Kohei 			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
49344c2d9bdSKaiGai Kohei 	if (!ab)
49444c2d9bdSKaiGai Kohei 		goto out;
49544c2d9bdSKaiGai Kohei 
49644c2d9bdSKaiGai Kohei 	audit_log_format(ab, "op=security_compute_av reason=%s "
49744c2d9bdSKaiGai Kohei 			 "scontext=%s tcontext=%s tclass=%s perms=",
49844c2d9bdSKaiGai Kohei 			 reason, scontext_name, tcontext_name, tclass_name);
49944c2d9bdSKaiGai Kohei 
50044c2d9bdSKaiGai Kohei 	for (index = 0; index < 32; index++) {
50144c2d9bdSKaiGai Kohei 		u32 mask = (1 << index);
50244c2d9bdSKaiGai Kohei 
50344c2d9bdSKaiGai Kohei 		if ((mask & permissions) == 0)
50444c2d9bdSKaiGai Kohei 			continue;
50544c2d9bdSKaiGai Kohei 
50644c2d9bdSKaiGai Kohei 		audit_log_format(ab, "%s%s",
50744c2d9bdSKaiGai Kohei 				 need_comma ? "," : "",
50844c2d9bdSKaiGai Kohei 				 permission_names[index]
50944c2d9bdSKaiGai Kohei 				 ? permission_names[index] : "????");
51044c2d9bdSKaiGai Kohei 		need_comma = true;
51144c2d9bdSKaiGai Kohei 	}
51244c2d9bdSKaiGai Kohei 	audit_log_end(ab);
51344c2d9bdSKaiGai Kohei out:
51444c2d9bdSKaiGai Kohei 	/* release scontext/tcontext */
51544c2d9bdSKaiGai Kohei 	kfree(tcontext_name);
51644c2d9bdSKaiGai Kohei 	kfree(scontext_name);
51744c2d9bdSKaiGai Kohei 
51844c2d9bdSKaiGai Kohei 	return;
51944c2d9bdSKaiGai Kohei }
52044c2d9bdSKaiGai Kohei 
52144c2d9bdSKaiGai Kohei /*
522d9250deaSKaiGai Kohei  * security_boundary_permission - drops violated permissions
523d9250deaSKaiGai Kohei  * on boundary constraint.
524d9250deaSKaiGai Kohei  */
525d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext,
526d9250deaSKaiGai Kohei 				     struct context *tcontext,
527d9250deaSKaiGai Kohei 				     u16 tclass,
528d9250deaSKaiGai Kohei 				     struct av_decision *avd)
529d9250deaSKaiGai Kohei {
5302ae3ba39SKaiGai Kohei 	struct context lo_scontext;
5312ae3ba39SKaiGai Kohei 	struct context lo_tcontext;
5322ae3ba39SKaiGai Kohei 	struct av_decision lo_avd;
53323bdecb0SEric Paris 	struct type_datum *source;
53423bdecb0SEric Paris 	struct type_datum *target;
5352ae3ba39SKaiGai Kohei 	u32 masked = 0;
536d9250deaSKaiGai Kohei 
53723bdecb0SEric Paris 	source = flex_array_get_ptr(policydb.type_val_to_struct_array,
53823bdecb0SEric Paris 				    scontext->type - 1);
53923bdecb0SEric Paris 	BUG_ON(!source);
54023bdecb0SEric Paris 
54123bdecb0SEric Paris 	target = flex_array_get_ptr(policydb.type_val_to_struct_array,
54223bdecb0SEric Paris 				    tcontext->type - 1);
54323bdecb0SEric Paris 	BUG_ON(!target);
54423bdecb0SEric Paris 
545d9250deaSKaiGai Kohei 	if (source->bounds) {
546d9250deaSKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
547d9250deaSKaiGai Kohei 
548d9250deaSKaiGai Kohei 		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
549d9250deaSKaiGai Kohei 		lo_scontext.type = source->bounds;
550d9250deaSKaiGai Kohei 
551d9250deaSKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
552d9250deaSKaiGai Kohei 					  tcontext,
553d9250deaSKaiGai Kohei 					  tclass,
554d9250deaSKaiGai Kohei 					  &lo_avd);
555d9250deaSKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
556d9250deaSKaiGai Kohei 			return;		/* no masked permission */
557d9250deaSKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5582ae3ba39SKaiGai Kohei 	}
559d9250deaSKaiGai Kohei 
5602ae3ba39SKaiGai Kohei 	if (target->bounds) {
5612ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5622ae3ba39SKaiGai Kohei 
5632ae3ba39SKaiGai Kohei 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5642ae3ba39SKaiGai Kohei 		lo_tcontext.type = target->bounds;
5652ae3ba39SKaiGai Kohei 
5662ae3ba39SKaiGai Kohei 		context_struct_compute_av(scontext,
5672ae3ba39SKaiGai Kohei 					  &lo_tcontext,
5682ae3ba39SKaiGai Kohei 					  tclass,
5692ae3ba39SKaiGai Kohei 					  &lo_avd);
5702ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
5712ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
5722ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5732ae3ba39SKaiGai Kohei 	}
5742ae3ba39SKaiGai Kohei 
5752ae3ba39SKaiGai Kohei 	if (source->bounds && target->bounds) {
5762ae3ba39SKaiGai Kohei 		memset(&lo_avd, 0, sizeof(lo_avd));
5772ae3ba39SKaiGai Kohei 		/*
5782ae3ba39SKaiGai Kohei 		 * lo_scontext and lo_tcontext are already
5792ae3ba39SKaiGai Kohei 		 * set up.
5802ae3ba39SKaiGai Kohei 		 */
5812ae3ba39SKaiGai Kohei 
5822ae3ba39SKaiGai Kohei 		context_struct_compute_av(&lo_scontext,
5832ae3ba39SKaiGai Kohei 					  &lo_tcontext,
5842ae3ba39SKaiGai Kohei 					  tclass,
5852ae3ba39SKaiGai Kohei 					  &lo_avd);
5862ae3ba39SKaiGai Kohei 		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
5872ae3ba39SKaiGai Kohei 			return;		/* no masked permission */
5882ae3ba39SKaiGai Kohei 		masked = ~lo_avd.allowed & avd->allowed;
5892ae3ba39SKaiGai Kohei 	}
5902ae3ba39SKaiGai Kohei 
5912ae3ba39SKaiGai Kohei 	if (masked) {
592d9250deaSKaiGai Kohei 		/* mask violated permissions */
593d9250deaSKaiGai Kohei 		avd->allowed &= ~masked;
594d9250deaSKaiGai Kohei 
59544c2d9bdSKaiGai Kohei 		/* audit masked permissions */
59644c2d9bdSKaiGai Kohei 		security_dump_masked_av(scontext, tcontext,
59744c2d9bdSKaiGai Kohei 					tclass, masked, "bounds");
598d9250deaSKaiGai Kohei 	}
599d9250deaSKaiGai Kohei }
600d9250deaSKaiGai Kohei 
601d9250deaSKaiGai Kohei /*
6021da177e4SLinus Torvalds  * Compute access vectors based on a context structure pair for
6031da177e4SLinus Torvalds  * the permissions in a particular class.
6041da177e4SLinus Torvalds  */
60519439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext,
6061da177e4SLinus Torvalds 				      struct context *tcontext,
6071da177e4SLinus Torvalds 				      u16 tclass,
6081da177e4SLinus Torvalds 				      struct av_decision *avd)
6091da177e4SLinus Torvalds {
6101da177e4SLinus Torvalds 	struct constraint_node *constraint;
6111da177e4SLinus Torvalds 	struct role_allow *ra;
6121da177e4SLinus Torvalds 	struct avtab_key avkey;
613782ebb99SStephen Smalley 	struct avtab_node *node;
6141da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
615782ebb99SStephen Smalley 	struct ebitmap *sattr, *tattr;
616782ebb99SStephen Smalley 	struct ebitmap_node *snode, *tnode;
617782ebb99SStephen Smalley 	unsigned int i, j;
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	avd->allowed = 0;
6201da177e4SLinus Torvalds 	avd->auditallow = 0;
6211da177e4SLinus Torvalds 	avd->auditdeny = 0xffffffff;
6221da177e4SLinus Torvalds 
623c6d3aaa4SStephen Smalley 	if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
624c6d3aaa4SStephen Smalley 		if (printk_ratelimit())
625c6d3aaa4SStephen Smalley 			printk(KERN_WARNING "SELinux:  Invalid class %hu\n", tclass);
62619439d05SStephen Smalley 		return;
627c6d3aaa4SStephen Smalley 	}
6283f12070eSEric Paris 
6293f12070eSEric Paris 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
6303f12070eSEric Paris 
6313f12070eSEric Paris 	/*
6321da177e4SLinus Torvalds 	 * If a specific type enforcement rule was defined for
6331da177e4SLinus Torvalds 	 * this permission check, then use it.
6341da177e4SLinus Torvalds 	 */
6351da177e4SLinus Torvalds 	avkey.target_class = tclass;
636782ebb99SStephen Smalley 	avkey.specified = AVTAB_AV;
6376371dcd3SEric Paris 	sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1);
6386371dcd3SEric Paris 	BUG_ON(!sattr);
6396371dcd3SEric Paris 	tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1);
6406371dcd3SEric Paris 	BUG_ON(!tattr);
6419fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(sattr, snode, i) {
6429fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
643782ebb99SStephen Smalley 			avkey.source_type = i + 1;
644782ebb99SStephen Smalley 			avkey.target_type = j + 1;
645782ebb99SStephen Smalley 			for (node = avtab_search_node(&policydb.te_avtab, &avkey);
646dbc74c65SVesa-Matti Kari 			     node;
647782ebb99SStephen Smalley 			     node = avtab_search_node_next(node, avkey.specified)) {
648782ebb99SStephen Smalley 				if (node->key.specified == AVTAB_ALLOWED)
649782ebb99SStephen Smalley 					avd->allowed |= node->datum.data;
650782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITALLOW)
651782ebb99SStephen Smalley 					avd->auditallow |= node->datum.data;
652782ebb99SStephen Smalley 				else if (node->key.specified == AVTAB_AUDITDENY)
653782ebb99SStephen Smalley 					avd->auditdeny &= node->datum.data;
6541da177e4SLinus Torvalds 			}
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 			/* Check conditional av table for additional permissions */
6571da177e4SLinus Torvalds 			cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
6581da177e4SLinus Torvalds 
659782ebb99SStephen Smalley 		}
660782ebb99SStephen Smalley 	}
661782ebb99SStephen Smalley 
6621da177e4SLinus Torvalds 	/*
6631da177e4SLinus Torvalds 	 * Remove any permissions prohibited by a constraint (this includes
6641da177e4SLinus Torvalds 	 * the MLS policy).
6651da177e4SLinus Torvalds 	 */
6661da177e4SLinus Torvalds 	constraint = tclass_datum->constraints;
6671da177e4SLinus Torvalds 	while (constraint) {
6681da177e4SLinus Torvalds 		if ((constraint->permissions & (avd->allowed)) &&
6691da177e4SLinus Torvalds 		    !constraint_expr_eval(scontext, tcontext, NULL,
6701da177e4SLinus Torvalds 					  constraint->expr)) {
671caabbdc0SKaiGai Kohei 			avd->allowed &= ~(constraint->permissions);
6721da177e4SLinus Torvalds 		}
6731da177e4SLinus Torvalds 		constraint = constraint->next;
6741da177e4SLinus Torvalds 	}
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	/*
6771da177e4SLinus Torvalds 	 * If checking process transition permission and the
6781da177e4SLinus Torvalds 	 * role is changing, then check the (current_role, new_role)
6791da177e4SLinus Torvalds 	 * pair.
6801da177e4SLinus Torvalds 	 */
681c6d3aaa4SStephen Smalley 	if (tclass == policydb.process_class &&
682c6d3aaa4SStephen Smalley 	    (avd->allowed & policydb.process_trans_perms) &&
6831da177e4SLinus Torvalds 	    scontext->role != tcontext->role) {
6841da177e4SLinus Torvalds 		for (ra = policydb.role_allow; ra; ra = ra->next) {
6851da177e4SLinus Torvalds 			if (scontext->role == ra->role &&
6861da177e4SLinus Torvalds 			    tcontext->role == ra->new_role)
6871da177e4SLinus Torvalds 				break;
6881da177e4SLinus Torvalds 		}
6891da177e4SLinus Torvalds 		if (!ra)
690c6d3aaa4SStephen Smalley 			avd->allowed &= ~policydb.process_trans_perms;
6911da177e4SLinus Torvalds 	}
6921da177e4SLinus Torvalds 
693d9250deaSKaiGai Kohei 	/*
694d9250deaSKaiGai Kohei 	 * If the given source and target types have boundary
695d9250deaSKaiGai Kohei 	 * constraint, lazy checks have to mask any violated
696d9250deaSKaiGai Kohei 	 * permission and notice it to userspace via audit.
697d9250deaSKaiGai Kohei 	 */
698d9250deaSKaiGai Kohei 	type_attribute_bounds_av(scontext, tcontext,
69919439d05SStephen Smalley 				 tclass, avd);
70022df4adbSStephen Smalley }
70122df4adbSStephen Smalley 
7021da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext,
7031da177e4SLinus Torvalds 					   struct context *ncontext,
7041da177e4SLinus Torvalds 					   struct context *tcontext,
7051da177e4SLinus Torvalds 					   u16 tclass)
7061da177e4SLinus Torvalds {
7071da177e4SLinus Torvalds 	char *o = NULL, *n = NULL, *t = NULL;
7081da177e4SLinus Torvalds 	u32 olen, nlen, tlen;
7091da177e4SLinus Torvalds 
7104b02b524SEric Paris 	if (context_struct_to_string(ocontext, &o, &olen))
7111da177e4SLinus Torvalds 		goto out;
7124b02b524SEric Paris 	if (context_struct_to_string(ncontext, &n, &nlen))
7131da177e4SLinus Torvalds 		goto out;
7144b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
7151da177e4SLinus Torvalds 		goto out;
7169ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
7171da177e4SLinus Torvalds 		  "security_validate_transition:  denied for"
7181da177e4SLinus Torvalds 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
719ac76c05bSEric Paris 		  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
7201da177e4SLinus Torvalds out:
7211da177e4SLinus Torvalds 	kfree(o);
7221da177e4SLinus Torvalds 	kfree(n);
7231da177e4SLinus Torvalds 	kfree(t);
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	if (!selinux_enforcing)
7261da177e4SLinus Torvalds 		return 0;
7271da177e4SLinus Torvalds 	return -EPERM;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
731c6d3aaa4SStephen Smalley 				 u16 orig_tclass)
7321da177e4SLinus Torvalds {
7331da177e4SLinus Torvalds 	struct context *ocontext;
7341da177e4SLinus Torvalds 	struct context *ncontext;
7351da177e4SLinus Torvalds 	struct context *tcontext;
7361da177e4SLinus Torvalds 	struct class_datum *tclass_datum;
7371da177e4SLinus Torvalds 	struct constraint_node *constraint;
738c6d3aaa4SStephen Smalley 	u16 tclass;
7391da177e4SLinus Torvalds 	int rc = 0;
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	if (!ss_initialized)
7421da177e4SLinus Torvalds 		return 0;
7431da177e4SLinus Torvalds 
7440804d113SJames Morris 	read_lock(&policy_rwlock);
7451da177e4SLinus Torvalds 
746c6d3aaa4SStephen Smalley 	tclass = unmap_class(orig_tclass);
747c6d3aaa4SStephen Smalley 
7481da177e4SLinus Torvalds 	if (!tclass || tclass > policydb.p_classes.nprim) {
749744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n",
750744ba35eSEric Paris 			__func__, tclass);
7511da177e4SLinus Torvalds 		rc = -EINVAL;
7521da177e4SLinus Torvalds 		goto out;
7531da177e4SLinus Torvalds 	}
7541da177e4SLinus Torvalds 	tclass_datum = policydb.class_val_to_struct[tclass - 1];
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	ocontext = sidtab_search(&sidtab, oldsid);
7571da177e4SLinus Torvalds 	if (!ocontext) {
758744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
759744ba35eSEric Paris 			__func__, oldsid);
7601da177e4SLinus Torvalds 		rc = -EINVAL;
7611da177e4SLinus Torvalds 		goto out;
7621da177e4SLinus Torvalds 	}
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	ncontext = sidtab_search(&sidtab, newsid);
7651da177e4SLinus Torvalds 	if (!ncontext) {
766744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
767744ba35eSEric Paris 			__func__, newsid);
7681da177e4SLinus Torvalds 		rc = -EINVAL;
7691da177e4SLinus Torvalds 		goto out;
7701da177e4SLinus Torvalds 	}
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tasksid);
7731da177e4SLinus Torvalds 	if (!tcontext) {
774744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
775744ba35eSEric Paris 			__func__, tasksid);
7761da177e4SLinus Torvalds 		rc = -EINVAL;
7771da177e4SLinus Torvalds 		goto out;
7781da177e4SLinus Torvalds 	}
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 	constraint = tclass_datum->validatetrans;
7811da177e4SLinus Torvalds 	while (constraint) {
7821da177e4SLinus Torvalds 		if (!constraint_expr_eval(ocontext, ncontext, tcontext,
7831da177e4SLinus Torvalds 					  constraint->expr)) {
7841da177e4SLinus Torvalds 			rc = security_validtrans_handle_fail(ocontext, ncontext,
7851da177e4SLinus Torvalds 							     tcontext, tclass);
7861da177e4SLinus Torvalds 			goto out;
7871da177e4SLinus Torvalds 		}
7881da177e4SLinus Torvalds 		constraint = constraint->next;
7891da177e4SLinus Torvalds 	}
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds out:
7920804d113SJames Morris 	read_unlock(&policy_rwlock);
7931da177e4SLinus Torvalds 	return rc;
7941da177e4SLinus Torvalds }
7951da177e4SLinus Torvalds 
796d9250deaSKaiGai Kohei /*
797d9250deaSKaiGai Kohei  * security_bounded_transition - check whether the given
798d9250deaSKaiGai Kohei  * transition is directed to bounded, or not.
799d9250deaSKaiGai Kohei  * It returns 0, if @newsid is bounded by @oldsid.
800d9250deaSKaiGai Kohei  * Otherwise, it returns error code.
801d9250deaSKaiGai Kohei  *
802d9250deaSKaiGai Kohei  * @oldsid : current security identifier
803d9250deaSKaiGai Kohei  * @newsid : destinated security identifier
804d9250deaSKaiGai Kohei  */
805d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid)
806d9250deaSKaiGai Kohei {
807d9250deaSKaiGai Kohei 	struct context *old_context, *new_context;
808d9250deaSKaiGai Kohei 	struct type_datum *type;
809d9250deaSKaiGai Kohei 	int index;
8104b02b524SEric Paris 	int rc;
811d9250deaSKaiGai Kohei 
812d9250deaSKaiGai Kohei 	read_lock(&policy_rwlock);
813d9250deaSKaiGai Kohei 
8144b02b524SEric Paris 	rc = -EINVAL;
815d9250deaSKaiGai Kohei 	old_context = sidtab_search(&sidtab, old_sid);
816d9250deaSKaiGai Kohei 	if (!old_context) {
817d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
818d9250deaSKaiGai Kohei 		       __func__, old_sid);
819d9250deaSKaiGai Kohei 		goto out;
820d9250deaSKaiGai Kohei 	}
821d9250deaSKaiGai Kohei 
8224b02b524SEric Paris 	rc = -EINVAL;
823d9250deaSKaiGai Kohei 	new_context = sidtab_search(&sidtab, new_sid);
824d9250deaSKaiGai Kohei 	if (!new_context) {
825d9250deaSKaiGai Kohei 		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
826d9250deaSKaiGai Kohei 		       __func__, new_sid);
827d9250deaSKaiGai Kohei 		goto out;
828d9250deaSKaiGai Kohei 	}
829d9250deaSKaiGai Kohei 
830d9250deaSKaiGai Kohei 	rc = 0;
8314b02b524SEric Paris 	/* type/domain unchanged */
8324b02b524SEric Paris 	if (old_context->type == new_context->type)
833d9250deaSKaiGai Kohei 		goto out;
834d9250deaSKaiGai Kohei 
835d9250deaSKaiGai Kohei 	index = new_context->type;
836d9250deaSKaiGai Kohei 	while (true) {
83723bdecb0SEric Paris 		type = flex_array_get_ptr(policydb.type_val_to_struct_array,
83823bdecb0SEric Paris 					  index - 1);
839d9250deaSKaiGai Kohei 		BUG_ON(!type);
840d9250deaSKaiGai Kohei 
841d9250deaSKaiGai Kohei 		/* not bounded anymore */
842d9250deaSKaiGai Kohei 		rc = -EPERM;
8434b02b524SEric Paris 		if (!type->bounds)
844d9250deaSKaiGai Kohei 			break;
845d9250deaSKaiGai Kohei 
846d9250deaSKaiGai Kohei 		/* @newsid is bounded by @oldsid */
847d9250deaSKaiGai Kohei 		rc = 0;
8484b02b524SEric Paris 		if (type->bounds == old_context->type)
849d9250deaSKaiGai Kohei 			break;
8504b02b524SEric Paris 
851d9250deaSKaiGai Kohei 		index = type->bounds;
852d9250deaSKaiGai Kohei 	}
85344c2d9bdSKaiGai Kohei 
85444c2d9bdSKaiGai Kohei 	if (rc) {
85544c2d9bdSKaiGai Kohei 		char *old_name = NULL;
85644c2d9bdSKaiGai Kohei 		char *new_name = NULL;
8572da5d31bSJames Morris 		u32 length;
85844c2d9bdSKaiGai Kohei 
85944c2d9bdSKaiGai Kohei 		if (!context_struct_to_string(old_context,
86044c2d9bdSKaiGai Kohei 					      &old_name, &length) &&
86144c2d9bdSKaiGai Kohei 		    !context_struct_to_string(new_context,
86244c2d9bdSKaiGai Kohei 					      &new_name, &length)) {
86344c2d9bdSKaiGai Kohei 			audit_log(current->audit_context,
86444c2d9bdSKaiGai Kohei 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
86544c2d9bdSKaiGai Kohei 				  "op=security_bounded_transition "
86644c2d9bdSKaiGai Kohei 				  "result=denied "
86744c2d9bdSKaiGai Kohei 				  "oldcontext=%s newcontext=%s",
86844c2d9bdSKaiGai Kohei 				  old_name, new_name);
86944c2d9bdSKaiGai Kohei 		}
87044c2d9bdSKaiGai Kohei 		kfree(new_name);
87144c2d9bdSKaiGai Kohei 		kfree(old_name);
87244c2d9bdSKaiGai Kohei 	}
873d9250deaSKaiGai Kohei out:
874d9250deaSKaiGai Kohei 	read_unlock(&policy_rwlock);
875d9250deaSKaiGai Kohei 
876d9250deaSKaiGai Kohei 	return rc;
877d9250deaSKaiGai Kohei }
878d9250deaSKaiGai Kohei 
87919439d05SStephen Smalley static void avd_init(struct av_decision *avd)
880c6d3aaa4SStephen Smalley {
88119439d05SStephen Smalley 	avd->allowed = 0;
88219439d05SStephen Smalley 	avd->auditallow = 0;
88319439d05SStephen Smalley 	avd->auditdeny = 0xffffffff;
88419439d05SStephen Smalley 	avd->seqno = latest_granting;
88519439d05SStephen Smalley 	avd->flags = 0;
886c6d3aaa4SStephen Smalley }
887c6d3aaa4SStephen Smalley 
888c6d3aaa4SStephen Smalley 
8891da177e4SLinus Torvalds /**
8901da177e4SLinus Torvalds  * security_compute_av - Compute access vector decisions.
8911da177e4SLinus Torvalds  * @ssid: source security identifier
8921da177e4SLinus Torvalds  * @tsid: target security identifier
8931da177e4SLinus Torvalds  * @tclass: target security class
8941da177e4SLinus Torvalds  * @avd: access vector decisions
8951da177e4SLinus Torvalds  *
8961da177e4SLinus Torvalds  * Compute a set of access vector decisions based on the
8971da177e4SLinus Torvalds  * SID pair (@ssid, @tsid) for the permissions in @tclass.
8981da177e4SLinus Torvalds  */
89919439d05SStephen Smalley void security_compute_av(u32 ssid,
9001da177e4SLinus Torvalds 			 u32 tsid,
901c6d3aaa4SStephen Smalley 			 u16 orig_tclass,
902c6d3aaa4SStephen Smalley 			 struct av_decision *avd)
903c6d3aaa4SStephen Smalley {
904c6d3aaa4SStephen Smalley 	u16 tclass;
90519439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
906c6d3aaa4SStephen Smalley 
907b7f3008aSStephen Smalley 	read_lock(&policy_rwlock);
90819439d05SStephen Smalley 	avd_init(avd);
909c6d3aaa4SStephen Smalley 	if (!ss_initialized)
910c6d3aaa4SStephen Smalley 		goto allow;
911c6d3aaa4SStephen Smalley 
91219439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
91319439d05SStephen Smalley 	if (!scontext) {
91419439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
91519439d05SStephen Smalley 		       __func__, ssid);
91619439d05SStephen Smalley 		goto out;
91719439d05SStephen Smalley 	}
91819439d05SStephen Smalley 
91919439d05SStephen Smalley 	/* permissive domain? */
92019439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
92119439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
92219439d05SStephen Smalley 
92319439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
92419439d05SStephen Smalley 	if (!tcontext) {
92519439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
92619439d05SStephen Smalley 		       __func__, tsid);
92719439d05SStephen Smalley 		goto out;
92819439d05SStephen Smalley 	}
92919439d05SStephen Smalley 
930c6d3aaa4SStephen Smalley 	tclass = unmap_class(orig_tclass);
931c6d3aaa4SStephen Smalley 	if (unlikely(orig_tclass && !tclass)) {
932c6d3aaa4SStephen Smalley 		if (policydb.allow_unknown)
933c6d3aaa4SStephen Smalley 			goto allow;
934b7f3008aSStephen Smalley 		goto out;
935c6d3aaa4SStephen Smalley 	}
93619439d05SStephen Smalley 	context_struct_compute_av(scontext, tcontext, tclass, avd);
937c6d3aaa4SStephen Smalley 	map_decision(orig_tclass, avd, policydb.allow_unknown);
938b7f3008aSStephen Smalley out:
939c6d3aaa4SStephen Smalley 	read_unlock(&policy_rwlock);
94019439d05SStephen Smalley 	return;
941c6d3aaa4SStephen Smalley allow:
942c6d3aaa4SStephen Smalley 	avd->allowed = 0xffffffff;
943b7f3008aSStephen Smalley 	goto out;
944c6d3aaa4SStephen Smalley }
945c6d3aaa4SStephen Smalley 
94619439d05SStephen Smalley void security_compute_av_user(u32 ssid,
947c6d3aaa4SStephen Smalley 			      u32 tsid,
9481da177e4SLinus Torvalds 			      u16 tclass,
9491da177e4SLinus Torvalds 			      struct av_decision *avd)
9501da177e4SLinus Torvalds {
95119439d05SStephen Smalley 	struct context *scontext = NULL, *tcontext = NULL;
9521da177e4SLinus Torvalds 
9530804d113SJames Morris 	read_lock(&policy_rwlock);
95419439d05SStephen Smalley 	avd_init(avd);
95519439d05SStephen Smalley 	if (!ss_initialized)
95619439d05SStephen Smalley 		goto allow;
95719439d05SStephen Smalley 
95819439d05SStephen Smalley 	scontext = sidtab_search(&sidtab, ssid);
95919439d05SStephen Smalley 	if (!scontext) {
96019439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
96119439d05SStephen Smalley 		       __func__, ssid);
96219439d05SStephen Smalley 		goto out;
96319439d05SStephen Smalley 	}
96419439d05SStephen Smalley 
96519439d05SStephen Smalley 	/* permissive domain? */
96619439d05SStephen Smalley 	if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
96719439d05SStephen Smalley 		avd->flags |= AVD_FLAGS_PERMISSIVE;
96819439d05SStephen Smalley 
96919439d05SStephen Smalley 	tcontext = sidtab_search(&sidtab, tsid);
97019439d05SStephen Smalley 	if (!tcontext) {
97119439d05SStephen Smalley 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
97219439d05SStephen Smalley 		       __func__, tsid);
97319439d05SStephen Smalley 		goto out;
97419439d05SStephen Smalley 	}
97519439d05SStephen Smalley 
97619439d05SStephen Smalley 	if (unlikely(!tclass)) {
97719439d05SStephen Smalley 		if (policydb.allow_unknown)
97819439d05SStephen Smalley 			goto allow;
97919439d05SStephen Smalley 		goto out;
98019439d05SStephen Smalley 	}
98119439d05SStephen Smalley 
98219439d05SStephen Smalley 	context_struct_compute_av(scontext, tcontext, tclass, avd);
98319439d05SStephen Smalley  out:
9840804d113SJames Morris 	read_unlock(&policy_rwlock);
98519439d05SStephen Smalley 	return;
98619439d05SStephen Smalley allow:
98719439d05SStephen Smalley 	avd->allowed = 0xffffffff;
98819439d05SStephen Smalley 	goto out;
9891da177e4SLinus Torvalds }
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds /*
9921da177e4SLinus Torvalds  * Write the security context string representation of
9931da177e4SLinus Torvalds  * the context structure `context' into a dynamically
9941da177e4SLinus Torvalds  * allocated string of the correct size.  Set `*scontext'
9951da177e4SLinus Torvalds  * to point to this string and set `*scontext_len' to
9961da177e4SLinus Torvalds  * the length of the string.
9971da177e4SLinus Torvalds  */
9981da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
9991da177e4SLinus Torvalds {
10001da177e4SLinus Torvalds 	char *scontextp;
10011da177e4SLinus Torvalds 
1002d5630b9dSEric Paris 	if (scontext)
10031da177e4SLinus Torvalds 		*scontext = NULL;
10041da177e4SLinus Torvalds 	*scontext_len = 0;
10051da177e4SLinus Torvalds 
100612b29f34SStephen Smalley 	if (context->len) {
100712b29f34SStephen Smalley 		*scontext_len = context->len;
100812b29f34SStephen Smalley 		*scontext = kstrdup(context->str, GFP_ATOMIC);
100912b29f34SStephen Smalley 		if (!(*scontext))
101012b29f34SStephen Smalley 			return -ENOMEM;
101112b29f34SStephen Smalley 		return 0;
101212b29f34SStephen Smalley 	}
101312b29f34SStephen Smalley 
10141da177e4SLinus Torvalds 	/* Compute the size of the context. */
1015ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1;
1016ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1;
1017ac76c05bSEric Paris 	*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1;
10181da177e4SLinus Torvalds 	*scontext_len += mls_compute_context_len(context);
10191da177e4SLinus Torvalds 
1020d5630b9dSEric Paris 	if (!scontext)
1021d5630b9dSEric Paris 		return 0;
1022d5630b9dSEric Paris 
10231da177e4SLinus Torvalds 	/* Allocate space for the context; caller must free this space. */
10241da177e4SLinus Torvalds 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
10255d55a345SEric Paris 	if (!scontextp)
10261da177e4SLinus Torvalds 		return -ENOMEM;
10271da177e4SLinus Torvalds 	*scontext = scontextp;
10281da177e4SLinus Torvalds 
10291da177e4SLinus Torvalds 	/*
10301da177e4SLinus Torvalds 	 * Copy the user name, role name and type name into the context.
10311da177e4SLinus Torvalds 	 */
10321da177e4SLinus Torvalds 	sprintf(scontextp, "%s:%s:%s",
1033ac76c05bSEric Paris 		sym_name(&policydb, SYM_USERS, context->user - 1),
1034ac76c05bSEric Paris 		sym_name(&policydb, SYM_ROLES, context->role - 1),
1035ac76c05bSEric Paris 		sym_name(&policydb, SYM_TYPES, context->type - 1));
1036ac76c05bSEric Paris 	scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
1037ac76c05bSEric Paris 		     1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
1038ac76c05bSEric Paris 		     1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 	mls_sid_to_context(context, &scontextp);
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 	*scontextp = 0;
10431da177e4SLinus Torvalds 
10441da177e4SLinus Torvalds 	return 0;
10451da177e4SLinus Torvalds }
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds #include "initial_sid_to_string.h"
10481da177e4SLinus Torvalds 
1049f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1050f0ee2e46SJames Carter {
1051f0ee2e46SJames Carter 	if (unlikely(sid > SECINITSID_NUM))
1052f0ee2e46SJames Carter 		return NULL;
1053f0ee2e46SJames Carter 	return initial_sid_to_string[sid];
1054f0ee2e46SJames Carter }
1055f0ee2e46SJames Carter 
105612b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
105712b29f34SStephen Smalley 					u32 *scontext_len, int force)
10581da177e4SLinus Torvalds {
10591da177e4SLinus Torvalds 	struct context *context;
10601da177e4SLinus Torvalds 	int rc = 0;
10611da177e4SLinus Torvalds 
1062d5630b9dSEric Paris 	if (scontext)
10634f4acf3aSStephen Smalley 		*scontext = NULL;
10644f4acf3aSStephen Smalley 	*scontext_len  = 0;
10654f4acf3aSStephen Smalley 
10661da177e4SLinus Torvalds 	if (!ss_initialized) {
10671da177e4SLinus Torvalds 		if (sid <= SECINITSID_NUM) {
10681da177e4SLinus Torvalds 			char *scontextp;
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
1071d5630b9dSEric Paris 			if (!scontext)
1072d5630b9dSEric Paris 				goto out;
10731da177e4SLinus Torvalds 			scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
10740cccca06SSerge E. Hallyn 			if (!scontextp) {
10750cccca06SSerge E. Hallyn 				rc = -ENOMEM;
10760cccca06SSerge E. Hallyn 				goto out;
10770cccca06SSerge E. Hallyn 			}
10781da177e4SLinus Torvalds 			strcpy(scontextp, initial_sid_to_string[sid]);
10791da177e4SLinus Torvalds 			*scontext = scontextp;
10801da177e4SLinus Torvalds 			goto out;
10811da177e4SLinus Torvalds 		}
1082744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  called before initial "
1083744ba35eSEric Paris 		       "load_policy on unknown SID %d\n", __func__, sid);
10841da177e4SLinus Torvalds 		rc = -EINVAL;
10851da177e4SLinus Torvalds 		goto out;
10861da177e4SLinus Torvalds 	}
10870804d113SJames Morris 	read_lock(&policy_rwlock);
108812b29f34SStephen Smalley 	if (force)
108912b29f34SStephen Smalley 		context = sidtab_search_force(&sidtab, sid);
109012b29f34SStephen Smalley 	else
10911da177e4SLinus Torvalds 		context = sidtab_search(&sidtab, sid);
10921da177e4SLinus Torvalds 	if (!context) {
1093744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1094744ba35eSEric Paris 			__func__, sid);
10951da177e4SLinus Torvalds 		rc = -EINVAL;
10961da177e4SLinus Torvalds 		goto out_unlock;
10971da177e4SLinus Torvalds 	}
10981da177e4SLinus Torvalds 	rc = context_struct_to_string(context, scontext, scontext_len);
10991da177e4SLinus Torvalds out_unlock:
11000804d113SJames Morris 	read_unlock(&policy_rwlock);
11011da177e4SLinus Torvalds out:
11021da177e4SLinus Torvalds 	return rc;
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds }
11051da177e4SLinus Torvalds 
110612b29f34SStephen Smalley /**
110712b29f34SStephen Smalley  * security_sid_to_context - Obtain a context for a given SID.
110812b29f34SStephen Smalley  * @sid: security identifier, SID
110912b29f34SStephen Smalley  * @scontext: security context
111012b29f34SStephen Smalley  * @scontext_len: length in bytes
111112b29f34SStephen Smalley  *
111212b29f34SStephen Smalley  * Write the string representation of the context associated with @sid
111312b29f34SStephen Smalley  * into a dynamically allocated string of the correct size.  Set @scontext
111412b29f34SStephen Smalley  * to point to this string and set @scontext_len to the length of the string.
111512b29f34SStephen Smalley  */
111612b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
11171da177e4SLinus Torvalds {
111812b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 0);
111912b29f34SStephen Smalley }
112012b29f34SStephen Smalley 
112112b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
112212b29f34SStephen Smalley {
112312b29f34SStephen Smalley 	return security_sid_to_context_core(sid, scontext, scontext_len, 1);
112412b29f34SStephen Smalley }
112512b29f34SStephen Smalley 
11269a59daa0SStephen Smalley /*
11279a59daa0SStephen Smalley  * Caveat:  Mutates scontext.
11289a59daa0SStephen Smalley  */
112912b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
113012b29f34SStephen Smalley 				    struct sidtab *sidtabp,
11319a59daa0SStephen Smalley 				    char *scontext,
113212b29f34SStephen Smalley 				    u32 scontext_len,
113312b29f34SStephen Smalley 				    struct context *ctx,
11349a59daa0SStephen Smalley 				    u32 def_sid)
113512b29f34SStephen Smalley {
11361da177e4SLinus Torvalds 	struct role_datum *role;
11371da177e4SLinus Torvalds 	struct type_datum *typdatum;
11381da177e4SLinus Torvalds 	struct user_datum *usrdatum;
11391da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
11401da177e4SLinus Torvalds 	int rc = 0;
11411da177e4SLinus Torvalds 
114212b29f34SStephen Smalley 	context_init(ctx);
114312b29f34SStephen Smalley 
114412b29f34SStephen Smalley 	/* Parse the security context. */
114512b29f34SStephen Smalley 
114612b29f34SStephen Smalley 	rc = -EINVAL;
11479a59daa0SStephen Smalley 	scontextp = (char *) scontext;
114812b29f34SStephen Smalley 
114912b29f34SStephen Smalley 	/* Extract the user. */
115012b29f34SStephen Smalley 	p = scontextp;
115112b29f34SStephen Smalley 	while (*p && *p != ':')
115212b29f34SStephen Smalley 		p++;
115312b29f34SStephen Smalley 
115412b29f34SStephen Smalley 	if (*p == 0)
115512b29f34SStephen Smalley 		goto out;
115612b29f34SStephen Smalley 
115712b29f34SStephen Smalley 	*p++ = 0;
115812b29f34SStephen Smalley 
115912b29f34SStephen Smalley 	usrdatum = hashtab_search(pol->p_users.table, scontextp);
116012b29f34SStephen Smalley 	if (!usrdatum)
116112b29f34SStephen Smalley 		goto out;
116212b29f34SStephen Smalley 
116312b29f34SStephen Smalley 	ctx->user = usrdatum->value;
116412b29f34SStephen Smalley 
116512b29f34SStephen Smalley 	/* Extract role. */
116612b29f34SStephen Smalley 	scontextp = p;
116712b29f34SStephen Smalley 	while (*p && *p != ':')
116812b29f34SStephen Smalley 		p++;
116912b29f34SStephen Smalley 
117012b29f34SStephen Smalley 	if (*p == 0)
117112b29f34SStephen Smalley 		goto out;
117212b29f34SStephen Smalley 
117312b29f34SStephen Smalley 	*p++ = 0;
117412b29f34SStephen Smalley 
117512b29f34SStephen Smalley 	role = hashtab_search(pol->p_roles.table, scontextp);
117612b29f34SStephen Smalley 	if (!role)
117712b29f34SStephen Smalley 		goto out;
117812b29f34SStephen Smalley 	ctx->role = role->value;
117912b29f34SStephen Smalley 
118012b29f34SStephen Smalley 	/* Extract type. */
118112b29f34SStephen Smalley 	scontextp = p;
118212b29f34SStephen Smalley 	while (*p && *p != ':')
118312b29f34SStephen Smalley 		p++;
118412b29f34SStephen Smalley 	oldc = *p;
118512b29f34SStephen Smalley 	*p++ = 0;
118612b29f34SStephen Smalley 
118712b29f34SStephen Smalley 	typdatum = hashtab_search(pol->p_types.table, scontextp);
1188d9250deaSKaiGai Kohei 	if (!typdatum || typdatum->attribute)
118912b29f34SStephen Smalley 		goto out;
119012b29f34SStephen Smalley 
119112b29f34SStephen Smalley 	ctx->type = typdatum->value;
119212b29f34SStephen Smalley 
119312b29f34SStephen Smalley 	rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
119412b29f34SStephen Smalley 	if (rc)
119512b29f34SStephen Smalley 		goto out;
119612b29f34SStephen Smalley 
119712b29f34SStephen Smalley 	rc = -EINVAL;
11984b02b524SEric Paris 	if ((p - scontext) < scontext_len)
119912b29f34SStephen Smalley 		goto out;
120012b29f34SStephen Smalley 
120112b29f34SStephen Smalley 	/* Check the validity of the new context. */
12024b02b524SEric Paris 	if (!policydb_context_isvalid(pol, ctx))
120312b29f34SStephen Smalley 		goto out;
120412b29f34SStephen Smalley 	rc = 0;
120512b29f34SStephen Smalley out:
12068e531af9SEric Paris 	if (rc)
12078e531af9SEric Paris 		context_destroy(ctx);
120812b29f34SStephen Smalley 	return rc;
120912b29f34SStephen Smalley }
121012b29f34SStephen Smalley 
121112b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
121212b29f34SStephen Smalley 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
121312b29f34SStephen Smalley 					int force)
121412b29f34SStephen Smalley {
12159a59daa0SStephen Smalley 	char *scontext2, *str = NULL;
121612b29f34SStephen Smalley 	struct context context;
121712b29f34SStephen Smalley 	int rc = 0;
121812b29f34SStephen Smalley 
12191da177e4SLinus Torvalds 	if (!ss_initialized) {
12201da177e4SLinus Torvalds 		int i;
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
12231da177e4SLinus Torvalds 			if (!strcmp(initial_sid_to_string[i], scontext)) {
12241da177e4SLinus Torvalds 				*sid = i;
12259a59daa0SStephen Smalley 				return 0;
12261da177e4SLinus Torvalds 			}
12271da177e4SLinus Torvalds 		}
12281da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
12299a59daa0SStephen Smalley 		return 0;
12301da177e4SLinus Torvalds 	}
12311da177e4SLinus Torvalds 	*sid = SECSID_NULL;
12321da177e4SLinus Torvalds 
12339a59daa0SStephen Smalley 	/* Copy the string so that we can modify the copy as we parse it. */
12349a59daa0SStephen Smalley 	scontext2 = kmalloc(scontext_len + 1, gfp_flags);
12359a59daa0SStephen Smalley 	if (!scontext2)
12369a59daa0SStephen Smalley 		return -ENOMEM;
12379a59daa0SStephen Smalley 	memcpy(scontext2, scontext, scontext_len);
12389a59daa0SStephen Smalley 	scontext2[scontext_len] = 0;
12399a59daa0SStephen Smalley 
12409a59daa0SStephen Smalley 	if (force) {
12419a59daa0SStephen Smalley 		/* Save another copy for storing in uninterpreted form */
12424b02b524SEric Paris 		rc = -ENOMEM;
12439a59daa0SStephen Smalley 		str = kstrdup(scontext2, gfp_flags);
12444b02b524SEric Paris 		if (!str)
12454b02b524SEric Paris 			goto out;
12469a59daa0SStephen Smalley 	}
12479a59daa0SStephen Smalley 
12480804d113SJames Morris 	read_lock(&policy_rwlock);
12494b02b524SEric Paris 	rc = string_to_context_struct(&policydb, &sidtab, scontext2,
12504b02b524SEric Paris 				      scontext_len, &context, def_sid);
125112b29f34SStephen Smalley 	if (rc == -EINVAL && force) {
12529a59daa0SStephen Smalley 		context.str = str;
125312b29f34SStephen Smalley 		context.len = scontext_len;
12549a59daa0SStephen Smalley 		str = NULL;
125512b29f34SStephen Smalley 	} else if (rc)
12564b02b524SEric Paris 		goto out_unlock;
12571da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &context, sid);
12581da177e4SLinus Torvalds 	context_destroy(&context);
12594b02b524SEric Paris out_unlock:
12600804d113SJames Morris 	read_unlock(&policy_rwlock);
12614b02b524SEric Paris out:
12629a59daa0SStephen Smalley 	kfree(scontext2);
12639a59daa0SStephen Smalley 	kfree(str);
12641da177e4SLinus Torvalds 	return rc;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds 
1267f5c1d5b2SJames Morris /**
1268f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
1269f5c1d5b2SJames Morris  * @scontext: security context
1270f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1271f5c1d5b2SJames Morris  * @sid: security identifier, SID
1272f5c1d5b2SJames Morris  *
1273f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1274f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1275f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1276f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1277f5c1d5b2SJames Morris  */
12788f0cfa52SDavid Howells int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
1279f5c1d5b2SJames Morris {
1280f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
128112b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 0);
1282f5c1d5b2SJames Morris }
1283f5c1d5b2SJames Morris 
1284f5c1d5b2SJames Morris /**
1285f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
1286f5c1d5b2SJames Morris  * falling back to specified default if needed.
1287f5c1d5b2SJames Morris  *
1288f5c1d5b2SJames Morris  * @scontext: security context
1289f5c1d5b2SJames Morris  * @scontext_len: length in bytes
1290f5c1d5b2SJames Morris  * @sid: security identifier, SID
1291d133a960SGabriel Craciunescu  * @def_sid: default SID to assign on error
1292f5c1d5b2SJames Morris  *
1293f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
1294f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
1295f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
1296f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
1297f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
129812b29f34SStephen Smalley  * Implicitly forces adding of the context even if it cannot be mapped yet.
1299f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1300f5c1d5b2SJames Morris  * memory is available, or 0 on success.
1301f5c1d5b2SJames Morris  */
13027bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len,
13037bf570dcSDavid Howells 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1304f5c1d5b2SJames Morris {
1305f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
130612b29f34SStephen Smalley 					    sid, def_sid, gfp_flags, 1);
130712b29f34SStephen Smalley }
130812b29f34SStephen Smalley 
130912b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
131012b29f34SStephen Smalley 				  u32 *sid)
131112b29f34SStephen Smalley {
131212b29f34SStephen Smalley 	return security_context_to_sid_core(scontext, scontext_len,
131312b29f34SStephen Smalley 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1314f5c1d5b2SJames Morris }
1315f5c1d5b2SJames Morris 
13161da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
13171da177e4SLinus Torvalds 	struct context *scontext,
13181da177e4SLinus Torvalds 	struct context *tcontext,
13191da177e4SLinus Torvalds 	u16 tclass,
13201da177e4SLinus Torvalds 	struct context *newcontext)
13211da177e4SLinus Torvalds {
13221da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
13231da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
13241da177e4SLinus Torvalds 
13254b02b524SEric Paris 	if (context_struct_to_string(scontext, &s, &slen))
13261da177e4SLinus Torvalds 		goto out;
13274b02b524SEric Paris 	if (context_struct_to_string(tcontext, &t, &tlen))
13281da177e4SLinus Torvalds 		goto out;
13294b02b524SEric Paris 	if (context_struct_to_string(newcontext, &n, &nlen))
13301da177e4SLinus Torvalds 		goto out;
13319ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
13321da177e4SLinus Torvalds 		  "security_compute_sid:  invalid context %s"
13331da177e4SLinus Torvalds 		  " for scontext=%s"
13341da177e4SLinus Torvalds 		  " tcontext=%s"
13351da177e4SLinus Torvalds 		  " tclass=%s",
1336ac76c05bSEric Paris 		  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
13371da177e4SLinus Torvalds out:
13381da177e4SLinus Torvalds 	kfree(s);
13391da177e4SLinus Torvalds 	kfree(t);
13401da177e4SLinus Torvalds 	kfree(n);
13411da177e4SLinus Torvalds 	if (!selinux_enforcing)
13421da177e4SLinus Torvalds 		return 0;
13431da177e4SLinus Torvalds 	return -EACCES;
13441da177e4SLinus Torvalds }
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds static int security_compute_sid(u32 ssid,
13471da177e4SLinus Torvalds 				u32 tsid,
1348c6d3aaa4SStephen Smalley 				u16 orig_tclass,
13491da177e4SLinus Torvalds 				u32 specified,
1350c6d3aaa4SStephen Smalley 				u32 *out_sid,
1351c6d3aaa4SStephen Smalley 				bool kern)
13521da177e4SLinus Torvalds {
13531da177e4SLinus Torvalds 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
13541da177e4SLinus Torvalds 	struct role_trans *roletr = NULL;
13551da177e4SLinus Torvalds 	struct avtab_key avkey;
13561da177e4SLinus Torvalds 	struct avtab_datum *avdatum;
13571da177e4SLinus Torvalds 	struct avtab_node *node;
1358c6d3aaa4SStephen Smalley 	u16 tclass;
13591da177e4SLinus Torvalds 	int rc = 0;
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	if (!ss_initialized) {
1362c6d3aaa4SStephen Smalley 		switch (orig_tclass) {
1363c6d3aaa4SStephen Smalley 		case SECCLASS_PROCESS: /* kernel value */
13641da177e4SLinus Torvalds 			*out_sid = ssid;
13651da177e4SLinus Torvalds 			break;
13661da177e4SLinus Torvalds 		default:
13671da177e4SLinus Torvalds 			*out_sid = tsid;
13681da177e4SLinus Torvalds 			break;
13691da177e4SLinus Torvalds 		}
13701da177e4SLinus Torvalds 		goto out;
13711da177e4SLinus Torvalds 	}
13721da177e4SLinus Torvalds 
1373851f8a69SVenkat Yekkirala 	context_init(&newcontext);
1374851f8a69SVenkat Yekkirala 
13750804d113SJames Morris 	read_lock(&policy_rwlock);
13761da177e4SLinus Torvalds 
1377c6d3aaa4SStephen Smalley 	if (kern)
1378c6d3aaa4SStephen Smalley 		tclass = unmap_class(orig_tclass);
1379c6d3aaa4SStephen Smalley 	else
1380c6d3aaa4SStephen Smalley 		tclass = orig_tclass;
1381c6d3aaa4SStephen Smalley 
13821da177e4SLinus Torvalds 	scontext = sidtab_search(&sidtab, ssid);
13831da177e4SLinus Torvalds 	if (!scontext) {
1384744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1385744ba35eSEric Paris 		       __func__, ssid);
13861da177e4SLinus Torvalds 		rc = -EINVAL;
13871da177e4SLinus Torvalds 		goto out_unlock;
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tsid);
13901da177e4SLinus Torvalds 	if (!tcontext) {
1391744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
1392744ba35eSEric Paris 		       __func__, tsid);
13931da177e4SLinus Torvalds 		rc = -EINVAL;
13941da177e4SLinus Torvalds 		goto out_unlock;
13951da177e4SLinus Torvalds 	}
13961da177e4SLinus Torvalds 
13971da177e4SLinus Torvalds 	/* Set the user identity. */
13981da177e4SLinus Torvalds 	switch (specified) {
13991da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
14001da177e4SLinus Torvalds 	case AVTAB_CHANGE:
14011da177e4SLinus Torvalds 		/* Use the process user identity. */
14021da177e4SLinus Torvalds 		newcontext.user = scontext->user;
14031da177e4SLinus Torvalds 		break;
14041da177e4SLinus Torvalds 	case AVTAB_MEMBER:
14051da177e4SLinus Torvalds 		/* Use the related object owner. */
14061da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
14071da177e4SLinus Torvalds 		break;
14081da177e4SLinus Torvalds 	}
14091da177e4SLinus Torvalds 
14101da177e4SLinus Torvalds 	/* Set the role and type to default values. */
1411c6d3aaa4SStephen Smalley 	if (tclass == policydb.process_class) {
14121da177e4SLinus Torvalds 		/* Use the current role and type of process. */
14131da177e4SLinus Torvalds 		newcontext.role = scontext->role;
14141da177e4SLinus Torvalds 		newcontext.type = scontext->type;
1415c6d3aaa4SStephen Smalley 	} else {
14161da177e4SLinus Torvalds 		/* Use the well-defined object role. */
14171da177e4SLinus Torvalds 		newcontext.role = OBJECT_R_VAL;
14181da177e4SLinus Torvalds 		/* Use the type of the related object. */
14191da177e4SLinus Torvalds 		newcontext.type = tcontext->type;
14201da177e4SLinus Torvalds 	}
14211da177e4SLinus Torvalds 
14221da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
14231da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
14241da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
14251da177e4SLinus Torvalds 	avkey.target_class = tclass;
1426782ebb99SStephen Smalley 	avkey.specified = specified;
1427782ebb99SStephen Smalley 	avdatum = avtab_search(&policydb.te_avtab, &avkey);
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
14301da177e4SLinus Torvalds 	if (!avdatum) {
1431782ebb99SStephen Smalley 		node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
1432dbc74c65SVesa-Matti Kari 		for (; node; node = avtab_search_node_next(node, specified)) {
1433782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
14341da177e4SLinus Torvalds 				avdatum = &node->datum;
14351da177e4SLinus Torvalds 				break;
14361da177e4SLinus Torvalds 			}
14371da177e4SLinus Torvalds 		}
14381da177e4SLinus Torvalds 	}
14391da177e4SLinus Torvalds 
1440782ebb99SStephen Smalley 	if (avdatum) {
14411da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
1442782ebb99SStephen Smalley 		newcontext.type = avdatum->data;
14431da177e4SLinus Torvalds 	}
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 	/* Check for class-specific changes. */
1446c6d3aaa4SStephen Smalley 	if  (tclass == policydb.process_class) {
14471da177e4SLinus Torvalds 		if (specified & AVTAB_TRANSITION) {
14481da177e4SLinus Torvalds 			/* Look for a role transition rule. */
14491da177e4SLinus Torvalds 			for (roletr = policydb.role_tr; roletr;
14501da177e4SLinus Torvalds 			     roletr = roletr->next) {
14511da177e4SLinus Torvalds 				if (roletr->role == scontext->role &&
14521da177e4SLinus Torvalds 				    roletr->type == tcontext->type) {
14531da177e4SLinus Torvalds 					/* Use the role transition rule. */
14541da177e4SLinus Torvalds 					newcontext.role = roletr->new_role;
14551da177e4SLinus Torvalds 					break;
14561da177e4SLinus Torvalds 				}
14571da177e4SLinus Torvalds 			}
14581da177e4SLinus Torvalds 		}
14591da177e4SLinus Torvalds 	}
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds 	/* Set the MLS attributes.
14621da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
14631da177e4SLinus Torvalds 	rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
14641da177e4SLinus Torvalds 	if (rc)
14651da177e4SLinus Torvalds 		goto out_unlock;
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 	/* Check the validity of the context. */
14681da177e4SLinus Torvalds 	if (!policydb_context_isvalid(&policydb, &newcontext)) {
14691da177e4SLinus Torvalds 		rc = compute_sid_handle_invalid_context(scontext,
14701da177e4SLinus Torvalds 							tcontext,
14711da177e4SLinus Torvalds 							tclass,
14721da177e4SLinus Torvalds 							&newcontext);
14731da177e4SLinus Torvalds 		if (rc)
14741da177e4SLinus Torvalds 			goto out_unlock;
14751da177e4SLinus Torvalds 	}
14761da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
14771da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
14781da177e4SLinus Torvalds out_unlock:
14790804d113SJames Morris 	read_unlock(&policy_rwlock);
14801da177e4SLinus Torvalds 	context_destroy(&newcontext);
14811da177e4SLinus Torvalds out:
14821da177e4SLinus Torvalds 	return rc;
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds 
14851da177e4SLinus Torvalds /**
14861da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
14871da177e4SLinus Torvalds  * @ssid: source security identifier
14881da177e4SLinus Torvalds  * @tsid: target security identifier
14891da177e4SLinus Torvalds  * @tclass: target security class
14901da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
14911da177e4SLinus Torvalds  *
14921da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
14931da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
14941da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
14951da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
14961da177e4SLinus Torvalds  * computed successfully.
14971da177e4SLinus Torvalds  */
14981da177e4SLinus Torvalds int security_transition_sid(u32 ssid,
14991da177e4SLinus Torvalds 			    u32 tsid,
15001da177e4SLinus Torvalds 			    u16 tclass,
15011da177e4SLinus Torvalds 			    u32 *out_sid)
15021da177e4SLinus Torvalds {
1503c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1504c6d3aaa4SStephen Smalley 				    out_sid, true);
1505c6d3aaa4SStephen Smalley }
1506c6d3aaa4SStephen Smalley 
1507c6d3aaa4SStephen Smalley int security_transition_sid_user(u32 ssid,
1508c6d3aaa4SStephen Smalley 				 u32 tsid,
1509c6d3aaa4SStephen Smalley 				 u16 tclass,
1510c6d3aaa4SStephen Smalley 				 u32 *out_sid)
1511c6d3aaa4SStephen Smalley {
1512c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
1513c6d3aaa4SStephen Smalley 				    out_sid, false);
15141da177e4SLinus Torvalds }
15151da177e4SLinus Torvalds 
15161da177e4SLinus Torvalds /**
15171da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
15181da177e4SLinus Torvalds  * @ssid: source security identifier
15191da177e4SLinus Torvalds  * @tsid: target security identifier
15201da177e4SLinus Torvalds  * @tclass: target security class
15211da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
15221da177e4SLinus Torvalds  *
15231da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
15241da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
15251da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
15261da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
15271da177e4SLinus Torvalds  * computed successfully.
15281da177e4SLinus Torvalds  */
15291da177e4SLinus Torvalds int security_member_sid(u32 ssid,
15301da177e4SLinus Torvalds 			u32 tsid,
15311da177e4SLinus Torvalds 			u16 tclass,
15321da177e4SLinus Torvalds 			u32 *out_sid)
15331da177e4SLinus Torvalds {
1534c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid,
1535c6d3aaa4SStephen Smalley 				    false);
15361da177e4SLinus Torvalds }
15371da177e4SLinus Torvalds 
15381da177e4SLinus Torvalds /**
15391da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
15401da177e4SLinus Torvalds  * @ssid: source security identifier
15411da177e4SLinus Torvalds  * @tsid: target security identifier
15421da177e4SLinus Torvalds  * @tclass: target security class
15431da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
15441da177e4SLinus Torvalds  *
15451da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
15461da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
15471da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
15481da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
15491da177e4SLinus Torvalds  * computed successfully.
15501da177e4SLinus Torvalds  */
15511da177e4SLinus Torvalds int security_change_sid(u32 ssid,
15521da177e4SLinus Torvalds 			u32 tsid,
15531da177e4SLinus Torvalds 			u16 tclass,
15541da177e4SLinus Torvalds 			u32 *out_sid)
15551da177e4SLinus Torvalds {
1556c6d3aaa4SStephen Smalley 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid,
1557c6d3aaa4SStephen Smalley 				    false);
1558b94c7e67SChad Sellers }
1559b94c7e67SChad Sellers 
15601da177e4SLinus Torvalds /* Clone the SID into the new SID table. */
15611da177e4SLinus Torvalds static int clone_sid(u32 sid,
15621da177e4SLinus Torvalds 		     struct context *context,
15631da177e4SLinus Torvalds 		     void *arg)
15641da177e4SLinus Torvalds {
15651da177e4SLinus Torvalds 	struct sidtab *s = arg;
15661da177e4SLinus Torvalds 
156742596eafSGuido Trentalancia 	if (sid > SECINITSID_NUM)
15681da177e4SLinus Torvalds 		return sidtab_insert(s, sid, context);
156942596eafSGuido Trentalancia 	else
157042596eafSGuido Trentalancia 		return 0;
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context)
15741da177e4SLinus Torvalds {
15751da177e4SLinus Torvalds 	char *s;
15761da177e4SLinus Torvalds 	u32 len;
15771da177e4SLinus Torvalds 
15784b02b524SEric Paris 	if (selinux_enforcing)
15794b02b524SEric Paris 		return -EINVAL;
15804b02b524SEric Paris 
158112b29f34SStephen Smalley 	if (!context_struct_to_string(context, &s, &len)) {
15824b02b524SEric Paris 		printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
15831da177e4SLinus Torvalds 		kfree(s);
15841da177e4SLinus Torvalds 	}
15854b02b524SEric Paris 	return 0;
15861da177e4SLinus Torvalds }
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds struct convert_context_args {
15891da177e4SLinus Torvalds 	struct policydb *oldp;
15901da177e4SLinus Torvalds 	struct policydb *newp;
15911da177e4SLinus Torvalds };
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds /*
15941da177e4SLinus Torvalds  * Convert the values in the security context
15951da177e4SLinus Torvalds  * structure `c' from the values specified
15961da177e4SLinus Torvalds  * in the policy `p->oldp' to the values specified
15971da177e4SLinus Torvalds  * in the policy `p->newp'.  Verify that the
15981da177e4SLinus Torvalds  * context is valid under the new policy.
15991da177e4SLinus Torvalds  */
16001da177e4SLinus Torvalds static int convert_context(u32 key,
16011da177e4SLinus Torvalds 			   struct context *c,
16021da177e4SLinus Torvalds 			   void *p)
16031da177e4SLinus Torvalds {
16041da177e4SLinus Torvalds 	struct convert_context_args *args;
16051da177e4SLinus Torvalds 	struct context oldc;
16060719aaf5SGuido Trentalancia 	struct ocontext *oc;
16070719aaf5SGuido Trentalancia 	struct mls_range *range;
16081da177e4SLinus Torvalds 	struct role_datum *role;
16091da177e4SLinus Torvalds 	struct type_datum *typdatum;
16101da177e4SLinus Torvalds 	struct user_datum *usrdatum;
16111da177e4SLinus Torvalds 	char *s;
16121da177e4SLinus Torvalds 	u32 len;
161342596eafSGuido Trentalancia 	int rc = 0;
161442596eafSGuido Trentalancia 
161542596eafSGuido Trentalancia 	if (key <= SECINITSID_NUM)
161642596eafSGuido Trentalancia 		goto out;
16171da177e4SLinus Torvalds 
16181da177e4SLinus Torvalds 	args = p;
16191da177e4SLinus Torvalds 
162012b29f34SStephen Smalley 	if (c->str) {
162112b29f34SStephen Smalley 		struct context ctx;
16224b02b524SEric Paris 
16239a59daa0SStephen Smalley 		rc = -ENOMEM;
16244b02b524SEric Paris 		s = kstrdup(c->str, GFP_KERNEL);
16254b02b524SEric Paris 		if (!s)
16269a59daa0SStephen Smalley 			goto out;
16274b02b524SEric Paris 
16289a59daa0SStephen Smalley 		rc = string_to_context_struct(args->newp, NULL, s,
16299a59daa0SStephen Smalley 					      c->len, &ctx, SECSID_NULL);
16309a59daa0SStephen Smalley 		kfree(s);
163112b29f34SStephen Smalley 		if (!rc) {
16324b02b524SEric Paris 			printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
163312b29f34SStephen Smalley 			       c->str);
163412b29f34SStephen Smalley 			/* Replace string with mapped representation. */
163512b29f34SStephen Smalley 			kfree(c->str);
163612b29f34SStephen Smalley 			memcpy(c, &ctx, sizeof(*c));
163712b29f34SStephen Smalley 			goto out;
163812b29f34SStephen Smalley 		} else if (rc == -EINVAL) {
163912b29f34SStephen Smalley 			/* Retain string representation for later mapping. */
164012b29f34SStephen Smalley 			rc = 0;
164112b29f34SStephen Smalley 			goto out;
164212b29f34SStephen Smalley 		} else {
164312b29f34SStephen Smalley 			/* Other error condition, e.g. ENOMEM. */
16444b02b524SEric Paris 			printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
164512b29f34SStephen Smalley 			       c->str, -rc);
164612b29f34SStephen Smalley 			goto out;
164712b29f34SStephen Smalley 		}
164812b29f34SStephen Smalley 	}
164912b29f34SStephen Smalley 
16501da177e4SLinus Torvalds 	rc = context_cpy(&oldc, c);
16511da177e4SLinus Torvalds 	if (rc)
16521da177e4SLinus Torvalds 		goto out;
16531da177e4SLinus Torvalds 
16541da177e4SLinus Torvalds 	/* Convert the user. */
16554b02b524SEric Paris 	rc = -EINVAL;
16561da177e4SLinus Torvalds 	usrdatum = hashtab_search(args->newp->p_users.table,
1657ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_USERS, c->user - 1));
16585d55a345SEric Paris 	if (!usrdatum)
16591da177e4SLinus Torvalds 		goto bad;
16601da177e4SLinus Torvalds 	c->user = usrdatum->value;
16611da177e4SLinus Torvalds 
16621da177e4SLinus Torvalds 	/* Convert the role. */
16634b02b524SEric Paris 	rc = -EINVAL;
16641da177e4SLinus Torvalds 	role = hashtab_search(args->newp->p_roles.table,
1665ac76c05bSEric Paris 			      sym_name(args->oldp, SYM_ROLES, c->role - 1));
16665d55a345SEric Paris 	if (!role)
16671da177e4SLinus Torvalds 		goto bad;
16681da177e4SLinus Torvalds 	c->role = role->value;
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 	/* Convert the type. */
16714b02b524SEric Paris 	rc = -EINVAL;
16721da177e4SLinus Torvalds 	typdatum = hashtab_search(args->newp->p_types.table,
1673ac76c05bSEric Paris 				  sym_name(args->oldp, SYM_TYPES, c->type - 1));
16745d55a345SEric Paris 	if (!typdatum)
16751da177e4SLinus Torvalds 		goto bad;
16761da177e4SLinus Torvalds 	c->type = typdatum->value;
16771da177e4SLinus Torvalds 
16780719aaf5SGuido Trentalancia 	/* Convert the MLS fields if dealing with MLS policies */
16790719aaf5SGuido Trentalancia 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
16801da177e4SLinus Torvalds 		rc = mls_convert_context(args->oldp, args->newp, c);
16811da177e4SLinus Torvalds 		if (rc)
16821da177e4SLinus Torvalds 			goto bad;
16830719aaf5SGuido Trentalancia 	} else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
16840719aaf5SGuido Trentalancia 		/*
16850719aaf5SGuido Trentalancia 		 * Switching between MLS and non-MLS policy:
16860719aaf5SGuido Trentalancia 		 * free any storage used by the MLS fields in the
16870719aaf5SGuido Trentalancia 		 * context for all existing entries in the sidtab.
16880719aaf5SGuido Trentalancia 		 */
16890719aaf5SGuido Trentalancia 		mls_context_destroy(c);
16900719aaf5SGuido Trentalancia 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
16910719aaf5SGuido Trentalancia 		/*
16920719aaf5SGuido Trentalancia 		 * Switching between non-MLS and MLS policy:
16930719aaf5SGuido Trentalancia 		 * ensure that the MLS fields of the context for all
16940719aaf5SGuido Trentalancia 		 * existing entries in the sidtab are filled in with a
16950719aaf5SGuido Trentalancia 		 * suitable default value, likely taken from one of the
16960719aaf5SGuido Trentalancia 		 * initial SIDs.
16970719aaf5SGuido Trentalancia 		 */
16980719aaf5SGuido Trentalancia 		oc = args->newp->ocontexts[OCON_ISID];
16990719aaf5SGuido Trentalancia 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
17000719aaf5SGuido Trentalancia 			oc = oc->next;
17014b02b524SEric Paris 		rc = -EINVAL;
17020719aaf5SGuido Trentalancia 		if (!oc) {
17030719aaf5SGuido Trentalancia 			printk(KERN_ERR "SELinux:  unable to look up"
17040719aaf5SGuido Trentalancia 				" the initial SIDs list\n");
17050719aaf5SGuido Trentalancia 			goto bad;
17060719aaf5SGuido Trentalancia 		}
17070719aaf5SGuido Trentalancia 		range = &oc->context[0].range;
17080719aaf5SGuido Trentalancia 		rc = mls_range_set(c, range);
17090719aaf5SGuido Trentalancia 		if (rc)
17100719aaf5SGuido Trentalancia 			goto bad;
17110719aaf5SGuido Trentalancia 	}
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 	/* Check the validity of the new context. */
17141da177e4SLinus Torvalds 	if (!policydb_context_isvalid(args->newp, c)) {
17151da177e4SLinus Torvalds 		rc = convert_context_handle_invalid_context(&oldc);
17161da177e4SLinus Torvalds 		if (rc)
17171da177e4SLinus Torvalds 			goto bad;
17181da177e4SLinus Torvalds 	}
17191da177e4SLinus Torvalds 
17201da177e4SLinus Torvalds 	context_destroy(&oldc);
17214b02b524SEric Paris 
172212b29f34SStephen Smalley 	rc = 0;
17231da177e4SLinus Torvalds out:
17241da177e4SLinus Torvalds 	return rc;
17251da177e4SLinus Torvalds bad:
172612b29f34SStephen Smalley 	/* Map old representation to string and save it. */
17274b02b524SEric Paris 	rc = context_struct_to_string(&oldc, &s, &len);
17284b02b524SEric Paris 	if (rc)
17294b02b524SEric Paris 		return rc;
17301da177e4SLinus Torvalds 	context_destroy(&oldc);
173112b29f34SStephen Smalley 	context_destroy(c);
173212b29f34SStephen Smalley 	c->str = s;
173312b29f34SStephen Smalley 	c->len = len;
17344b02b524SEric Paris 	printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
173512b29f34SStephen Smalley 	       c->str);
173612b29f34SStephen Smalley 	rc = 0;
17371da177e4SLinus Torvalds 	goto out;
17381da177e4SLinus Torvalds }
17391da177e4SLinus Torvalds 
17403bb56b25SPaul Moore static void security_load_policycaps(void)
17413bb56b25SPaul Moore {
17423bb56b25SPaul Moore 	selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
17433bb56b25SPaul Moore 						  POLICYDB_CAPABILITY_NETPEER);
1744b0c636b9SEric Paris 	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
1745b0c636b9SEric Paris 						  POLICYDB_CAPABILITY_OPENPERM);
17463bb56b25SPaul Moore }
17473bb56b25SPaul Moore 
17481da177e4SLinus Torvalds extern void selinux_complete_init(void);
1749e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p);
17501da177e4SLinus Torvalds 
17511da177e4SLinus Torvalds /**
17521da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
17531da177e4SLinus Torvalds  * @data: binary policy data
17541da177e4SLinus Torvalds  * @len: length of data in bytes
17551da177e4SLinus Torvalds  *
17561da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
17571da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
17581da177e4SLinus Torvalds  * This function will flush the access vector cache after
17591da177e4SLinus Torvalds  * loading the new policy.
17601da177e4SLinus Torvalds  */
17611da177e4SLinus Torvalds int security_load_policy(void *data, size_t len)
17621da177e4SLinus Torvalds {
17631da177e4SLinus Torvalds 	struct policydb oldpolicydb, newpolicydb;
17641da177e4SLinus Torvalds 	struct sidtab oldsidtab, newsidtab;
1765c6d3aaa4SStephen Smalley 	struct selinux_mapping *oldmap, *map = NULL;
17661da177e4SLinus Torvalds 	struct convert_context_args args;
17671da177e4SLinus Torvalds 	u32 seqno;
1768c6d3aaa4SStephen Smalley 	u16 map_size;
17691da177e4SLinus Torvalds 	int rc = 0;
17701da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds 	if (!ss_initialized) {
17731da177e4SLinus Torvalds 		avtab_cache_init();
1774a2000050SEric Paris 		rc = policydb_read(&policydb, fp);
1775a2000050SEric Paris 		if (rc) {
17761da177e4SLinus Torvalds 			avtab_cache_destroy();
1777a2000050SEric Paris 			return rc;
17781da177e4SLinus Torvalds 		}
1779a2000050SEric Paris 
1780cee74f47SEric Paris 		policydb.len = len;
1781a2000050SEric Paris 		rc = selinux_set_mapping(&policydb, secclass_map,
1782c6d3aaa4SStephen Smalley 					 &current_mapping,
1783a2000050SEric Paris 					 &current_mapping_size);
1784a2000050SEric Paris 		if (rc) {
17851da177e4SLinus Torvalds 			policydb_destroy(&policydb);
17861da177e4SLinus Torvalds 			avtab_cache_destroy();
1787a2000050SEric Paris 			return rc;
17881da177e4SLinus Torvalds 		}
1789a2000050SEric Paris 
1790a2000050SEric Paris 		rc = policydb_load_isids(&policydb, &sidtab);
1791a2000050SEric Paris 		if (rc) {
1792b94c7e67SChad Sellers 			policydb_destroy(&policydb);
1793b94c7e67SChad Sellers 			avtab_cache_destroy();
1794a2000050SEric Paris 			return rc;
1795b94c7e67SChad Sellers 		}
1796a2000050SEric Paris 
17973bb56b25SPaul Moore 		security_load_policycaps();
17981da177e4SLinus Torvalds 		ss_initialized = 1;
17994c443d1bSStephen Smalley 		seqno = ++latest_granting;
18001da177e4SLinus Torvalds 		selinux_complete_init();
18014c443d1bSStephen Smalley 		avc_ss_reset(seqno);
18024c443d1bSStephen Smalley 		selnl_notify_policyload(seqno);
180311904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
18047420ed23SVenkat Yekkirala 		selinux_netlbl_cache_invalidate();
1805342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
18061da177e4SLinus Torvalds 		return 0;
18071da177e4SLinus Torvalds 	}
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds #if 0
18101da177e4SLinus Torvalds 	sidtab_hash_eval(&sidtab, "sids");
18111da177e4SLinus Torvalds #endif
18121da177e4SLinus Torvalds 
1813a2000050SEric Paris 	rc = policydb_read(&newpolicydb, fp);
1814a2000050SEric Paris 	if (rc)
1815a2000050SEric Paris 		return rc;
18161da177e4SLinus Torvalds 
1817cee74f47SEric Paris 	newpolicydb.len = len;
18180719aaf5SGuido Trentalancia 	/* If switching between different policy types, log MLS status */
18190719aaf5SGuido Trentalancia 	if (policydb.mls_enabled && !newpolicydb.mls_enabled)
18200719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Disabling MLS support...\n");
18210719aaf5SGuido Trentalancia 	else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
18220719aaf5SGuido Trentalancia 		printk(KERN_INFO "SELinux: Enabling MLS support...\n");
18230719aaf5SGuido Trentalancia 
182442596eafSGuido Trentalancia 	rc = policydb_load_isids(&newpolicydb, &newsidtab);
182542596eafSGuido Trentalancia 	if (rc) {
182642596eafSGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
182712b29f34SStephen Smalley 		policydb_destroy(&newpolicydb);
182842596eafSGuido Trentalancia 		return rc;
182912b29f34SStephen Smalley 	}
18301da177e4SLinus Torvalds 
1831a2000050SEric Paris 	rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
1832a2000050SEric Paris 	if (rc)
1833b94c7e67SChad Sellers 		goto err;
1834b94c7e67SChad Sellers 
1835e900a7d9SStephen Smalley 	rc = security_preserve_bools(&newpolicydb);
1836e900a7d9SStephen Smalley 	if (rc) {
1837454d972cSJames Morris 		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");
1838e900a7d9SStephen Smalley 		goto err;
1839e900a7d9SStephen Smalley 	}
1840e900a7d9SStephen Smalley 
18411da177e4SLinus Torvalds 	/* Clone the SID table. */
18421da177e4SLinus Torvalds 	sidtab_shutdown(&sidtab);
1843a2000050SEric Paris 
1844a2000050SEric Paris 	rc = sidtab_map(&sidtab, clone_sid, &newsidtab);
1845a2000050SEric Paris 	if (rc)
18461da177e4SLinus Torvalds 		goto err;
18471da177e4SLinus Torvalds 
184812b29f34SStephen Smalley 	/*
184912b29f34SStephen Smalley 	 * Convert the internal representations of contexts
185012b29f34SStephen Smalley 	 * in the new SID table.
185112b29f34SStephen Smalley 	 */
18521da177e4SLinus Torvalds 	args.oldp = &policydb;
18531da177e4SLinus Torvalds 	args.newp = &newpolicydb;
185412b29f34SStephen Smalley 	rc = sidtab_map(&newsidtab, convert_context, &args);
18550719aaf5SGuido Trentalancia 	if (rc) {
18560719aaf5SGuido Trentalancia 		printk(KERN_ERR "SELinux:  unable to convert the internal"
18570719aaf5SGuido Trentalancia 			" representation of contexts in the new SID"
18580719aaf5SGuido Trentalancia 			" table\n");
185912b29f34SStephen Smalley 		goto err;
18600719aaf5SGuido Trentalancia 	}
18611da177e4SLinus Torvalds 
18621da177e4SLinus Torvalds 	/* Save the old policydb and SID table to free later. */
18631da177e4SLinus Torvalds 	memcpy(&oldpolicydb, &policydb, sizeof policydb);
18641da177e4SLinus Torvalds 	sidtab_set(&oldsidtab, &sidtab);
18651da177e4SLinus Torvalds 
18661da177e4SLinus Torvalds 	/* Install the new policydb and SID table. */
18670804d113SJames Morris 	write_lock_irq(&policy_rwlock);
18681da177e4SLinus Torvalds 	memcpy(&policydb, &newpolicydb, sizeof policydb);
18691da177e4SLinus Torvalds 	sidtab_set(&sidtab, &newsidtab);
18703bb56b25SPaul Moore 	security_load_policycaps();
1871c6d3aaa4SStephen Smalley 	oldmap = current_mapping;
1872c6d3aaa4SStephen Smalley 	current_mapping = map;
1873c6d3aaa4SStephen Smalley 	current_mapping_size = map_size;
18741da177e4SLinus Torvalds 	seqno = ++latest_granting;
18750804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds 	/* Free the old policydb and SID table. */
18781da177e4SLinus Torvalds 	policydb_destroy(&oldpolicydb);
18791da177e4SLinus Torvalds 	sidtab_destroy(&oldsidtab);
1880c6d3aaa4SStephen Smalley 	kfree(oldmap);
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 	avc_ss_reset(seqno);
18831da177e4SLinus Torvalds 	selnl_notify_policyload(seqno);
188411904167SKaiGai Kohei 	selinux_status_update_policyload(seqno);
18857420ed23SVenkat Yekkirala 	selinux_netlbl_cache_invalidate();
1886342a0cffSVenkat Yekkirala 	selinux_xfrm_notify_policyload();
18871da177e4SLinus Torvalds 
18881da177e4SLinus Torvalds 	return 0;
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds err:
1891c6d3aaa4SStephen Smalley 	kfree(map);
18921da177e4SLinus Torvalds 	sidtab_destroy(&newsidtab);
18931da177e4SLinus Torvalds 	policydb_destroy(&newpolicydb);
18941da177e4SLinus Torvalds 	return rc;
18951da177e4SLinus Torvalds 
18961da177e4SLinus Torvalds }
18971da177e4SLinus Torvalds 
1898cee74f47SEric Paris size_t security_policydb_len(void)
1899cee74f47SEric Paris {
1900cee74f47SEric Paris 	size_t len;
1901cee74f47SEric Paris 
1902cee74f47SEric Paris 	read_lock(&policy_rwlock);
1903cee74f47SEric Paris 	len = policydb.len;
1904cee74f47SEric Paris 	read_unlock(&policy_rwlock);
1905cee74f47SEric Paris 
1906cee74f47SEric Paris 	return len;
1907cee74f47SEric Paris }
1908cee74f47SEric Paris 
19091da177e4SLinus Torvalds /**
19101da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
19111da177e4SLinus Torvalds  * @protocol: protocol number
19121da177e4SLinus Torvalds  * @port: port number
19131da177e4SLinus Torvalds  * @out_sid: security identifier
19141da177e4SLinus Torvalds  */
19153e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
19161da177e4SLinus Torvalds {
19171da177e4SLinus Torvalds 	struct ocontext *c;
19181da177e4SLinus Torvalds 	int rc = 0;
19191da177e4SLinus Torvalds 
19200804d113SJames Morris 	read_lock(&policy_rwlock);
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_PORT];
19231da177e4SLinus Torvalds 	while (c) {
19241da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
19251da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
19261da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
19271da177e4SLinus Torvalds 			break;
19281da177e4SLinus Torvalds 		c = c->next;
19291da177e4SLinus Torvalds 	}
19301da177e4SLinus Torvalds 
19311da177e4SLinus Torvalds 	if (c) {
19321da177e4SLinus Torvalds 		if (!c->sid[0]) {
19331da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
19341da177e4SLinus Torvalds 						   &c->context[0],
19351da177e4SLinus Torvalds 						   &c->sid[0]);
19361da177e4SLinus Torvalds 			if (rc)
19371da177e4SLinus Torvalds 				goto out;
19381da177e4SLinus Torvalds 		}
19391da177e4SLinus Torvalds 		*out_sid = c->sid[0];
19401da177e4SLinus Torvalds 	} else {
19411da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
19421da177e4SLinus Torvalds 	}
19431da177e4SLinus Torvalds 
19441da177e4SLinus Torvalds out:
19450804d113SJames Morris 	read_unlock(&policy_rwlock);
19461da177e4SLinus Torvalds 	return rc;
19471da177e4SLinus Torvalds }
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds /**
19501da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
19511da177e4SLinus Torvalds  * @name: interface name
19521da177e4SLinus Torvalds  * @if_sid: interface SID
19531da177e4SLinus Torvalds  */
1954e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid)
19551da177e4SLinus Torvalds {
19561da177e4SLinus Torvalds 	int rc = 0;
19571da177e4SLinus Torvalds 	struct ocontext *c;
19581da177e4SLinus Torvalds 
19590804d113SJames Morris 	read_lock(&policy_rwlock);
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_NETIF];
19621da177e4SLinus Torvalds 	while (c) {
19631da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
19641da177e4SLinus Torvalds 			break;
19651da177e4SLinus Torvalds 		c = c->next;
19661da177e4SLinus Torvalds 	}
19671da177e4SLinus Torvalds 
19681da177e4SLinus Torvalds 	if (c) {
19691da177e4SLinus Torvalds 		if (!c->sid[0] || !c->sid[1]) {
19701da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
19711da177e4SLinus Torvalds 						  &c->context[0],
19721da177e4SLinus Torvalds 						  &c->sid[0]);
19731da177e4SLinus Torvalds 			if (rc)
19741da177e4SLinus Torvalds 				goto out;
19751da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
19761da177e4SLinus Torvalds 						   &c->context[1],
19771da177e4SLinus Torvalds 						   &c->sid[1]);
19781da177e4SLinus Torvalds 			if (rc)
19791da177e4SLinus Torvalds 				goto out;
19801da177e4SLinus Torvalds 		}
19811da177e4SLinus Torvalds 		*if_sid = c->sid[0];
1982e8bfdb9dSPaul Moore 	} else
19831da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds out:
19860804d113SJames Morris 	read_unlock(&policy_rwlock);
19871da177e4SLinus Torvalds 	return rc;
19881da177e4SLinus Torvalds }
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
19911da177e4SLinus Torvalds {
19921da177e4SLinus Torvalds 	int i, fail = 0;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	for (i = 0; i < 4; i++)
19951da177e4SLinus Torvalds 		if (addr[i] != (input[i] & mask[i])) {
19961da177e4SLinus Torvalds 			fail = 1;
19971da177e4SLinus Torvalds 			break;
19981da177e4SLinus Torvalds 		}
19991da177e4SLinus Torvalds 
20001da177e4SLinus Torvalds 	return !fail;
20011da177e4SLinus Torvalds }
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds /**
20041da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
20051da177e4SLinus Torvalds  * @domain: communication domain aka address family
20061da177e4SLinus Torvalds  * @addrp: address
20071da177e4SLinus Torvalds  * @addrlen: address length in bytes
20081da177e4SLinus Torvalds  * @out_sid: security identifier
20091da177e4SLinus Torvalds  */
20101da177e4SLinus Torvalds int security_node_sid(u16 domain,
20111da177e4SLinus Torvalds 		      void *addrp,
20121da177e4SLinus Torvalds 		      u32 addrlen,
20131da177e4SLinus Torvalds 		      u32 *out_sid)
20141da177e4SLinus Torvalds {
20154b02b524SEric Paris 	int rc;
20161da177e4SLinus Torvalds 	struct ocontext *c;
20171da177e4SLinus Torvalds 
20180804d113SJames Morris 	read_lock(&policy_rwlock);
20191da177e4SLinus Torvalds 
20201da177e4SLinus Torvalds 	switch (domain) {
20211da177e4SLinus Torvalds 	case AF_INET: {
20221da177e4SLinus Torvalds 		u32 addr;
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 		rc = -EINVAL;
20254b02b524SEric Paris 		if (addrlen != sizeof(u32))
20261da177e4SLinus Torvalds 			goto out;
20271da177e4SLinus Torvalds 
20281da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
20291da177e4SLinus Torvalds 
20301da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE];
20311da177e4SLinus Torvalds 		while (c) {
20321da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
20331da177e4SLinus Torvalds 				break;
20341da177e4SLinus Torvalds 			c = c->next;
20351da177e4SLinus Torvalds 		}
20361da177e4SLinus Torvalds 		break;
20371da177e4SLinus Torvalds 	}
20381da177e4SLinus Torvalds 
20391da177e4SLinus Torvalds 	case AF_INET6:
20401da177e4SLinus Torvalds 		rc = -EINVAL;
20414b02b524SEric Paris 		if (addrlen != sizeof(u64) * 2)
20421da177e4SLinus Torvalds 			goto out;
20431da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE6];
20441da177e4SLinus Torvalds 		while (c) {
20451da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
20461da177e4SLinus Torvalds 						c->u.node6.mask))
20471da177e4SLinus Torvalds 				break;
20481da177e4SLinus Torvalds 			c = c->next;
20491da177e4SLinus Torvalds 		}
20501da177e4SLinus Torvalds 		break;
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds 	default:
20534b02b524SEric Paris 		rc = 0;
20541da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
20551da177e4SLinus Torvalds 		goto out;
20561da177e4SLinus Torvalds 	}
20571da177e4SLinus Torvalds 
20581da177e4SLinus Torvalds 	if (c) {
20591da177e4SLinus Torvalds 		if (!c->sid[0]) {
20601da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
20611da177e4SLinus Torvalds 						   &c->context[0],
20621da177e4SLinus Torvalds 						   &c->sid[0]);
20631da177e4SLinus Torvalds 			if (rc)
20641da177e4SLinus Torvalds 				goto out;
20651da177e4SLinus Torvalds 		}
20661da177e4SLinus Torvalds 		*out_sid = c->sid[0];
20671da177e4SLinus Torvalds 	} else {
20681da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
20691da177e4SLinus Torvalds 	}
20701da177e4SLinus Torvalds 
20714b02b524SEric Paris 	rc = 0;
20721da177e4SLinus Torvalds out:
20730804d113SJames Morris 	read_unlock(&policy_rwlock);
20741da177e4SLinus Torvalds 	return rc;
20751da177e4SLinus Torvalds }
20761da177e4SLinus Torvalds 
20771da177e4SLinus Torvalds #define SIDS_NEL 25
20781da177e4SLinus Torvalds 
20791da177e4SLinus Torvalds /**
20801da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
20811da177e4SLinus Torvalds  * @fromsid: starting SID
20821da177e4SLinus Torvalds  * @username: username
20831da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
20841da177e4SLinus Torvalds  * @nel: number of elements in @sids
20851da177e4SLinus Torvalds  *
20861da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
20871da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
20881da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
20891da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
20901da177e4SLinus Torvalds  * number of elements in the array.
20911da177e4SLinus Torvalds  */
20921da177e4SLinus Torvalds 
20931da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid,
20941da177e4SLinus Torvalds 			   char *username,
20951da177e4SLinus Torvalds 			   u32 **sids,
20961da177e4SLinus Torvalds 			   u32 *nel)
20971da177e4SLinus Torvalds {
20981da177e4SLinus Torvalds 	struct context *fromcon, usercon;
20992c3c05dbSStephen Smalley 	u32 *mysids = NULL, *mysids2, sid;
21001da177e4SLinus Torvalds 	u32 mynel = 0, maxnel = SIDS_NEL;
21011da177e4SLinus Torvalds 	struct user_datum *user;
21021da177e4SLinus Torvalds 	struct role_datum *role;
2103782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
21041da177e4SLinus Torvalds 	int rc = 0, i, j;
21051da177e4SLinus Torvalds 
21061da177e4SLinus Torvalds 	*sids = NULL;
21071da177e4SLinus Torvalds 	*nel = 0;
21082c3c05dbSStephen Smalley 
21092c3c05dbSStephen Smalley 	if (!ss_initialized)
21101da177e4SLinus Torvalds 		goto out;
21111da177e4SLinus Torvalds 
21120804d113SJames Morris 	read_lock(&policy_rwlock);
21131da177e4SLinus Torvalds 
211412b29f34SStephen Smalley 	context_init(&usercon);
211512b29f34SStephen Smalley 
21164b02b524SEric Paris 	rc = -EINVAL;
21171da177e4SLinus Torvalds 	fromcon = sidtab_search(&sidtab, fromsid);
21184b02b524SEric Paris 	if (!fromcon)
21191da177e4SLinus Torvalds 		goto out_unlock;
21201da177e4SLinus Torvalds 
21211da177e4SLinus Torvalds 	rc = -EINVAL;
21224b02b524SEric Paris 	user = hashtab_search(policydb.p_users.table, username);
21234b02b524SEric Paris 	if (!user)
21241da177e4SLinus Torvalds 		goto out_unlock;
21254b02b524SEric Paris 
21261da177e4SLinus Torvalds 	usercon.user = user->value;
21271da177e4SLinus Torvalds 
21281da177e4SLinus Torvalds 	rc = -ENOMEM;
21294b02b524SEric Paris 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
21304b02b524SEric Paris 	if (!mysids)
21311da177e4SLinus Torvalds 		goto out_unlock;
21321da177e4SLinus Torvalds 
21339fe79ad1SKaiGai Kohei 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
21341da177e4SLinus Torvalds 		role = policydb.role_val_to_struct[i];
21351da177e4SLinus Torvalds 		usercon.role = i + 1;
21369fe79ad1SKaiGai Kohei 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
21371da177e4SLinus Torvalds 			usercon.type = j + 1;
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds 			if (mls_setup_user_range(fromcon, user, &usercon))
21401da177e4SLinus Torvalds 				continue;
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
21432c3c05dbSStephen Smalley 			if (rc)
21441da177e4SLinus Torvalds 				goto out_unlock;
21451da177e4SLinus Torvalds 			if (mynel < maxnel) {
21461da177e4SLinus Torvalds 				mysids[mynel++] = sid;
21471da177e4SLinus Torvalds 			} else {
21484b02b524SEric Paris 				rc = -ENOMEM;
21491da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
215089d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
21514b02b524SEric Paris 				if (!mysids2)
21521da177e4SLinus Torvalds 					goto out_unlock;
21531da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
21541da177e4SLinus Torvalds 				kfree(mysids);
21551da177e4SLinus Torvalds 				mysids = mysids2;
21561da177e4SLinus Torvalds 				mysids[mynel++] = sid;
21571da177e4SLinus Torvalds 			}
21581da177e4SLinus Torvalds 		}
21591da177e4SLinus Torvalds 	}
21604b02b524SEric Paris 	rc = 0;
21611da177e4SLinus Torvalds out_unlock:
21620804d113SJames Morris 	read_unlock(&policy_rwlock);
21632c3c05dbSStephen Smalley 	if (rc || !mynel) {
21642c3c05dbSStephen Smalley 		kfree(mysids);
21652c3c05dbSStephen Smalley 		goto out;
21662c3c05dbSStephen Smalley 	}
21672c3c05dbSStephen Smalley 
21684b02b524SEric Paris 	rc = -ENOMEM;
21692c3c05dbSStephen Smalley 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
21702c3c05dbSStephen Smalley 	if (!mysids2) {
21712c3c05dbSStephen Smalley 		kfree(mysids);
21722c3c05dbSStephen Smalley 		goto out;
21732c3c05dbSStephen Smalley 	}
21742c3c05dbSStephen Smalley 	for (i = 0, j = 0; i < mynel; i++) {
21752c3c05dbSStephen Smalley 		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2176c6d3aaa4SStephen Smalley 					  SECCLASS_PROCESS, /* kernel value */
21772c3c05dbSStephen Smalley 					  PROCESS__TRANSITION, AVC_STRICT,
21782c3c05dbSStephen Smalley 					  NULL);
21792c3c05dbSStephen Smalley 		if (!rc)
21802c3c05dbSStephen Smalley 			mysids2[j++] = mysids[i];
21812c3c05dbSStephen Smalley 		cond_resched();
21822c3c05dbSStephen Smalley 	}
21832c3c05dbSStephen Smalley 	rc = 0;
21842c3c05dbSStephen Smalley 	kfree(mysids);
21852c3c05dbSStephen Smalley 	*sids = mysids2;
21862c3c05dbSStephen Smalley 	*nel = j;
21871da177e4SLinus Torvalds out:
21881da177e4SLinus Torvalds 	return rc;
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds /**
21921da177e4SLinus Torvalds  * security_genfs_sid - Obtain a SID for a file in a filesystem
21931da177e4SLinus Torvalds  * @fstype: filesystem type
21941da177e4SLinus Torvalds  * @path: path from root of mount
21951da177e4SLinus Torvalds  * @sclass: file security class
21961da177e4SLinus Torvalds  * @sid: SID for path
21971da177e4SLinus Torvalds  *
21981da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
21991da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
22001da177e4SLinus Torvalds  * transition SIDs or task SIDs.
22011da177e4SLinus Torvalds  */
22021da177e4SLinus Torvalds int security_genfs_sid(const char *fstype,
22031da177e4SLinus Torvalds 		       char *path,
2204c6d3aaa4SStephen Smalley 		       u16 orig_sclass,
22051da177e4SLinus Torvalds 		       u32 *sid)
22061da177e4SLinus Torvalds {
22071da177e4SLinus Torvalds 	int len;
2208c6d3aaa4SStephen Smalley 	u16 sclass;
22091da177e4SLinus Torvalds 	struct genfs *genfs;
22101da177e4SLinus Torvalds 	struct ocontext *c;
22114b02b524SEric Paris 	int rc, cmp = 0;
22121da177e4SLinus Torvalds 
2213b1aa5301SStephen Smalley 	while (path[0] == '/' && path[1] == '/')
2214b1aa5301SStephen Smalley 		path++;
2215b1aa5301SStephen Smalley 
22160804d113SJames Morris 	read_lock(&policy_rwlock);
22171da177e4SLinus Torvalds 
2218c6d3aaa4SStephen Smalley 	sclass = unmap_class(orig_sclass);
22194b02b524SEric Paris 	*sid = SECINITSID_UNLABELED;
2220c6d3aaa4SStephen Smalley 
22211da177e4SLinus Torvalds 	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
22221da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
22231da177e4SLinus Torvalds 		if (cmp <= 0)
22241da177e4SLinus Torvalds 			break;
22251da177e4SLinus Torvalds 	}
22261da177e4SLinus Torvalds 
22271da177e4SLinus Torvalds 	rc = -ENOENT;
22284b02b524SEric Paris 	if (!genfs || cmp)
22291da177e4SLinus Torvalds 		goto out;
22301da177e4SLinus Torvalds 
22311da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
22321da177e4SLinus Torvalds 		len = strlen(c->u.name);
22331da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
22341da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
22351da177e4SLinus Torvalds 			break;
22361da177e4SLinus Torvalds 	}
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds 	rc = -ENOENT;
22394b02b524SEric Paris 	if (!c)
22401da177e4SLinus Torvalds 		goto out;
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 	if (!c->sid[0]) {
22434b02b524SEric Paris 		rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
22441da177e4SLinus Torvalds 		if (rc)
22451da177e4SLinus Torvalds 			goto out;
22461da177e4SLinus Torvalds 	}
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds 	*sid = c->sid[0];
22494b02b524SEric Paris 	rc = 0;
22501da177e4SLinus Torvalds out:
22510804d113SJames Morris 	read_unlock(&policy_rwlock);
22521da177e4SLinus Torvalds 	return rc;
22531da177e4SLinus Torvalds }
22541da177e4SLinus Torvalds 
22551da177e4SLinus Torvalds /**
22561da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
22571da177e4SLinus Torvalds  * @fstype: filesystem type
22581da177e4SLinus Torvalds  * @behavior: labeling behavior
22591da177e4SLinus Torvalds  * @sid: SID for filesystem (superblock)
22601da177e4SLinus Torvalds  */
22611da177e4SLinus Torvalds int security_fs_use(
22621da177e4SLinus Torvalds 	const char *fstype,
22631da177e4SLinus Torvalds 	unsigned int *behavior,
2264089be43eSJames Morris 	u32 *sid)
22651da177e4SLinus Torvalds {
22661da177e4SLinus Torvalds 	int rc = 0;
22671da177e4SLinus Torvalds 	struct ocontext *c;
22681da177e4SLinus Torvalds 
22690804d113SJames Morris 	read_lock(&policy_rwlock);
22701da177e4SLinus Torvalds 
22711da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_FSUSE];
22721da177e4SLinus Torvalds 	while (c) {
22731da177e4SLinus Torvalds 		if (strcmp(fstype, c->u.name) == 0)
22741da177e4SLinus Torvalds 			break;
22751da177e4SLinus Torvalds 		c = c->next;
22761da177e4SLinus Torvalds 	}
22771da177e4SLinus Torvalds 
22781da177e4SLinus Torvalds 	if (c) {
22791da177e4SLinus Torvalds 		*behavior = c->v.behavior;
22801da177e4SLinus Torvalds 		if (!c->sid[0]) {
22814b02b524SEric Paris 			rc = sidtab_context_to_sid(&sidtab, &c->context[0],
22821da177e4SLinus Torvalds 						   &c->sid[0]);
22831da177e4SLinus Torvalds 			if (rc)
22841da177e4SLinus Torvalds 				goto out;
22851da177e4SLinus Torvalds 		}
22861da177e4SLinus Torvalds 		*sid = c->sid[0];
2287089be43eSJames Morris 	} else {
22881da177e4SLinus Torvalds 		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
22891da177e4SLinus Torvalds 		if (rc) {
22901da177e4SLinus Torvalds 			*behavior = SECURITY_FS_USE_NONE;
22911da177e4SLinus Torvalds 			rc = 0;
22921da177e4SLinus Torvalds 		} else {
22931da177e4SLinus Torvalds 			*behavior = SECURITY_FS_USE_GENFS;
22941da177e4SLinus Torvalds 		}
2295089be43eSJames Morris 	}
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds out:
22980804d113SJames Morris 	read_unlock(&policy_rwlock);
22991da177e4SLinus Torvalds 	return rc;
23001da177e4SLinus Torvalds }
23011da177e4SLinus Torvalds 
23021da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values)
23031da177e4SLinus Torvalds {
23044b02b524SEric Paris 	int i, rc;
23051da177e4SLinus Torvalds 
23060804d113SJames Morris 	read_lock(&policy_rwlock);
23071da177e4SLinus Torvalds 	*names = NULL;
23081da177e4SLinus Torvalds 	*values = NULL;
23091da177e4SLinus Torvalds 
23101da177e4SLinus Torvalds 	rc = 0;
23114b02b524SEric Paris 	*len = policydb.p_bools.nprim;
23124b02b524SEric Paris 	if (!*len)
23131da177e4SLinus Torvalds 		goto out;
23141da177e4SLinus Torvalds 
23154b02b524SEric Paris 	rc = -ENOMEM;
2316e0795cf4SJesper Juhl 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
23171da177e4SLinus Torvalds 	if (!*names)
23181da177e4SLinus Torvalds 		goto err;
23191da177e4SLinus Torvalds 
23204b02b524SEric Paris 	rc = -ENOMEM;
2321e0795cf4SJesper Juhl 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
23221da177e4SLinus Torvalds 	if (!*values)
23231da177e4SLinus Torvalds 		goto err;
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
23261da177e4SLinus Torvalds 		size_t name_len;
23274b02b524SEric Paris 
23281da177e4SLinus Torvalds 		(*values)[i] = policydb.bool_val_to_struct[i]->state;
2329ac76c05bSEric Paris 		name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
23304b02b524SEric Paris 
23314b02b524SEric Paris 		rc = -ENOMEM;
2332e0795cf4SJesper Juhl 		(*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
23331da177e4SLinus Torvalds 		if (!(*names)[i])
23341da177e4SLinus Torvalds 			goto err;
23354b02b524SEric Paris 
2336ac76c05bSEric Paris 		strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
23371da177e4SLinus Torvalds 		(*names)[i][name_len - 1] = 0;
23381da177e4SLinus Torvalds 	}
23391da177e4SLinus Torvalds 	rc = 0;
23401da177e4SLinus Torvalds out:
23410804d113SJames Morris 	read_unlock(&policy_rwlock);
23421da177e4SLinus Torvalds 	return rc;
23431da177e4SLinus Torvalds err:
23441da177e4SLinus Torvalds 	if (*names) {
23451da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
23461da177e4SLinus Torvalds 			kfree((*names)[i]);
23471da177e4SLinus Torvalds 	}
23481da177e4SLinus Torvalds 	kfree(*values);
23491da177e4SLinus Torvalds 	goto out;
23501da177e4SLinus Torvalds }
23511da177e4SLinus Torvalds 
23521da177e4SLinus Torvalds 
23531da177e4SLinus Torvalds int security_set_bools(int len, int *values)
23541da177e4SLinus Torvalds {
23554b02b524SEric Paris 	int i, rc;
23561da177e4SLinus Torvalds 	int lenp, seqno = 0;
23571da177e4SLinus Torvalds 	struct cond_node *cur;
23581da177e4SLinus Torvalds 
23590804d113SJames Morris 	write_lock_irq(&policy_rwlock);
23601da177e4SLinus Torvalds 
23611da177e4SLinus Torvalds 	rc = -EFAULT;
23624b02b524SEric Paris 	lenp = policydb.p_bools.nprim;
23634b02b524SEric Paris 	if (len != lenp)
23641da177e4SLinus Torvalds 		goto out;
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
2367af601e46SSteve Grubb 		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
2368af601e46SSteve Grubb 			audit_log(current->audit_context, GFP_ATOMIC,
2369af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
23704746ec5bSEric Paris 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
2371ac76c05bSEric Paris 				sym_name(&policydb, SYM_BOOLS, i),
2372af601e46SSteve Grubb 				!!values[i],
2373af601e46SSteve Grubb 				policydb.bool_val_to_struct[i]->state,
23744746ec5bSEric Paris 				audit_get_loginuid(current),
23754746ec5bSEric Paris 				audit_get_sessionid(current));
2376af601e46SSteve Grubb 		}
23775d55a345SEric Paris 		if (values[i])
23781da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 1;
23795d55a345SEric Paris 		else
23801da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 0;
23811da177e4SLinus Torvalds 	}
23821da177e4SLinus Torvalds 
2383dbc74c65SVesa-Matti Kari 	for (cur = policydb.cond_list; cur; cur = cur->next) {
23841da177e4SLinus Torvalds 		rc = evaluate_cond_node(&policydb, cur);
23851da177e4SLinus Torvalds 		if (rc)
23861da177e4SLinus Torvalds 			goto out;
23871da177e4SLinus Torvalds 	}
23881da177e4SLinus Torvalds 
23891da177e4SLinus Torvalds 	seqno = ++latest_granting;
23904b02b524SEric Paris 	rc = 0;
23911da177e4SLinus Torvalds out:
23920804d113SJames Morris 	write_unlock_irq(&policy_rwlock);
23931da177e4SLinus Torvalds 	if (!rc) {
23941da177e4SLinus Torvalds 		avc_ss_reset(seqno);
23951da177e4SLinus Torvalds 		selnl_notify_policyload(seqno);
239611904167SKaiGai Kohei 		selinux_status_update_policyload(seqno);
2397342a0cffSVenkat Yekkirala 		selinux_xfrm_notify_policyload();
23981da177e4SLinus Torvalds 	}
23991da177e4SLinus Torvalds 	return rc;
24001da177e4SLinus Torvalds }
24011da177e4SLinus Torvalds 
24021da177e4SLinus Torvalds int security_get_bool_value(int bool)
24031da177e4SLinus Torvalds {
24044b02b524SEric Paris 	int rc;
24051da177e4SLinus Torvalds 	int len;
24061da177e4SLinus Torvalds 
24070804d113SJames Morris 	read_lock(&policy_rwlock);
24081da177e4SLinus Torvalds 
24091da177e4SLinus Torvalds 	rc = -EFAULT;
24104b02b524SEric Paris 	len = policydb.p_bools.nprim;
24114b02b524SEric Paris 	if (bool >= len)
24121da177e4SLinus Torvalds 		goto out;
24131da177e4SLinus Torvalds 
24141da177e4SLinus Torvalds 	rc = policydb.bool_val_to_struct[bool]->state;
24151da177e4SLinus Torvalds out:
24160804d113SJames Morris 	read_unlock(&policy_rwlock);
24171da177e4SLinus Torvalds 	return rc;
24181da177e4SLinus Torvalds }
2419376bd9cbSDarrel Goeddel 
2420e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p)
2421e900a7d9SStephen Smalley {
2422e900a7d9SStephen Smalley 	int rc, nbools = 0, *bvalues = NULL, i;
2423e900a7d9SStephen Smalley 	char **bnames = NULL;
2424e900a7d9SStephen Smalley 	struct cond_bool_datum *booldatum;
2425e900a7d9SStephen Smalley 	struct cond_node *cur;
2426e900a7d9SStephen Smalley 
2427e900a7d9SStephen Smalley 	rc = security_get_bools(&nbools, &bnames, &bvalues);
2428e900a7d9SStephen Smalley 	if (rc)
2429e900a7d9SStephen Smalley 		goto out;
2430e900a7d9SStephen Smalley 	for (i = 0; i < nbools; i++) {
2431e900a7d9SStephen Smalley 		booldatum = hashtab_search(p->p_bools.table, bnames[i]);
2432e900a7d9SStephen Smalley 		if (booldatum)
2433e900a7d9SStephen Smalley 			booldatum->state = bvalues[i];
2434e900a7d9SStephen Smalley 	}
2435dbc74c65SVesa-Matti Kari 	for (cur = p->cond_list; cur; cur = cur->next) {
2436e900a7d9SStephen Smalley 		rc = evaluate_cond_node(p, cur);
2437e900a7d9SStephen Smalley 		if (rc)
2438e900a7d9SStephen Smalley 			goto out;
2439e900a7d9SStephen Smalley 	}
2440e900a7d9SStephen Smalley 
2441e900a7d9SStephen Smalley out:
2442e900a7d9SStephen Smalley 	if (bnames) {
2443e900a7d9SStephen Smalley 		for (i = 0; i < nbools; i++)
2444e900a7d9SStephen Smalley 			kfree(bnames[i]);
2445e900a7d9SStephen Smalley 	}
2446e900a7d9SStephen Smalley 	kfree(bnames);
2447e900a7d9SStephen Smalley 	kfree(bvalues);
2448e900a7d9SStephen Smalley 	return rc;
2449e900a7d9SStephen Smalley }
2450e900a7d9SStephen Smalley 
245108554d6bSVenkat Yekkirala /*
245208554d6bSVenkat Yekkirala  * security_sid_mls_copy() - computes a new sid based on the given
245308554d6bSVenkat Yekkirala  * sid and the mls portion of mls_sid.
245408554d6bSVenkat Yekkirala  */
245508554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
245608554d6bSVenkat Yekkirala {
245708554d6bSVenkat Yekkirala 	struct context *context1;
245808554d6bSVenkat Yekkirala 	struct context *context2;
245908554d6bSVenkat Yekkirala 	struct context newcon;
246008554d6bSVenkat Yekkirala 	char *s;
246108554d6bSVenkat Yekkirala 	u32 len;
24624b02b524SEric Paris 	int rc;
246308554d6bSVenkat Yekkirala 
24644b02b524SEric Paris 	rc = 0;
24650719aaf5SGuido Trentalancia 	if (!ss_initialized || !policydb.mls_enabled) {
246608554d6bSVenkat Yekkirala 		*new_sid = sid;
246708554d6bSVenkat Yekkirala 		goto out;
246808554d6bSVenkat Yekkirala 	}
246908554d6bSVenkat Yekkirala 
247008554d6bSVenkat Yekkirala 	context_init(&newcon);
247108554d6bSVenkat Yekkirala 
24720804d113SJames Morris 	read_lock(&policy_rwlock);
24734b02b524SEric Paris 
24744b02b524SEric Paris 	rc = -EINVAL;
247508554d6bSVenkat Yekkirala 	context1 = sidtab_search(&sidtab, sid);
247608554d6bSVenkat Yekkirala 	if (!context1) {
2477744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2478744ba35eSEric Paris 			__func__, sid);
247908554d6bSVenkat Yekkirala 		goto out_unlock;
248008554d6bSVenkat Yekkirala 	}
248108554d6bSVenkat Yekkirala 
24824b02b524SEric Paris 	rc = -EINVAL;
248308554d6bSVenkat Yekkirala 	context2 = sidtab_search(&sidtab, mls_sid);
248408554d6bSVenkat Yekkirala 	if (!context2) {
2485744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2486744ba35eSEric Paris 			__func__, mls_sid);
248708554d6bSVenkat Yekkirala 		goto out_unlock;
248808554d6bSVenkat Yekkirala 	}
248908554d6bSVenkat Yekkirala 
249008554d6bSVenkat Yekkirala 	newcon.user = context1->user;
249108554d6bSVenkat Yekkirala 	newcon.role = context1->role;
249208554d6bSVenkat Yekkirala 	newcon.type = context1->type;
24930efc61eaSVenkat Yekkirala 	rc = mls_context_cpy(&newcon, context2);
249408554d6bSVenkat Yekkirala 	if (rc)
249508554d6bSVenkat Yekkirala 		goto out_unlock;
249608554d6bSVenkat Yekkirala 
249708554d6bSVenkat Yekkirala 	/* Check the validity of the new context. */
249808554d6bSVenkat Yekkirala 	if (!policydb_context_isvalid(&policydb, &newcon)) {
249908554d6bSVenkat Yekkirala 		rc = convert_context_handle_invalid_context(&newcon);
25004b02b524SEric Paris 		if (rc) {
250108554d6bSVenkat Yekkirala 			if (!context_struct_to_string(&newcon, &s, &len)) {
250208554d6bSVenkat Yekkirala 				audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
250308554d6bSVenkat Yekkirala 					  "security_sid_mls_copy: invalid context %s", s);
250408554d6bSVenkat Yekkirala 				kfree(s);
250508554d6bSVenkat Yekkirala 			}
25064b02b524SEric Paris 			goto out_unlock;
25074b02b524SEric Paris 		}
25084b02b524SEric Paris 	}
250908554d6bSVenkat Yekkirala 
25104b02b524SEric Paris 	rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid);
251108554d6bSVenkat Yekkirala out_unlock:
25120804d113SJames Morris 	read_unlock(&policy_rwlock);
251308554d6bSVenkat Yekkirala 	context_destroy(&newcon);
251408554d6bSVenkat Yekkirala out:
251508554d6bSVenkat Yekkirala 	return rc;
251608554d6bSVenkat Yekkirala }
251708554d6bSVenkat Yekkirala 
2518220deb96SPaul Moore /**
2519220deb96SPaul Moore  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
2520220deb96SPaul Moore  * @nlbl_sid: NetLabel SID
2521220deb96SPaul Moore  * @nlbl_type: NetLabel labeling protocol type
2522220deb96SPaul Moore  * @xfrm_sid: XFRM SID
2523220deb96SPaul Moore  *
2524220deb96SPaul Moore  * Description:
2525220deb96SPaul Moore  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
2526220deb96SPaul Moore  * resolved into a single SID it is returned via @peer_sid and the function
2527220deb96SPaul Moore  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
2528220deb96SPaul Moore  * returns a negative value.  A table summarizing the behavior is below:
2529220deb96SPaul Moore  *
2530220deb96SPaul Moore  *                                 | function return |      @sid
2531220deb96SPaul Moore  *   ------------------------------+-----------------+-----------------
2532220deb96SPaul Moore  *   no peer labels                |        0        |    SECSID_NULL
2533220deb96SPaul Moore  *   single peer label             |        0        |    <peer_label>
2534220deb96SPaul Moore  *   multiple, consistent labels   |        0        |    <peer_label>
2535220deb96SPaul Moore  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
2536220deb96SPaul Moore  *
2537220deb96SPaul Moore  */
2538220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
2539220deb96SPaul Moore 				 u32 xfrm_sid,
2540220deb96SPaul Moore 				 u32 *peer_sid)
2541220deb96SPaul Moore {
2542220deb96SPaul Moore 	int rc;
2543220deb96SPaul Moore 	struct context *nlbl_ctx;
2544220deb96SPaul Moore 	struct context *xfrm_ctx;
2545220deb96SPaul Moore 
25464b02b524SEric Paris 	*peer_sid = SECSID_NULL;
25474b02b524SEric Paris 
2548220deb96SPaul Moore 	/* handle the common (which also happens to be the set of easy) cases
2549220deb96SPaul Moore 	 * right away, these two if statements catch everything involving a
2550220deb96SPaul Moore 	 * single or absent peer SID/label */
2551220deb96SPaul Moore 	if (xfrm_sid == SECSID_NULL) {
2552220deb96SPaul Moore 		*peer_sid = nlbl_sid;
2553220deb96SPaul Moore 		return 0;
2554220deb96SPaul Moore 	}
2555220deb96SPaul Moore 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
2556220deb96SPaul Moore 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
2557220deb96SPaul Moore 	 * is present */
2558220deb96SPaul Moore 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
2559220deb96SPaul Moore 		*peer_sid = xfrm_sid;
2560220deb96SPaul Moore 		return 0;
2561220deb96SPaul Moore 	}
2562220deb96SPaul Moore 
2563220deb96SPaul Moore 	/* we don't need to check ss_initialized here since the only way both
2564220deb96SPaul Moore 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
2565220deb96SPaul Moore 	 * security server was initialized and ss_initialized was true */
25664b02b524SEric Paris 	if (!policydb.mls_enabled)
2567220deb96SPaul Moore 		return 0;
2568220deb96SPaul Moore 
25690804d113SJames Morris 	read_lock(&policy_rwlock);
2570220deb96SPaul Moore 
25714b02b524SEric Paris 	rc = -EINVAL;
2572220deb96SPaul Moore 	nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
2573220deb96SPaul Moore 	if (!nlbl_ctx) {
2574744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2575744ba35eSEric Paris 		       __func__, nlbl_sid);
25764b02b524SEric Paris 		goto out;
2577220deb96SPaul Moore 	}
25784b02b524SEric Paris 	rc = -EINVAL;
2579220deb96SPaul Moore 	xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
2580220deb96SPaul Moore 	if (!xfrm_ctx) {
2581744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
2582744ba35eSEric Paris 		       __func__, xfrm_sid);
25834b02b524SEric Paris 		goto out;
2584220deb96SPaul Moore 	}
2585220deb96SPaul Moore 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
25864b02b524SEric Paris 	if (rc)
25874b02b524SEric Paris 		goto out;
2588220deb96SPaul Moore 
2589220deb96SPaul Moore 	/* at present NetLabel SIDs/labels really only carry MLS
2590220deb96SPaul Moore 	 * information so if the MLS portion of the NetLabel SID
2591220deb96SPaul Moore 	 * matches the MLS portion of the labeled XFRM SID/label
2592220deb96SPaul Moore 	 * then pass along the XFRM SID as it is the most
2593220deb96SPaul Moore 	 * expressive */
2594220deb96SPaul Moore 	*peer_sid = xfrm_sid;
25954b02b524SEric Paris out:
25964b02b524SEric Paris 	read_unlock(&policy_rwlock);
2597220deb96SPaul Moore 	return rc;
2598220deb96SPaul Moore }
2599220deb96SPaul Moore 
260055fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
260155fcf09bSChristopher J. PeBenito {
260255fcf09bSChristopher J. PeBenito 	struct class_datum *datum = d;
260355fcf09bSChristopher J. PeBenito 	char *name = k, **classes = args;
260455fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
260555fcf09bSChristopher J. PeBenito 
260655fcf09bSChristopher J. PeBenito 	classes[value] = kstrdup(name, GFP_ATOMIC);
260755fcf09bSChristopher J. PeBenito 	if (!classes[value])
260855fcf09bSChristopher J. PeBenito 		return -ENOMEM;
260955fcf09bSChristopher J. PeBenito 
261055fcf09bSChristopher J. PeBenito 	return 0;
261155fcf09bSChristopher J. PeBenito }
261255fcf09bSChristopher J. PeBenito 
261355fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses)
261455fcf09bSChristopher J. PeBenito {
26154b02b524SEric Paris 	int rc;
261655fcf09bSChristopher J. PeBenito 
26170804d113SJames Morris 	read_lock(&policy_rwlock);
261855fcf09bSChristopher J. PeBenito 
26194b02b524SEric Paris 	rc = -ENOMEM;
262055fcf09bSChristopher J. PeBenito 	*nclasses = policydb.p_classes.nprim;
26219f59f90bSJulia Lawall 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
262255fcf09bSChristopher J. PeBenito 	if (!*classes)
262355fcf09bSChristopher J. PeBenito 		goto out;
262455fcf09bSChristopher J. PeBenito 
262555fcf09bSChristopher J. PeBenito 	rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
262655fcf09bSChristopher J. PeBenito 			*classes);
26274b02b524SEric Paris 	if (rc) {
262855fcf09bSChristopher J. PeBenito 		int i;
262955fcf09bSChristopher J. PeBenito 		for (i = 0; i < *nclasses; i++)
263055fcf09bSChristopher J. PeBenito 			kfree((*classes)[i]);
263155fcf09bSChristopher J. PeBenito 		kfree(*classes);
263255fcf09bSChristopher J. PeBenito 	}
263355fcf09bSChristopher J. PeBenito 
263455fcf09bSChristopher J. PeBenito out:
26350804d113SJames Morris 	read_unlock(&policy_rwlock);
263655fcf09bSChristopher J. PeBenito 	return rc;
263755fcf09bSChristopher J. PeBenito }
263855fcf09bSChristopher J. PeBenito 
263955fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
264055fcf09bSChristopher J. PeBenito {
264155fcf09bSChristopher J. PeBenito 	struct perm_datum *datum = d;
264255fcf09bSChristopher J. PeBenito 	char *name = k, **perms = args;
264355fcf09bSChristopher J. PeBenito 	int value = datum->value - 1;
264455fcf09bSChristopher J. PeBenito 
264555fcf09bSChristopher J. PeBenito 	perms[value] = kstrdup(name, GFP_ATOMIC);
264655fcf09bSChristopher J. PeBenito 	if (!perms[value])
264755fcf09bSChristopher J. PeBenito 		return -ENOMEM;
264855fcf09bSChristopher J. PeBenito 
264955fcf09bSChristopher J. PeBenito 	return 0;
265055fcf09bSChristopher J. PeBenito }
265155fcf09bSChristopher J. PeBenito 
265255fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms)
265355fcf09bSChristopher J. PeBenito {
26544b02b524SEric Paris 	int rc, i;
265555fcf09bSChristopher J. PeBenito 	struct class_datum *match;
265655fcf09bSChristopher J. PeBenito 
26570804d113SJames Morris 	read_lock(&policy_rwlock);
265855fcf09bSChristopher J. PeBenito 
26594b02b524SEric Paris 	rc = -EINVAL;
266055fcf09bSChristopher J. PeBenito 	match = hashtab_search(policydb.p_classes.table, class);
266155fcf09bSChristopher J. PeBenito 	if (!match) {
2662744ba35eSEric Paris 		printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
2663dd6f953aSHarvey Harrison 			__func__, class);
266455fcf09bSChristopher J. PeBenito 		goto out;
266555fcf09bSChristopher J. PeBenito 	}
266655fcf09bSChristopher J. PeBenito 
26674b02b524SEric Paris 	rc = -ENOMEM;
266855fcf09bSChristopher J. PeBenito 	*nperms = match->permissions.nprim;
26699f59f90bSJulia Lawall 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
267055fcf09bSChristopher J. PeBenito 	if (!*perms)
267155fcf09bSChristopher J. PeBenito 		goto out;
267255fcf09bSChristopher J. PeBenito 
267355fcf09bSChristopher J. PeBenito 	if (match->comdatum) {
267455fcf09bSChristopher J. PeBenito 		rc = hashtab_map(match->comdatum->permissions.table,
267555fcf09bSChristopher J. PeBenito 				get_permissions_callback, *perms);
26764b02b524SEric Paris 		if (rc)
267755fcf09bSChristopher J. PeBenito 			goto err;
267855fcf09bSChristopher J. PeBenito 	}
267955fcf09bSChristopher J. PeBenito 
268055fcf09bSChristopher J. PeBenito 	rc = hashtab_map(match->permissions.table, get_permissions_callback,
268155fcf09bSChristopher J. PeBenito 			*perms);
26824b02b524SEric Paris 	if (rc)
268355fcf09bSChristopher J. PeBenito 		goto err;
268455fcf09bSChristopher J. PeBenito 
268555fcf09bSChristopher J. PeBenito out:
26860804d113SJames Morris 	read_unlock(&policy_rwlock);
268755fcf09bSChristopher J. PeBenito 	return rc;
268855fcf09bSChristopher J. PeBenito 
268955fcf09bSChristopher J. PeBenito err:
26900804d113SJames Morris 	read_unlock(&policy_rwlock);
269155fcf09bSChristopher J. PeBenito 	for (i = 0; i < *nperms; i++)
269255fcf09bSChristopher J. PeBenito 		kfree((*perms)[i]);
269355fcf09bSChristopher J. PeBenito 	kfree(*perms);
269455fcf09bSChristopher J. PeBenito 	return rc;
269555fcf09bSChristopher J. PeBenito }
269655fcf09bSChristopher J. PeBenito 
26973f12070eSEric Paris int security_get_reject_unknown(void)
26983f12070eSEric Paris {
26993f12070eSEric Paris 	return policydb.reject_unknown;
27003f12070eSEric Paris }
27013f12070eSEric Paris 
27023f12070eSEric Paris int security_get_allow_unknown(void)
27033f12070eSEric Paris {
27043f12070eSEric Paris 	return policydb.allow_unknown;
27053f12070eSEric Paris }
27063f12070eSEric Paris 
27073bb56b25SPaul Moore /**
27083bb56b25SPaul Moore  * security_policycap_supported - Check for a specific policy capability
27093bb56b25SPaul Moore  * @req_cap: capability
27103bb56b25SPaul Moore  *
27113bb56b25SPaul Moore  * Description:
27123bb56b25SPaul Moore  * This function queries the currently loaded policy to see if it supports the
27133bb56b25SPaul Moore  * capability specified by @req_cap.  Returns true (1) if the capability is
27143bb56b25SPaul Moore  * supported, false (0) if it isn't supported.
27153bb56b25SPaul Moore  *
27163bb56b25SPaul Moore  */
27173bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap)
27183bb56b25SPaul Moore {
27193bb56b25SPaul Moore 	int rc;
27203bb56b25SPaul Moore 
27210804d113SJames Morris 	read_lock(&policy_rwlock);
27223bb56b25SPaul Moore 	rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
27230804d113SJames Morris 	read_unlock(&policy_rwlock);
27243bb56b25SPaul Moore 
27253bb56b25SPaul Moore 	return rc;
27263bb56b25SPaul Moore }
27273bb56b25SPaul Moore 
2728376bd9cbSDarrel Goeddel struct selinux_audit_rule {
2729376bd9cbSDarrel Goeddel 	u32 au_seqno;
2730376bd9cbSDarrel Goeddel 	struct context au_ctxt;
2731376bd9cbSDarrel Goeddel };
2732376bd9cbSDarrel Goeddel 
27339d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
2734376bd9cbSDarrel Goeddel {
27359d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
27369d57a7f9SAhmed S. Darwish 
2737376bd9cbSDarrel Goeddel 	if (rule) {
2738376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
2739376bd9cbSDarrel Goeddel 		kfree(rule);
2740376bd9cbSDarrel Goeddel 	}
2741376bd9cbSDarrel Goeddel }
2742376bd9cbSDarrel Goeddel 
27439d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
2744376bd9cbSDarrel Goeddel {
2745376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
2746376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
2747376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
2748376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
27499d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
2750376bd9cbSDarrel Goeddel 	int rc = 0;
2751376bd9cbSDarrel Goeddel 
2752376bd9cbSDarrel Goeddel 	*rule = NULL;
2753376bd9cbSDarrel Goeddel 
2754376bd9cbSDarrel Goeddel 	if (!ss_initialized)
27553ad40d64SSteve G 		return -EOPNOTSUPP;
2756376bd9cbSDarrel Goeddel 
2757376bd9cbSDarrel Goeddel 	switch (field) {
27583a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
27593a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
27603a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
27616e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
27626e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
27636e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
2764376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
27655af75d8dSAl Viro 		if (op != Audit_equal && op != Audit_not_equal)
2766376bd9cbSDarrel Goeddel 			return -EINVAL;
2767376bd9cbSDarrel Goeddel 		break;
27683a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
27693a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
27706e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
27716e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
2772376bd9cbSDarrel Goeddel 		/* we do not allow a range, indicated by the presense of '-' */
2773376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
2774376bd9cbSDarrel Goeddel 			return -EINVAL;
2775376bd9cbSDarrel Goeddel 		break;
2776376bd9cbSDarrel Goeddel 	default:
2777376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
2778376bd9cbSDarrel Goeddel 		return -EINVAL;
2779376bd9cbSDarrel Goeddel 	}
2780376bd9cbSDarrel Goeddel 
2781376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
2782376bd9cbSDarrel Goeddel 	if (!tmprule)
2783376bd9cbSDarrel Goeddel 		return -ENOMEM;
2784376bd9cbSDarrel Goeddel 
2785376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
2786376bd9cbSDarrel Goeddel 
27870804d113SJames Morris 	read_lock(&policy_rwlock);
2788376bd9cbSDarrel Goeddel 
2789376bd9cbSDarrel Goeddel 	tmprule->au_seqno = latest_granting;
2790376bd9cbSDarrel Goeddel 
2791376bd9cbSDarrel Goeddel 	switch (field) {
27923a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
27936e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
27944b02b524SEric Paris 		rc = -EINVAL;
2795376bd9cbSDarrel Goeddel 		userdatum = hashtab_search(policydb.p_users.table, rulestr);
2796376bd9cbSDarrel Goeddel 		if (!userdatum)
27974b02b524SEric Paris 			goto out;
2798376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.user = userdatum->value;
2799376bd9cbSDarrel Goeddel 		break;
28003a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
28016e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
28024b02b524SEric Paris 		rc = -EINVAL;
2803376bd9cbSDarrel Goeddel 		roledatum = hashtab_search(policydb.p_roles.table, rulestr);
2804376bd9cbSDarrel Goeddel 		if (!roledatum)
28054b02b524SEric Paris 			goto out;
2806376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.role = roledatum->value;
2807376bd9cbSDarrel Goeddel 		break;
28083a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
28096e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
28104b02b524SEric Paris 		rc = -EINVAL;
2811376bd9cbSDarrel Goeddel 		typedatum = hashtab_search(policydb.p_types.table, rulestr);
2812376bd9cbSDarrel Goeddel 		if (!typedatum)
28134b02b524SEric Paris 			goto out;
2814376bd9cbSDarrel Goeddel 		tmprule->au_ctxt.type = typedatum->value;
2815376bd9cbSDarrel Goeddel 		break;
28163a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
28173a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
28186e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
28196e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
2820376bd9cbSDarrel Goeddel 		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
28214b02b524SEric Paris 		if (rc)
28224b02b524SEric Paris 			goto out;
2823376bd9cbSDarrel Goeddel 		break;
2824376bd9cbSDarrel Goeddel 	}
28254b02b524SEric Paris 	rc = 0;
28264b02b524SEric Paris out:
28270804d113SJames Morris 	read_unlock(&policy_rwlock);
2828376bd9cbSDarrel Goeddel 
2829376bd9cbSDarrel Goeddel 	if (rc) {
2830376bd9cbSDarrel Goeddel 		selinux_audit_rule_free(tmprule);
2831376bd9cbSDarrel Goeddel 		tmprule = NULL;
2832376bd9cbSDarrel Goeddel 	}
2833376bd9cbSDarrel Goeddel 
2834376bd9cbSDarrel Goeddel 	*rule = tmprule;
2835376bd9cbSDarrel Goeddel 
2836376bd9cbSDarrel Goeddel 	return rc;
2837376bd9cbSDarrel Goeddel }
2838376bd9cbSDarrel Goeddel 
28399d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
28409d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
28419d57a7f9SAhmed S. Darwish {
28429d57a7f9SAhmed S. Darwish 	int i;
28439d57a7f9SAhmed S. Darwish 
28449d57a7f9SAhmed S. Darwish 	for (i = 0; i < rule->field_count; i++) {
28459d57a7f9SAhmed S. Darwish 		struct audit_field *f = &rule->fields[i];
28469d57a7f9SAhmed S. Darwish 		switch (f->type) {
28479d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_USER:
28489d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_ROLE:
28499d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_TYPE:
28509d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_SEN:
28519d57a7f9SAhmed S. Darwish 		case AUDIT_SUBJ_CLR:
28529d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_USER:
28539d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_ROLE:
28549d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_TYPE:
28559d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_LOW:
28569d57a7f9SAhmed S. Darwish 		case AUDIT_OBJ_LEV_HIGH:
28579d57a7f9SAhmed S. Darwish 			return 1;
28589d57a7f9SAhmed S. Darwish 		}
28599d57a7f9SAhmed S. Darwish 	}
28609d57a7f9SAhmed S. Darwish 
28619d57a7f9SAhmed S. Darwish 	return 0;
28629d57a7f9SAhmed S. Darwish }
28639d57a7f9SAhmed S. Darwish 
28649d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
2865376bd9cbSDarrel Goeddel 			     struct audit_context *actx)
2866376bd9cbSDarrel Goeddel {
2867376bd9cbSDarrel Goeddel 	struct context *ctxt;
2868376bd9cbSDarrel Goeddel 	struct mls_level *level;
28699d57a7f9SAhmed S. Darwish 	struct selinux_audit_rule *rule = vrule;
2870376bd9cbSDarrel Goeddel 	int match = 0;
2871376bd9cbSDarrel Goeddel 
2872376bd9cbSDarrel Goeddel 	if (!rule) {
2873376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
2874376bd9cbSDarrel Goeddel 			  "selinux_audit_rule_match: missing rule\n");
2875376bd9cbSDarrel Goeddel 		return -ENOENT;
2876376bd9cbSDarrel Goeddel 	}
2877376bd9cbSDarrel Goeddel 
28780804d113SJames Morris 	read_lock(&policy_rwlock);
2879376bd9cbSDarrel Goeddel 
2880376bd9cbSDarrel Goeddel 	if (rule->au_seqno < latest_granting) {
2881376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
2882376bd9cbSDarrel Goeddel 			  "selinux_audit_rule_match: stale rule\n");
2883376bd9cbSDarrel Goeddel 		match = -ESTALE;
2884376bd9cbSDarrel Goeddel 		goto out;
2885376bd9cbSDarrel Goeddel 	}
2886376bd9cbSDarrel Goeddel 
28879a2f44f0SStephen Smalley 	ctxt = sidtab_search(&sidtab, sid);
2888376bd9cbSDarrel Goeddel 	if (!ctxt) {
2889376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
2890376bd9cbSDarrel Goeddel 			  "selinux_audit_rule_match: unrecognized SID %d\n",
28919a2f44f0SStephen Smalley 			  sid);
2892376bd9cbSDarrel Goeddel 		match = -ENOENT;
2893376bd9cbSDarrel Goeddel 		goto out;
2894376bd9cbSDarrel Goeddel 	}
2895376bd9cbSDarrel Goeddel 
2896376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
2897376bd9cbSDarrel Goeddel 	   without a match */
2898376bd9cbSDarrel Goeddel 	switch (field) {
28993a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_USER:
29006e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_USER:
2901376bd9cbSDarrel Goeddel 		switch (op) {
29025af75d8dSAl Viro 		case Audit_equal:
2903376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
2904376bd9cbSDarrel Goeddel 			break;
29055af75d8dSAl Viro 		case Audit_not_equal:
2906376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
2907376bd9cbSDarrel Goeddel 			break;
2908376bd9cbSDarrel Goeddel 		}
2909376bd9cbSDarrel Goeddel 		break;
29103a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_ROLE:
29116e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_ROLE:
2912376bd9cbSDarrel Goeddel 		switch (op) {
29135af75d8dSAl Viro 		case Audit_equal:
2914376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
2915376bd9cbSDarrel Goeddel 			break;
29165af75d8dSAl Viro 		case Audit_not_equal:
2917376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
2918376bd9cbSDarrel Goeddel 			break;
2919376bd9cbSDarrel Goeddel 		}
2920376bd9cbSDarrel Goeddel 		break;
29213a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_TYPE:
29226e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_TYPE:
2923376bd9cbSDarrel Goeddel 		switch (op) {
29245af75d8dSAl Viro 		case Audit_equal:
2925376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
2926376bd9cbSDarrel Goeddel 			break;
29275af75d8dSAl Viro 		case Audit_not_equal:
2928376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
2929376bd9cbSDarrel Goeddel 			break;
2930376bd9cbSDarrel Goeddel 		}
2931376bd9cbSDarrel Goeddel 		break;
29323a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_SEN:
29333a6b9f85SDarrel Goeddel 	case AUDIT_SUBJ_CLR:
29346e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_LOW:
29356e5a2d1dSDarrel Goeddel 	case AUDIT_OBJ_LEV_HIGH:
29366e5a2d1dSDarrel Goeddel 		level = ((field == AUDIT_SUBJ_SEN ||
29376e5a2d1dSDarrel Goeddel 			  field == AUDIT_OBJ_LEV_LOW) ?
2938376bd9cbSDarrel Goeddel 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
2939376bd9cbSDarrel Goeddel 		switch (op) {
29405af75d8dSAl Viro 		case Audit_equal:
2941376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
2942376bd9cbSDarrel Goeddel 					     level);
2943376bd9cbSDarrel Goeddel 			break;
29445af75d8dSAl Viro 		case Audit_not_equal:
2945376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
2946376bd9cbSDarrel Goeddel 					      level);
2947376bd9cbSDarrel Goeddel 			break;
29485af75d8dSAl Viro 		case Audit_lt:
2949376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
2950376bd9cbSDarrel Goeddel 					       level) &&
2951376bd9cbSDarrel Goeddel 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
2952376bd9cbSDarrel Goeddel 					       level));
2953376bd9cbSDarrel Goeddel 			break;
29545af75d8dSAl Viro 		case Audit_le:
2955376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
2956376bd9cbSDarrel Goeddel 					      level);
2957376bd9cbSDarrel Goeddel 			break;
29585af75d8dSAl Viro 		case Audit_gt:
2959376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
2960376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]) &&
2961376bd9cbSDarrel Goeddel 				 !mls_level_eq(level,
2962376bd9cbSDarrel Goeddel 					       &rule->au_ctxt.range.level[0]));
2963376bd9cbSDarrel Goeddel 			break;
29645af75d8dSAl Viro 		case Audit_ge:
2965376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
2966376bd9cbSDarrel Goeddel 					      &rule->au_ctxt.range.level[0]);
2967376bd9cbSDarrel Goeddel 			break;
2968376bd9cbSDarrel Goeddel 		}
2969376bd9cbSDarrel Goeddel 	}
2970376bd9cbSDarrel Goeddel 
2971376bd9cbSDarrel Goeddel out:
29720804d113SJames Morris 	read_unlock(&policy_rwlock);
2973376bd9cbSDarrel Goeddel 	return match;
2974376bd9cbSDarrel Goeddel }
2975376bd9cbSDarrel Goeddel 
29769d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules;
2977376bd9cbSDarrel Goeddel 
2978376bd9cbSDarrel Goeddel static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
2979376bd9cbSDarrel Goeddel 			       u16 class, u32 perms, u32 *retained)
2980376bd9cbSDarrel Goeddel {
2981376bd9cbSDarrel Goeddel 	int err = 0;
2982376bd9cbSDarrel Goeddel 
2983376bd9cbSDarrel Goeddel 	if (event == AVC_CALLBACK_RESET && aurule_callback)
2984376bd9cbSDarrel Goeddel 		err = aurule_callback();
2985376bd9cbSDarrel Goeddel 	return err;
2986376bd9cbSDarrel Goeddel }
2987376bd9cbSDarrel Goeddel 
2988376bd9cbSDarrel Goeddel static int __init aurule_init(void)
2989376bd9cbSDarrel Goeddel {
2990376bd9cbSDarrel Goeddel 	int err;
2991376bd9cbSDarrel Goeddel 
2992376bd9cbSDarrel Goeddel 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
2993376bd9cbSDarrel Goeddel 			       SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
2994376bd9cbSDarrel Goeddel 	if (err)
2995376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
2996376bd9cbSDarrel Goeddel 
2997376bd9cbSDarrel Goeddel 	return err;
2998376bd9cbSDarrel Goeddel }
2999376bd9cbSDarrel Goeddel __initcall(aurule_init);
3000376bd9cbSDarrel Goeddel 
30017420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
30027420ed23SVenkat Yekkirala /**
30035778eabdSPaul Moore  * security_netlbl_cache_add - Add an entry to the NetLabel cache
30045778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
30055dbe1eb0SPaul Moore  * @sid: the SELinux SID
30067420ed23SVenkat Yekkirala  *
30077420ed23SVenkat Yekkirala  * Description:
30087420ed23SVenkat Yekkirala  * Attempt to cache the context in @ctx, which was derived from the packet in
30095778eabdSPaul Moore  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
30105778eabdSPaul Moore  * already been initialized.
30117420ed23SVenkat Yekkirala  *
30127420ed23SVenkat Yekkirala  */
30135778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
30145dbe1eb0SPaul Moore 				      u32 sid)
30157420ed23SVenkat Yekkirala {
30165dbe1eb0SPaul Moore 	u32 *sid_cache;
30177420ed23SVenkat Yekkirala 
30185dbe1eb0SPaul Moore 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
30195dbe1eb0SPaul Moore 	if (sid_cache == NULL)
30205dbe1eb0SPaul Moore 		return;
30215778eabdSPaul Moore 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
30225dbe1eb0SPaul Moore 	if (secattr->cache == NULL) {
30235dbe1eb0SPaul Moore 		kfree(sid_cache);
30245778eabdSPaul Moore 		return;
30250ec8abd7SJesper Juhl 	}
30267420ed23SVenkat Yekkirala 
30275dbe1eb0SPaul Moore 	*sid_cache = sid;
30285dbe1eb0SPaul Moore 	secattr->cache->free = kfree;
30295dbe1eb0SPaul Moore 	secattr->cache->data = sid_cache;
30305778eabdSPaul Moore 	secattr->flags |= NETLBL_SECATTR_CACHE;
30317420ed23SVenkat Yekkirala }
30327420ed23SVenkat Yekkirala 
30337420ed23SVenkat Yekkirala /**
30345778eabdSPaul Moore  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
30357420ed23SVenkat Yekkirala  * @secattr: the NetLabel packet security attributes
30367420ed23SVenkat Yekkirala  * @sid: the SELinux SID
30377420ed23SVenkat Yekkirala  *
30387420ed23SVenkat Yekkirala  * Description:
30395778eabdSPaul Moore  * Convert the given NetLabel security attributes in @secattr into a
30407420ed23SVenkat Yekkirala  * SELinux SID.  If the @secattr field does not contain a full SELinux
30415dbe1eb0SPaul Moore  * SID/context then use SECINITSID_NETMSG as the foundation.  If possibile the
30425dbe1eb0SPaul Moore  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
30435dbe1eb0SPaul Moore  * allow the @secattr to be used by NetLabel to cache the secattr to SID
30445dbe1eb0SPaul Moore  * conversion for future lookups.  Returns zero on success, negative values on
30455dbe1eb0SPaul Moore  * failure.
30467420ed23SVenkat Yekkirala  *
30477420ed23SVenkat Yekkirala  */
30485778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
30497420ed23SVenkat Yekkirala 				   u32 *sid)
30507420ed23SVenkat Yekkirala {
30517ae9f23cSEric Paris 	int rc;
30527420ed23SVenkat Yekkirala 	struct context *ctx;
30537420ed23SVenkat Yekkirala 	struct context ctx_new;
30545778eabdSPaul Moore 
30555778eabdSPaul Moore 	if (!ss_initialized) {
30565778eabdSPaul Moore 		*sid = SECSID_NULL;
30575778eabdSPaul Moore 		return 0;
30585778eabdSPaul Moore 	}
30597420ed23SVenkat Yekkirala 
30600804d113SJames Morris 	read_lock(&policy_rwlock);
30617420ed23SVenkat Yekkirala 
30627ae9f23cSEric Paris 	if (secattr->flags & NETLBL_SECATTR_CACHE)
30635dbe1eb0SPaul Moore 		*sid = *(u32 *)secattr->cache->data;
30647ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_SECID)
306516efd454SPaul Moore 		*sid = secattr->attr.secid;
30667ae9f23cSEric Paris 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
30677ae9f23cSEric Paris 		rc = -EIDRM;
30685dbe1eb0SPaul Moore 		ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
30697420ed23SVenkat Yekkirala 		if (ctx == NULL)
30707ae9f23cSEric Paris 			goto out;
30717420ed23SVenkat Yekkirala 
307281990fbdSPaul Moore 		context_init(&ctx_new);
30737420ed23SVenkat Yekkirala 		ctx_new.user = ctx->user;
30747420ed23SVenkat Yekkirala 		ctx_new.role = ctx->role;
30757420ed23SVenkat Yekkirala 		ctx_new.type = ctx->type;
307602752760SPaul Moore 		mls_import_netlbl_lvl(&ctx_new, secattr);
3077701a90baSPaul Moore 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
30787ae9f23cSEric Paris 			rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
30797ae9f23cSEric Paris 						   secattr->attr.mls.cat);
30807ae9f23cSEric Paris 			if (rc)
30817ae9f23cSEric Paris 				goto out;
308281990fbdSPaul Moore 			memcpy(&ctx_new.range.level[1].cat,
308381990fbdSPaul Moore 			       &ctx_new.range.level[0].cat,
308481990fbdSPaul Moore 			       sizeof(ctx_new.range.level[0].cat));
30857420ed23SVenkat Yekkirala 		}
30867ae9f23cSEric Paris 		rc = -EIDRM;
30877ae9f23cSEric Paris 		if (!mls_context_isvalid(&policydb, &ctx_new))
30887ae9f23cSEric Paris 			goto out_free;
30897420ed23SVenkat Yekkirala 
30907420ed23SVenkat Yekkirala 		rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
30917ae9f23cSEric Paris 		if (rc)
30927ae9f23cSEric Paris 			goto out_free;
30937420ed23SVenkat Yekkirala 
30945dbe1eb0SPaul Moore 		security_netlbl_cache_add(secattr, *sid);
30955778eabdSPaul Moore 
30967420ed23SVenkat Yekkirala 		ebitmap_destroy(&ctx_new.range.level[0].cat);
30977ae9f23cSEric Paris 	} else
3098388b2405Spaul.moore@hp.com 		*sid = SECSID_NULL;
30997420ed23SVenkat Yekkirala 
31007ae9f23cSEric Paris 	read_unlock(&policy_rwlock);
31017ae9f23cSEric Paris 	return 0;
31027ae9f23cSEric Paris out_free:
31037ae9f23cSEric Paris 	ebitmap_destroy(&ctx_new.range.level[0].cat);
31047ae9f23cSEric Paris out:
31050804d113SJames Morris 	read_unlock(&policy_rwlock);
31067420ed23SVenkat Yekkirala 	return rc;
31077420ed23SVenkat Yekkirala }
31087420ed23SVenkat Yekkirala 
31097420ed23SVenkat Yekkirala /**
31105778eabdSPaul Moore  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
31115778eabdSPaul Moore  * @sid: the SELinux SID
31125778eabdSPaul Moore  * @secattr: the NetLabel packet security attributes
31137420ed23SVenkat Yekkirala  *
31147420ed23SVenkat Yekkirala  * Description:
31155778eabdSPaul Moore  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
31165778eabdSPaul Moore  * Returns zero on success, negative values on failure.
31177420ed23SVenkat Yekkirala  *
31187420ed23SVenkat Yekkirala  */
31195778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
31207420ed23SVenkat Yekkirala {
312199d854d2SPaul Moore 	int rc;
31227420ed23SVenkat Yekkirala 	struct context *ctx;
31237420ed23SVenkat Yekkirala 
31247420ed23SVenkat Yekkirala 	if (!ss_initialized)
31257420ed23SVenkat Yekkirala 		return 0;
31267420ed23SVenkat Yekkirala 
31270804d113SJames Morris 	read_lock(&policy_rwlock);
31284b02b524SEric Paris 
312999d854d2SPaul Moore 	rc = -ENOENT;
31304b02b524SEric Paris 	ctx = sidtab_search(&sidtab, sid);
31314b02b524SEric Paris 	if (ctx == NULL)
31324b02b524SEric Paris 		goto out;
31334b02b524SEric Paris 
31344b02b524SEric Paris 	rc = -ENOMEM;
3135ac76c05bSEric Paris 	secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1),
31367420ed23SVenkat Yekkirala 				  GFP_ATOMIC);
31374b02b524SEric Paris 	if (secattr->domain == NULL)
31384b02b524SEric Paris 		goto out;
31394b02b524SEric Paris 
31408d75899dSPaul Moore 	secattr->attr.secid = sid;
31418d75899dSPaul Moore 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
31425778eabdSPaul Moore 	mls_export_netlbl_lvl(ctx, secattr);
31435778eabdSPaul Moore 	rc = mls_export_netlbl_cat(ctx, secattr);
31444b02b524SEric Paris out:
31450804d113SJames Morris 	read_unlock(&policy_rwlock);
3146f8687afeSPaul Moore 	return rc;
3147f8687afeSPaul Moore }
31487420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3149cee74f47SEric Paris 
3150cee74f47SEric Paris /**
3151cee74f47SEric Paris  * security_read_policy - read the policy.
3152cee74f47SEric Paris  * @data: binary policy data
3153cee74f47SEric Paris  * @len: length of data in bytes
3154cee74f47SEric Paris  *
3155cee74f47SEric Paris  */
3156cee74f47SEric Paris int security_read_policy(void **data, ssize_t *len)
3157cee74f47SEric Paris {
3158cee74f47SEric Paris 	int rc;
3159cee74f47SEric Paris 	struct policy_file fp;
3160cee74f47SEric Paris 
3161cee74f47SEric Paris 	if (!ss_initialized)
3162cee74f47SEric Paris 		return -EINVAL;
3163cee74f47SEric Paris 
3164cee74f47SEric Paris 	*len = security_policydb_len();
3165cee74f47SEric Paris 
3166845ca30fSEric Paris 	*data = vmalloc_user(*len);
3167cee74f47SEric Paris 	if (!*data)
3168cee74f47SEric Paris 		return -ENOMEM;
3169cee74f47SEric Paris 
3170cee74f47SEric Paris 	fp.data = *data;
3171cee74f47SEric Paris 	fp.len = *len;
3172cee74f47SEric Paris 
3173cee74f47SEric Paris 	read_lock(&policy_rwlock);
3174cee74f47SEric Paris 	rc = policydb_write(&policydb, &fp);
3175cee74f47SEric Paris 	read_unlock(&policy_rwlock);
3176cee74f47SEric Paris 
3177cee74f47SEric Paris 	if (rc)
3178cee74f47SEric Paris 		return rc;
3179cee74f47SEric Paris 
3180cee74f47SEric Paris 	*len = (unsigned long)fp.data - (unsigned long)*data;
3181cee74f47SEric Paris 	return 0;
3182cee74f47SEric Paris 
3183cee74f47SEric Paris }
3184