xref: /OK3568_Linux_fs/kernel/security/selinux/ss/services.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Implementation of the security services.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors : Stephen Smalley, <sds@tycho.nsa.gov>
6*4882a593Smuzhiyun  *	     James Morris <jmorris@redhat.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *	Support for enhanced MLS infrastructure.
11*4882a593Smuzhiyun  *	Support for context based audit filters.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *	Added conditional policy language extensions
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * Updated: Hewlett-Packard <paul@paul-moore.com>
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  *      Added support for NetLabel
20*4882a593Smuzhiyun  *      Added support for the policy capability bitmap
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * Updated: Chad Sellers <csellers@tresys.com>
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *  Added validation of kernel classes and permissions
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  *  Added support for bounds domain and audit messaged on masked permissions
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Updated: Guido Trentalancia <guido@trentalancia.com>
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  *  Added support for runtime switching of the policy type
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * Copyright (C) 2008, 2009 NEC Corporation
35*4882a593Smuzhiyun  * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
36*4882a593Smuzhiyun  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
37*4882a593Smuzhiyun  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
38*4882a593Smuzhiyun  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun #include <linux/kernel.h>
41*4882a593Smuzhiyun #include <linux/slab.h>
42*4882a593Smuzhiyun #include <linux/string.h>
43*4882a593Smuzhiyun #include <linux/spinlock.h>
44*4882a593Smuzhiyun #include <linux/rcupdate.h>
45*4882a593Smuzhiyun #include <linux/errno.h>
46*4882a593Smuzhiyun #include <linux/in.h>
47*4882a593Smuzhiyun #include <linux/sched.h>
48*4882a593Smuzhiyun #include <linux/audit.h>
49*4882a593Smuzhiyun #include <linux/vmalloc.h>
50*4882a593Smuzhiyun #include <net/netlabel.h>
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #include "flask.h"
53*4882a593Smuzhiyun #include "avc.h"
54*4882a593Smuzhiyun #include "avc_ss.h"
55*4882a593Smuzhiyun #include "security.h"
56*4882a593Smuzhiyun #include "context.h"
57*4882a593Smuzhiyun #include "policydb.h"
58*4882a593Smuzhiyun #include "sidtab.h"
59*4882a593Smuzhiyun #include "services.h"
60*4882a593Smuzhiyun #include "conditional.h"
61*4882a593Smuzhiyun #include "mls.h"
62*4882a593Smuzhiyun #include "objsec.h"
63*4882a593Smuzhiyun #include "netlabel.h"
64*4882a593Smuzhiyun #include "xfrm.h"
65*4882a593Smuzhiyun #include "ebitmap.h"
66*4882a593Smuzhiyun #include "audit.h"
67*4882a593Smuzhiyun #include "policycap_names.h"
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #include <trace/hooks/selinux.h>
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct convert_context_args {
72*4882a593Smuzhiyun 	struct selinux_state *state;
73*4882a593Smuzhiyun 	struct policydb *oldp;
74*4882a593Smuzhiyun 	struct policydb *newp;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun struct selinux_policy_convert_data {
78*4882a593Smuzhiyun 	struct convert_context_args args;
79*4882a593Smuzhiyun 	struct sidtab_convert_params sidtab_params;
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /* Forward declaration. */
83*4882a593Smuzhiyun static int context_struct_to_string(struct policydb *policydb,
84*4882a593Smuzhiyun 				    struct context *context,
85*4882a593Smuzhiyun 				    char **scontext,
86*4882a593Smuzhiyun 				    u32 *scontext_len);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static int sidtab_entry_to_string(struct policydb *policydb,
89*4882a593Smuzhiyun 				  struct sidtab *sidtab,
90*4882a593Smuzhiyun 				  struct sidtab_entry *entry,
91*4882a593Smuzhiyun 				  char **scontext,
92*4882a593Smuzhiyun 				  u32 *scontext_len);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static void context_struct_compute_av(struct policydb *policydb,
95*4882a593Smuzhiyun 				      struct context *scontext,
96*4882a593Smuzhiyun 				      struct context *tcontext,
97*4882a593Smuzhiyun 				      u16 tclass,
98*4882a593Smuzhiyun 				      struct av_decision *avd,
99*4882a593Smuzhiyun 				      struct extended_perms *xperms);
100*4882a593Smuzhiyun 
selinux_set_mapping(struct policydb * pol,struct security_class_mapping * map,struct selinux_map * out_map)101*4882a593Smuzhiyun static int selinux_set_mapping(struct policydb *pol,
102*4882a593Smuzhiyun 			       struct security_class_mapping *map,
103*4882a593Smuzhiyun 			       struct selinux_map *out_map)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	u16 i, j;
106*4882a593Smuzhiyun 	unsigned k;
107*4882a593Smuzhiyun 	bool print_unknown_handle = false;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* Find number of classes in the input mapping */
110*4882a593Smuzhiyun 	if (!map)
111*4882a593Smuzhiyun 		return -EINVAL;
112*4882a593Smuzhiyun 	i = 0;
113*4882a593Smuzhiyun 	while (map[i].name)
114*4882a593Smuzhiyun 		i++;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/* Allocate space for the class records, plus one for class zero */
117*4882a593Smuzhiyun 	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
118*4882a593Smuzhiyun 	if (!out_map->mapping)
119*4882a593Smuzhiyun 		return -ENOMEM;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* Store the raw class and permission values */
122*4882a593Smuzhiyun 	j = 0;
123*4882a593Smuzhiyun 	while (map[j].name) {
124*4882a593Smuzhiyun 		struct security_class_mapping *p_in = map + (j++);
125*4882a593Smuzhiyun 		struct selinux_mapping *p_out = out_map->mapping + j;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 		/* An empty class string skips ahead */
128*4882a593Smuzhiyun 		if (!strcmp(p_in->name, "")) {
129*4882a593Smuzhiyun 			p_out->num_perms = 0;
130*4882a593Smuzhiyun 			continue;
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 		p_out->value = string_to_security_class(pol, p_in->name);
134*4882a593Smuzhiyun 		if (!p_out->value) {
135*4882a593Smuzhiyun 			pr_info("SELinux:  Class %s not defined in policy.\n",
136*4882a593Smuzhiyun 			       p_in->name);
137*4882a593Smuzhiyun 			if (pol->reject_unknown)
138*4882a593Smuzhiyun 				goto err;
139*4882a593Smuzhiyun 			p_out->num_perms = 0;
140*4882a593Smuzhiyun 			print_unknown_handle = true;
141*4882a593Smuzhiyun 			continue;
142*4882a593Smuzhiyun 		}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		k = 0;
145*4882a593Smuzhiyun 		while (p_in->perms[k]) {
146*4882a593Smuzhiyun 			/* An empty permission string skips ahead */
147*4882a593Smuzhiyun 			if (!*p_in->perms[k]) {
148*4882a593Smuzhiyun 				k++;
149*4882a593Smuzhiyun 				continue;
150*4882a593Smuzhiyun 			}
151*4882a593Smuzhiyun 			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
152*4882a593Smuzhiyun 							    p_in->perms[k]);
153*4882a593Smuzhiyun 			if (!p_out->perms[k]) {
154*4882a593Smuzhiyun 				pr_info("SELinux:  Permission %s in class %s not defined in policy.\n",
155*4882a593Smuzhiyun 				       p_in->perms[k], p_in->name);
156*4882a593Smuzhiyun 				if (pol->reject_unknown)
157*4882a593Smuzhiyun 					goto err;
158*4882a593Smuzhiyun 				print_unknown_handle = true;
159*4882a593Smuzhiyun 			}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 			k++;
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 		p_out->num_perms = k;
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (print_unknown_handle)
167*4882a593Smuzhiyun 		pr_info("SELinux: the above unknown classes and permissions will be %s\n",
168*4882a593Smuzhiyun 		       pol->allow_unknown ? "allowed" : "denied");
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	out_map->size = i;
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun err:
173*4882a593Smuzhiyun 	kfree(out_map->mapping);
174*4882a593Smuzhiyun 	out_map->mapping = NULL;
175*4882a593Smuzhiyun 	return -EINVAL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun  * Get real, policy values from mapped values
180*4882a593Smuzhiyun  */
181*4882a593Smuzhiyun 
unmap_class(struct selinux_map * map,u16 tclass)182*4882a593Smuzhiyun static u16 unmap_class(struct selinux_map *map, u16 tclass)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	if (tclass < map->size)
185*4882a593Smuzhiyun 		return map->mapping[tclass].value;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return tclass;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun  * Get kernel value for class from its policy value
192*4882a593Smuzhiyun  */
map_class(struct selinux_map * map,u16 pol_value)193*4882a593Smuzhiyun static u16 map_class(struct selinux_map *map, u16 pol_value)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	u16 i;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	for (i = 1; i < map->size; i++) {
198*4882a593Smuzhiyun 		if (map->mapping[i].value == pol_value)
199*4882a593Smuzhiyun 			return i;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	return SECCLASS_NULL;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
map_decision(struct selinux_map * map,u16 tclass,struct av_decision * avd,int allow_unknown)205*4882a593Smuzhiyun static void map_decision(struct selinux_map *map,
206*4882a593Smuzhiyun 			 u16 tclass, struct av_decision *avd,
207*4882a593Smuzhiyun 			 int allow_unknown)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	if (tclass < map->size) {
210*4882a593Smuzhiyun 		struct selinux_mapping *mapping = &map->mapping[tclass];
211*4882a593Smuzhiyun 		unsigned int i, n = mapping->num_perms;
212*4882a593Smuzhiyun 		u32 result;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		for (i = 0, result = 0; i < n; i++) {
215*4882a593Smuzhiyun 			if (avd->allowed & mapping->perms[i])
216*4882a593Smuzhiyun 				result |= 1<<i;
217*4882a593Smuzhiyun 			if (allow_unknown && !mapping->perms[i])
218*4882a593Smuzhiyun 				result |= 1<<i;
219*4882a593Smuzhiyun 		}
220*4882a593Smuzhiyun 		avd->allowed = result;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 		for (i = 0, result = 0; i < n; i++)
223*4882a593Smuzhiyun 			if (avd->auditallow & mapping->perms[i])
224*4882a593Smuzhiyun 				result |= 1<<i;
225*4882a593Smuzhiyun 		avd->auditallow = result;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		for (i = 0, result = 0; i < n; i++) {
228*4882a593Smuzhiyun 			if (avd->auditdeny & mapping->perms[i])
229*4882a593Smuzhiyun 				result |= 1<<i;
230*4882a593Smuzhiyun 			if (!allow_unknown && !mapping->perms[i])
231*4882a593Smuzhiyun 				result |= 1<<i;
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 		/*
234*4882a593Smuzhiyun 		 * In case the kernel has a bug and requests a permission
235*4882a593Smuzhiyun 		 * between num_perms and the maximum permission number, we
236*4882a593Smuzhiyun 		 * should audit that denial
237*4882a593Smuzhiyun 		 */
238*4882a593Smuzhiyun 		for (; i < (sizeof(u32)*8); i++)
239*4882a593Smuzhiyun 			result |= 1<<i;
240*4882a593Smuzhiyun 		avd->auditdeny = result;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
security_mls_enabled(struct selinux_state * state)244*4882a593Smuzhiyun int security_mls_enabled(struct selinux_state *state)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	int mls_enabled;
247*4882a593Smuzhiyun 	struct selinux_policy *policy;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (!selinux_initialized(state))
250*4882a593Smuzhiyun 		return 0;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	rcu_read_lock();
253*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
254*4882a593Smuzhiyun 	mls_enabled = policy->policydb.mls_enabled;
255*4882a593Smuzhiyun 	rcu_read_unlock();
256*4882a593Smuzhiyun 	return mls_enabled;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun /*
260*4882a593Smuzhiyun  * Return the boolean value of a constraint expression
261*4882a593Smuzhiyun  * when it is applied to the specified source and target
262*4882a593Smuzhiyun  * security contexts.
263*4882a593Smuzhiyun  *
264*4882a593Smuzhiyun  * xcontext is a special beast...  It is used by the validatetrans rules
265*4882a593Smuzhiyun  * only.  For these rules, scontext is the context before the transition,
266*4882a593Smuzhiyun  * tcontext is the context after the transition, and xcontext is the context
267*4882a593Smuzhiyun  * of the process performing the transition.  All other callers of
268*4882a593Smuzhiyun  * constraint_expr_eval should pass in NULL for xcontext.
269*4882a593Smuzhiyun  */
constraint_expr_eval(struct policydb * policydb,struct context * scontext,struct context * tcontext,struct context * xcontext,struct constraint_expr * cexpr)270*4882a593Smuzhiyun static int constraint_expr_eval(struct policydb *policydb,
271*4882a593Smuzhiyun 				struct context *scontext,
272*4882a593Smuzhiyun 				struct context *tcontext,
273*4882a593Smuzhiyun 				struct context *xcontext,
274*4882a593Smuzhiyun 				struct constraint_expr *cexpr)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	u32 val1, val2;
277*4882a593Smuzhiyun 	struct context *c;
278*4882a593Smuzhiyun 	struct role_datum *r1, *r2;
279*4882a593Smuzhiyun 	struct mls_level *l1, *l2;
280*4882a593Smuzhiyun 	struct constraint_expr *e;
281*4882a593Smuzhiyun 	int s[CEXPR_MAXDEPTH];
282*4882a593Smuzhiyun 	int sp = -1;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	for (e = cexpr; e; e = e->next) {
285*4882a593Smuzhiyun 		switch (e->expr_type) {
286*4882a593Smuzhiyun 		case CEXPR_NOT:
287*4882a593Smuzhiyun 			BUG_ON(sp < 0);
288*4882a593Smuzhiyun 			s[sp] = !s[sp];
289*4882a593Smuzhiyun 			break;
290*4882a593Smuzhiyun 		case CEXPR_AND:
291*4882a593Smuzhiyun 			BUG_ON(sp < 1);
292*4882a593Smuzhiyun 			sp--;
293*4882a593Smuzhiyun 			s[sp] &= s[sp + 1];
294*4882a593Smuzhiyun 			break;
295*4882a593Smuzhiyun 		case CEXPR_OR:
296*4882a593Smuzhiyun 			BUG_ON(sp < 1);
297*4882a593Smuzhiyun 			sp--;
298*4882a593Smuzhiyun 			s[sp] |= s[sp + 1];
299*4882a593Smuzhiyun 			break;
300*4882a593Smuzhiyun 		case CEXPR_ATTR:
301*4882a593Smuzhiyun 			if (sp == (CEXPR_MAXDEPTH - 1))
302*4882a593Smuzhiyun 				return 0;
303*4882a593Smuzhiyun 			switch (e->attr) {
304*4882a593Smuzhiyun 			case CEXPR_USER:
305*4882a593Smuzhiyun 				val1 = scontext->user;
306*4882a593Smuzhiyun 				val2 = tcontext->user;
307*4882a593Smuzhiyun 				break;
308*4882a593Smuzhiyun 			case CEXPR_TYPE:
309*4882a593Smuzhiyun 				val1 = scontext->type;
310*4882a593Smuzhiyun 				val2 = tcontext->type;
311*4882a593Smuzhiyun 				break;
312*4882a593Smuzhiyun 			case CEXPR_ROLE:
313*4882a593Smuzhiyun 				val1 = scontext->role;
314*4882a593Smuzhiyun 				val2 = tcontext->role;
315*4882a593Smuzhiyun 				r1 = policydb->role_val_to_struct[val1 - 1];
316*4882a593Smuzhiyun 				r2 = policydb->role_val_to_struct[val2 - 1];
317*4882a593Smuzhiyun 				switch (e->op) {
318*4882a593Smuzhiyun 				case CEXPR_DOM:
319*4882a593Smuzhiyun 					s[++sp] = ebitmap_get_bit(&r1->dominates,
320*4882a593Smuzhiyun 								  val2 - 1);
321*4882a593Smuzhiyun 					continue;
322*4882a593Smuzhiyun 				case CEXPR_DOMBY:
323*4882a593Smuzhiyun 					s[++sp] = ebitmap_get_bit(&r2->dominates,
324*4882a593Smuzhiyun 								  val1 - 1);
325*4882a593Smuzhiyun 					continue;
326*4882a593Smuzhiyun 				case CEXPR_INCOMP:
327*4882a593Smuzhiyun 					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
328*4882a593Smuzhiyun 								    val2 - 1) &&
329*4882a593Smuzhiyun 						   !ebitmap_get_bit(&r2->dominates,
330*4882a593Smuzhiyun 								    val1 - 1));
331*4882a593Smuzhiyun 					continue;
332*4882a593Smuzhiyun 				default:
333*4882a593Smuzhiyun 					break;
334*4882a593Smuzhiyun 				}
335*4882a593Smuzhiyun 				break;
336*4882a593Smuzhiyun 			case CEXPR_L1L2:
337*4882a593Smuzhiyun 				l1 = &(scontext->range.level[0]);
338*4882a593Smuzhiyun 				l2 = &(tcontext->range.level[0]);
339*4882a593Smuzhiyun 				goto mls_ops;
340*4882a593Smuzhiyun 			case CEXPR_L1H2:
341*4882a593Smuzhiyun 				l1 = &(scontext->range.level[0]);
342*4882a593Smuzhiyun 				l2 = &(tcontext->range.level[1]);
343*4882a593Smuzhiyun 				goto mls_ops;
344*4882a593Smuzhiyun 			case CEXPR_H1L2:
345*4882a593Smuzhiyun 				l1 = &(scontext->range.level[1]);
346*4882a593Smuzhiyun 				l2 = &(tcontext->range.level[0]);
347*4882a593Smuzhiyun 				goto mls_ops;
348*4882a593Smuzhiyun 			case CEXPR_H1H2:
349*4882a593Smuzhiyun 				l1 = &(scontext->range.level[1]);
350*4882a593Smuzhiyun 				l2 = &(tcontext->range.level[1]);
351*4882a593Smuzhiyun 				goto mls_ops;
352*4882a593Smuzhiyun 			case CEXPR_L1H1:
353*4882a593Smuzhiyun 				l1 = &(scontext->range.level[0]);
354*4882a593Smuzhiyun 				l2 = &(scontext->range.level[1]);
355*4882a593Smuzhiyun 				goto mls_ops;
356*4882a593Smuzhiyun 			case CEXPR_L2H2:
357*4882a593Smuzhiyun 				l1 = &(tcontext->range.level[0]);
358*4882a593Smuzhiyun 				l2 = &(tcontext->range.level[1]);
359*4882a593Smuzhiyun 				goto mls_ops;
360*4882a593Smuzhiyun mls_ops:
361*4882a593Smuzhiyun 			switch (e->op) {
362*4882a593Smuzhiyun 			case CEXPR_EQ:
363*4882a593Smuzhiyun 				s[++sp] = mls_level_eq(l1, l2);
364*4882a593Smuzhiyun 				continue;
365*4882a593Smuzhiyun 			case CEXPR_NEQ:
366*4882a593Smuzhiyun 				s[++sp] = !mls_level_eq(l1, l2);
367*4882a593Smuzhiyun 				continue;
368*4882a593Smuzhiyun 			case CEXPR_DOM:
369*4882a593Smuzhiyun 				s[++sp] = mls_level_dom(l1, l2);
370*4882a593Smuzhiyun 				continue;
371*4882a593Smuzhiyun 			case CEXPR_DOMBY:
372*4882a593Smuzhiyun 				s[++sp] = mls_level_dom(l2, l1);
373*4882a593Smuzhiyun 				continue;
374*4882a593Smuzhiyun 			case CEXPR_INCOMP:
375*4882a593Smuzhiyun 				s[++sp] = mls_level_incomp(l2, l1);
376*4882a593Smuzhiyun 				continue;
377*4882a593Smuzhiyun 			default:
378*4882a593Smuzhiyun 				BUG();
379*4882a593Smuzhiyun 				return 0;
380*4882a593Smuzhiyun 			}
381*4882a593Smuzhiyun 			break;
382*4882a593Smuzhiyun 			default:
383*4882a593Smuzhiyun 				BUG();
384*4882a593Smuzhiyun 				return 0;
385*4882a593Smuzhiyun 			}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 			switch (e->op) {
388*4882a593Smuzhiyun 			case CEXPR_EQ:
389*4882a593Smuzhiyun 				s[++sp] = (val1 == val2);
390*4882a593Smuzhiyun 				break;
391*4882a593Smuzhiyun 			case CEXPR_NEQ:
392*4882a593Smuzhiyun 				s[++sp] = (val1 != val2);
393*4882a593Smuzhiyun 				break;
394*4882a593Smuzhiyun 			default:
395*4882a593Smuzhiyun 				BUG();
396*4882a593Smuzhiyun 				return 0;
397*4882a593Smuzhiyun 			}
398*4882a593Smuzhiyun 			break;
399*4882a593Smuzhiyun 		case CEXPR_NAMES:
400*4882a593Smuzhiyun 			if (sp == (CEXPR_MAXDEPTH-1))
401*4882a593Smuzhiyun 				return 0;
402*4882a593Smuzhiyun 			c = scontext;
403*4882a593Smuzhiyun 			if (e->attr & CEXPR_TARGET)
404*4882a593Smuzhiyun 				c = tcontext;
405*4882a593Smuzhiyun 			else if (e->attr & CEXPR_XTARGET) {
406*4882a593Smuzhiyun 				c = xcontext;
407*4882a593Smuzhiyun 				if (!c) {
408*4882a593Smuzhiyun 					BUG();
409*4882a593Smuzhiyun 					return 0;
410*4882a593Smuzhiyun 				}
411*4882a593Smuzhiyun 			}
412*4882a593Smuzhiyun 			if (e->attr & CEXPR_USER)
413*4882a593Smuzhiyun 				val1 = c->user;
414*4882a593Smuzhiyun 			else if (e->attr & CEXPR_ROLE)
415*4882a593Smuzhiyun 				val1 = c->role;
416*4882a593Smuzhiyun 			else if (e->attr & CEXPR_TYPE)
417*4882a593Smuzhiyun 				val1 = c->type;
418*4882a593Smuzhiyun 			else {
419*4882a593Smuzhiyun 				BUG();
420*4882a593Smuzhiyun 				return 0;
421*4882a593Smuzhiyun 			}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 			switch (e->op) {
424*4882a593Smuzhiyun 			case CEXPR_EQ:
425*4882a593Smuzhiyun 				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
426*4882a593Smuzhiyun 				break;
427*4882a593Smuzhiyun 			case CEXPR_NEQ:
428*4882a593Smuzhiyun 				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
429*4882a593Smuzhiyun 				break;
430*4882a593Smuzhiyun 			default:
431*4882a593Smuzhiyun 				BUG();
432*4882a593Smuzhiyun 				return 0;
433*4882a593Smuzhiyun 			}
434*4882a593Smuzhiyun 			break;
435*4882a593Smuzhiyun 		default:
436*4882a593Smuzhiyun 			BUG();
437*4882a593Smuzhiyun 			return 0;
438*4882a593Smuzhiyun 		}
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	BUG_ON(sp != 0);
442*4882a593Smuzhiyun 	return s[0];
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun /*
446*4882a593Smuzhiyun  * security_dump_masked_av - dumps masked permissions during
447*4882a593Smuzhiyun  * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
448*4882a593Smuzhiyun  */
dump_masked_av_helper(void * k,void * d,void * args)449*4882a593Smuzhiyun static int dump_masked_av_helper(void *k, void *d, void *args)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	struct perm_datum *pdatum = d;
452*4882a593Smuzhiyun 	char **permission_names = args;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	BUG_ON(pdatum->value < 1 || pdatum->value > 32);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	permission_names[pdatum->value - 1] = (char *)k;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
security_dump_masked_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,u32 permissions,const char * reason)461*4882a593Smuzhiyun static void security_dump_masked_av(struct policydb *policydb,
462*4882a593Smuzhiyun 				    struct context *scontext,
463*4882a593Smuzhiyun 				    struct context *tcontext,
464*4882a593Smuzhiyun 				    u16 tclass,
465*4882a593Smuzhiyun 				    u32 permissions,
466*4882a593Smuzhiyun 				    const char *reason)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct common_datum *common_dat;
469*4882a593Smuzhiyun 	struct class_datum *tclass_dat;
470*4882a593Smuzhiyun 	struct audit_buffer *ab;
471*4882a593Smuzhiyun 	char *tclass_name;
472*4882a593Smuzhiyun 	char *scontext_name = NULL;
473*4882a593Smuzhiyun 	char *tcontext_name = NULL;
474*4882a593Smuzhiyun 	char *permission_names[32];
475*4882a593Smuzhiyun 	int index;
476*4882a593Smuzhiyun 	u32 length;
477*4882a593Smuzhiyun 	bool need_comma = false;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (!permissions)
480*4882a593Smuzhiyun 		return;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
483*4882a593Smuzhiyun 	tclass_dat = policydb->class_val_to_struct[tclass - 1];
484*4882a593Smuzhiyun 	common_dat = tclass_dat->comdatum;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	/* init permission_names */
487*4882a593Smuzhiyun 	if (common_dat &&
488*4882a593Smuzhiyun 	    hashtab_map(&common_dat->permissions.table,
489*4882a593Smuzhiyun 			dump_masked_av_helper, permission_names) < 0)
490*4882a593Smuzhiyun 		goto out;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (hashtab_map(&tclass_dat->permissions.table,
493*4882a593Smuzhiyun 			dump_masked_av_helper, permission_names) < 0)
494*4882a593Smuzhiyun 		goto out;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* get scontext/tcontext in text form */
497*4882a593Smuzhiyun 	if (context_struct_to_string(policydb, scontext,
498*4882a593Smuzhiyun 				     &scontext_name, &length) < 0)
499*4882a593Smuzhiyun 		goto out;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	if (context_struct_to_string(policydb, tcontext,
502*4882a593Smuzhiyun 				     &tcontext_name, &length) < 0)
503*4882a593Smuzhiyun 		goto out;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	/* audit a message */
506*4882a593Smuzhiyun 	ab = audit_log_start(audit_context(),
507*4882a593Smuzhiyun 			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
508*4882a593Smuzhiyun 	if (!ab)
509*4882a593Smuzhiyun 		goto out;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	audit_log_format(ab, "op=security_compute_av reason=%s "
512*4882a593Smuzhiyun 			 "scontext=%s tcontext=%s tclass=%s perms=",
513*4882a593Smuzhiyun 			 reason, scontext_name, tcontext_name, tclass_name);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	for (index = 0; index < 32; index++) {
516*4882a593Smuzhiyun 		u32 mask = (1 << index);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 		if ((mask & permissions) == 0)
519*4882a593Smuzhiyun 			continue;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 		audit_log_format(ab, "%s%s",
522*4882a593Smuzhiyun 				 need_comma ? "," : "",
523*4882a593Smuzhiyun 				 permission_names[index]
524*4882a593Smuzhiyun 				 ? permission_names[index] : "????");
525*4882a593Smuzhiyun 		need_comma = true;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 	audit_log_end(ab);
528*4882a593Smuzhiyun out:
529*4882a593Smuzhiyun 	/* release scontext/tcontext */
530*4882a593Smuzhiyun 	kfree(tcontext_name);
531*4882a593Smuzhiyun 	kfree(scontext_name);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	return;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun /*
537*4882a593Smuzhiyun  * security_boundary_permission - drops violated permissions
538*4882a593Smuzhiyun  * on boundary constraint.
539*4882a593Smuzhiyun  */
type_attribute_bounds_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd)540*4882a593Smuzhiyun static void type_attribute_bounds_av(struct policydb *policydb,
541*4882a593Smuzhiyun 				     struct context *scontext,
542*4882a593Smuzhiyun 				     struct context *tcontext,
543*4882a593Smuzhiyun 				     u16 tclass,
544*4882a593Smuzhiyun 				     struct av_decision *avd)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	struct context lo_scontext;
547*4882a593Smuzhiyun 	struct context lo_tcontext, *tcontextp = tcontext;
548*4882a593Smuzhiyun 	struct av_decision lo_avd;
549*4882a593Smuzhiyun 	struct type_datum *source;
550*4882a593Smuzhiyun 	struct type_datum *target;
551*4882a593Smuzhiyun 	u32 masked = 0;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	source = policydb->type_val_to_struct[scontext->type - 1];
554*4882a593Smuzhiyun 	BUG_ON(!source);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	if (!source->bounds)
557*4882a593Smuzhiyun 		return;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	target = policydb->type_val_to_struct[tcontext->type - 1];
560*4882a593Smuzhiyun 	BUG_ON(!target);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	memset(&lo_avd, 0, sizeof(lo_avd));
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
565*4882a593Smuzhiyun 	lo_scontext.type = source->bounds;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (target->bounds) {
568*4882a593Smuzhiyun 		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
569*4882a593Smuzhiyun 		lo_tcontext.type = target->bounds;
570*4882a593Smuzhiyun 		tcontextp = &lo_tcontext;
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	context_struct_compute_av(policydb, &lo_scontext,
574*4882a593Smuzhiyun 				  tcontextp,
575*4882a593Smuzhiyun 				  tclass,
576*4882a593Smuzhiyun 				  &lo_avd,
577*4882a593Smuzhiyun 				  NULL);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	masked = ~lo_avd.allowed & avd->allowed;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (likely(!masked))
582*4882a593Smuzhiyun 		return;		/* no masked permission */
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	/* mask violated permissions */
585*4882a593Smuzhiyun 	avd->allowed &= ~masked;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	/* audit masked permissions */
588*4882a593Smuzhiyun 	security_dump_masked_av(policydb, scontext, tcontext,
589*4882a593Smuzhiyun 				tclass, masked, "bounds");
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun /*
593*4882a593Smuzhiyun  * flag which drivers have permissions
594*4882a593Smuzhiyun  * only looking for ioctl based extended permssions
595*4882a593Smuzhiyun  */
services_compute_xperms_drivers(struct extended_perms * xperms,struct avtab_node * node)596*4882a593Smuzhiyun void services_compute_xperms_drivers(
597*4882a593Smuzhiyun 		struct extended_perms *xperms,
598*4882a593Smuzhiyun 		struct avtab_node *node)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	unsigned int i;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
603*4882a593Smuzhiyun 		/* if one or more driver has all permissions allowed */
604*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
605*4882a593Smuzhiyun 			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
606*4882a593Smuzhiyun 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
607*4882a593Smuzhiyun 		/* if allowing permissions within a driver */
608*4882a593Smuzhiyun 		security_xperm_set(xperms->drivers.p,
609*4882a593Smuzhiyun 					node->datum.u.xperms->driver);
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
613*4882a593Smuzhiyun 	if (node->key.specified & AVTAB_XPERMS_ALLOWED)
614*4882a593Smuzhiyun 		xperms->len = 1;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun  * Compute access vectors and extended permissions based on a context
619*4882a593Smuzhiyun  * structure pair for the permissions in a particular class.
620*4882a593Smuzhiyun  */
context_struct_compute_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd,struct extended_perms * xperms)621*4882a593Smuzhiyun static void context_struct_compute_av(struct policydb *policydb,
622*4882a593Smuzhiyun 				      struct context *scontext,
623*4882a593Smuzhiyun 				      struct context *tcontext,
624*4882a593Smuzhiyun 				      u16 tclass,
625*4882a593Smuzhiyun 				      struct av_decision *avd,
626*4882a593Smuzhiyun 				      struct extended_perms *xperms)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct constraint_node *constraint;
629*4882a593Smuzhiyun 	struct role_allow *ra;
630*4882a593Smuzhiyun 	struct avtab_key avkey;
631*4882a593Smuzhiyun 	struct avtab_node *node;
632*4882a593Smuzhiyun 	struct class_datum *tclass_datum;
633*4882a593Smuzhiyun 	struct ebitmap *sattr, *tattr;
634*4882a593Smuzhiyun 	struct ebitmap_node *snode, *tnode;
635*4882a593Smuzhiyun 	unsigned int i, j;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	avd->allowed = 0;
638*4882a593Smuzhiyun 	avd->auditallow = 0;
639*4882a593Smuzhiyun 	avd->auditdeny = 0xffffffff;
640*4882a593Smuzhiyun 	if (xperms) {
641*4882a593Smuzhiyun 		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
642*4882a593Smuzhiyun 		xperms->len = 0;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
646*4882a593Smuzhiyun 		if (printk_ratelimit())
647*4882a593Smuzhiyun 			pr_warn("SELinux:  Invalid class %hu\n", tclass);
648*4882a593Smuzhiyun 		return;
649*4882a593Smuzhiyun 	}
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	/*
654*4882a593Smuzhiyun 	 * If a specific type enforcement rule was defined for
655*4882a593Smuzhiyun 	 * this permission check, then use it.
656*4882a593Smuzhiyun 	 */
657*4882a593Smuzhiyun 	avkey.target_class = tclass;
658*4882a593Smuzhiyun 	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
659*4882a593Smuzhiyun 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
660*4882a593Smuzhiyun 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
661*4882a593Smuzhiyun 	ebitmap_for_each_positive_bit(sattr, snode, i) {
662*4882a593Smuzhiyun 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
663*4882a593Smuzhiyun 			avkey.source_type = i + 1;
664*4882a593Smuzhiyun 			avkey.target_type = j + 1;
665*4882a593Smuzhiyun 			for (node = avtab_search_node(&policydb->te_avtab,
666*4882a593Smuzhiyun 						      &avkey);
667*4882a593Smuzhiyun 			     node;
668*4882a593Smuzhiyun 			     node = avtab_search_node_next(node, avkey.specified)) {
669*4882a593Smuzhiyun 				if (node->key.specified == AVTAB_ALLOWED)
670*4882a593Smuzhiyun 					avd->allowed |= node->datum.u.data;
671*4882a593Smuzhiyun 				else if (node->key.specified == AVTAB_AUDITALLOW)
672*4882a593Smuzhiyun 					avd->auditallow |= node->datum.u.data;
673*4882a593Smuzhiyun 				else if (node->key.specified == AVTAB_AUDITDENY)
674*4882a593Smuzhiyun 					avd->auditdeny &= node->datum.u.data;
675*4882a593Smuzhiyun 				else if (xperms && (node->key.specified & AVTAB_XPERMS))
676*4882a593Smuzhiyun 					services_compute_xperms_drivers(xperms, node);
677*4882a593Smuzhiyun 			}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 			/* Check conditional av table for additional permissions */
680*4882a593Smuzhiyun 			cond_compute_av(&policydb->te_cond_avtab, &avkey,
681*4882a593Smuzhiyun 					avd, xperms);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 		}
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	/*
687*4882a593Smuzhiyun 	 * Remove any permissions prohibited by a constraint (this includes
688*4882a593Smuzhiyun 	 * the MLS policy).
689*4882a593Smuzhiyun 	 */
690*4882a593Smuzhiyun 	constraint = tclass_datum->constraints;
691*4882a593Smuzhiyun 	while (constraint) {
692*4882a593Smuzhiyun 		if ((constraint->permissions & (avd->allowed)) &&
693*4882a593Smuzhiyun 		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
694*4882a593Smuzhiyun 					  constraint->expr)) {
695*4882a593Smuzhiyun 			avd->allowed &= ~(constraint->permissions);
696*4882a593Smuzhiyun 		}
697*4882a593Smuzhiyun 		constraint = constraint->next;
698*4882a593Smuzhiyun 	}
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	/*
701*4882a593Smuzhiyun 	 * If checking process transition permission and the
702*4882a593Smuzhiyun 	 * role is changing, then check the (current_role, new_role)
703*4882a593Smuzhiyun 	 * pair.
704*4882a593Smuzhiyun 	 */
705*4882a593Smuzhiyun 	if (tclass == policydb->process_class &&
706*4882a593Smuzhiyun 	    (avd->allowed & policydb->process_trans_perms) &&
707*4882a593Smuzhiyun 	    scontext->role != tcontext->role) {
708*4882a593Smuzhiyun 		for (ra = policydb->role_allow; ra; ra = ra->next) {
709*4882a593Smuzhiyun 			if (scontext->role == ra->role &&
710*4882a593Smuzhiyun 			    tcontext->role == ra->new_role)
711*4882a593Smuzhiyun 				break;
712*4882a593Smuzhiyun 		}
713*4882a593Smuzhiyun 		if (!ra)
714*4882a593Smuzhiyun 			avd->allowed &= ~policydb->process_trans_perms;
715*4882a593Smuzhiyun 	}
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	/*
718*4882a593Smuzhiyun 	 * If the given source and target types have boundary
719*4882a593Smuzhiyun 	 * constraint, lazy checks have to mask any violated
720*4882a593Smuzhiyun 	 * permission and notice it to userspace via audit.
721*4882a593Smuzhiyun 	 */
722*4882a593Smuzhiyun 	type_attribute_bounds_av(policydb, scontext, tcontext,
723*4882a593Smuzhiyun 				 tclass, avd);
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
security_validtrans_handle_fail(struct selinux_state * state,struct selinux_policy * policy,struct sidtab_entry * oentry,struct sidtab_entry * nentry,struct sidtab_entry * tentry,u16 tclass)726*4882a593Smuzhiyun static int security_validtrans_handle_fail(struct selinux_state *state,
727*4882a593Smuzhiyun 					struct selinux_policy *policy,
728*4882a593Smuzhiyun 					struct sidtab_entry *oentry,
729*4882a593Smuzhiyun 					struct sidtab_entry *nentry,
730*4882a593Smuzhiyun 					struct sidtab_entry *tentry,
731*4882a593Smuzhiyun 					u16 tclass)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun 	struct policydb *p = &policy->policydb;
734*4882a593Smuzhiyun 	struct sidtab *sidtab = policy->sidtab;
735*4882a593Smuzhiyun 	char *o = NULL, *n = NULL, *t = NULL;
736*4882a593Smuzhiyun 	u32 olen, nlen, tlen;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen))
739*4882a593Smuzhiyun 		goto out;
740*4882a593Smuzhiyun 	if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen))
741*4882a593Smuzhiyun 		goto out;
742*4882a593Smuzhiyun 	if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen))
743*4882a593Smuzhiyun 		goto out;
744*4882a593Smuzhiyun 	audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
745*4882a593Smuzhiyun 		  "op=security_validate_transition seresult=denied"
746*4882a593Smuzhiyun 		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
747*4882a593Smuzhiyun 		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
748*4882a593Smuzhiyun out:
749*4882a593Smuzhiyun 	kfree(o);
750*4882a593Smuzhiyun 	kfree(n);
751*4882a593Smuzhiyun 	kfree(t);
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	if (!enforcing_enabled(state))
754*4882a593Smuzhiyun 		return 0;
755*4882a593Smuzhiyun 	return -EPERM;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun 
security_compute_validatetrans(struct selinux_state * state,u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass,bool user)758*4882a593Smuzhiyun static int security_compute_validatetrans(struct selinux_state *state,
759*4882a593Smuzhiyun 					  u32 oldsid, u32 newsid, u32 tasksid,
760*4882a593Smuzhiyun 					  u16 orig_tclass, bool user)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	struct selinux_policy *policy;
763*4882a593Smuzhiyun 	struct policydb *policydb;
764*4882a593Smuzhiyun 	struct sidtab *sidtab;
765*4882a593Smuzhiyun 	struct sidtab_entry *oentry;
766*4882a593Smuzhiyun 	struct sidtab_entry *nentry;
767*4882a593Smuzhiyun 	struct sidtab_entry *tentry;
768*4882a593Smuzhiyun 	struct class_datum *tclass_datum;
769*4882a593Smuzhiyun 	struct constraint_node *constraint;
770*4882a593Smuzhiyun 	u16 tclass;
771*4882a593Smuzhiyun 	int rc = 0;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	if (!selinux_initialized(state))
775*4882a593Smuzhiyun 		return 0;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	rcu_read_lock();
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
780*4882a593Smuzhiyun 	policydb = &policy->policydb;
781*4882a593Smuzhiyun 	sidtab = policy->sidtab;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	if (!user)
784*4882a593Smuzhiyun 		tclass = unmap_class(&policy->map, orig_tclass);
785*4882a593Smuzhiyun 	else
786*4882a593Smuzhiyun 		tclass = orig_tclass;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	if (!tclass || tclass > policydb->p_classes.nprim) {
789*4882a593Smuzhiyun 		rc = -EINVAL;
790*4882a593Smuzhiyun 		goto out;
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 	tclass_datum = policydb->class_val_to_struct[tclass - 1];
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	oentry = sidtab_search_entry(sidtab, oldsid);
795*4882a593Smuzhiyun 	if (!oentry) {
796*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
797*4882a593Smuzhiyun 			__func__, oldsid);
798*4882a593Smuzhiyun 		rc = -EINVAL;
799*4882a593Smuzhiyun 		goto out;
800*4882a593Smuzhiyun 	}
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	nentry = sidtab_search_entry(sidtab, newsid);
803*4882a593Smuzhiyun 	if (!nentry) {
804*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
805*4882a593Smuzhiyun 			__func__, newsid);
806*4882a593Smuzhiyun 		rc = -EINVAL;
807*4882a593Smuzhiyun 		goto out;
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	tentry = sidtab_search_entry(sidtab, tasksid);
811*4882a593Smuzhiyun 	if (!tentry) {
812*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
813*4882a593Smuzhiyun 			__func__, tasksid);
814*4882a593Smuzhiyun 		rc = -EINVAL;
815*4882a593Smuzhiyun 		goto out;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	constraint = tclass_datum->validatetrans;
819*4882a593Smuzhiyun 	while (constraint) {
820*4882a593Smuzhiyun 		if (!constraint_expr_eval(policydb, &oentry->context,
821*4882a593Smuzhiyun 					  &nentry->context, &tentry->context,
822*4882a593Smuzhiyun 					  constraint->expr)) {
823*4882a593Smuzhiyun 			if (user)
824*4882a593Smuzhiyun 				rc = -EPERM;
825*4882a593Smuzhiyun 			else
826*4882a593Smuzhiyun 				rc = security_validtrans_handle_fail(state,
827*4882a593Smuzhiyun 								policy,
828*4882a593Smuzhiyun 								oentry,
829*4882a593Smuzhiyun 								nentry,
830*4882a593Smuzhiyun 								tentry,
831*4882a593Smuzhiyun 								tclass);
832*4882a593Smuzhiyun 			goto out;
833*4882a593Smuzhiyun 		}
834*4882a593Smuzhiyun 		constraint = constraint->next;
835*4882a593Smuzhiyun 	}
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun out:
838*4882a593Smuzhiyun 	rcu_read_unlock();
839*4882a593Smuzhiyun 	return rc;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
security_validate_transition_user(struct selinux_state * state,u32 oldsid,u32 newsid,u32 tasksid,u16 tclass)842*4882a593Smuzhiyun int security_validate_transition_user(struct selinux_state *state,
843*4882a593Smuzhiyun 				      u32 oldsid, u32 newsid, u32 tasksid,
844*4882a593Smuzhiyun 				      u16 tclass)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun 	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
847*4882a593Smuzhiyun 					      tclass, true);
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun 
security_validate_transition(struct selinux_state * state,u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass)850*4882a593Smuzhiyun int security_validate_transition(struct selinux_state *state,
851*4882a593Smuzhiyun 				 u32 oldsid, u32 newsid, u32 tasksid,
852*4882a593Smuzhiyun 				 u16 orig_tclass)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun 	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
855*4882a593Smuzhiyun 					      orig_tclass, false);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun /*
859*4882a593Smuzhiyun  * security_bounded_transition - check whether the given
860*4882a593Smuzhiyun  * transition is directed to bounded, or not.
861*4882a593Smuzhiyun  * It returns 0, if @newsid is bounded by @oldsid.
862*4882a593Smuzhiyun  * Otherwise, it returns error code.
863*4882a593Smuzhiyun  *
864*4882a593Smuzhiyun  * @oldsid : current security identifier
865*4882a593Smuzhiyun  * @newsid : destinated security identifier
866*4882a593Smuzhiyun  */
security_bounded_transition(struct selinux_state * state,u32 old_sid,u32 new_sid)867*4882a593Smuzhiyun int security_bounded_transition(struct selinux_state *state,
868*4882a593Smuzhiyun 				u32 old_sid, u32 new_sid)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun 	struct selinux_policy *policy;
871*4882a593Smuzhiyun 	struct policydb *policydb;
872*4882a593Smuzhiyun 	struct sidtab *sidtab;
873*4882a593Smuzhiyun 	struct sidtab_entry *old_entry, *new_entry;
874*4882a593Smuzhiyun 	struct type_datum *type;
875*4882a593Smuzhiyun 	int index;
876*4882a593Smuzhiyun 	int rc;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	if (!selinux_initialized(state))
879*4882a593Smuzhiyun 		return 0;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	rcu_read_lock();
882*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
883*4882a593Smuzhiyun 	policydb = &policy->policydb;
884*4882a593Smuzhiyun 	sidtab = policy->sidtab;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	rc = -EINVAL;
887*4882a593Smuzhiyun 	old_entry = sidtab_search_entry(sidtab, old_sid);
888*4882a593Smuzhiyun 	if (!old_entry) {
889*4882a593Smuzhiyun 		pr_err("SELinux: %s: unrecognized SID %u\n",
890*4882a593Smuzhiyun 		       __func__, old_sid);
891*4882a593Smuzhiyun 		goto out;
892*4882a593Smuzhiyun 	}
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	rc = -EINVAL;
895*4882a593Smuzhiyun 	new_entry = sidtab_search_entry(sidtab, new_sid);
896*4882a593Smuzhiyun 	if (!new_entry) {
897*4882a593Smuzhiyun 		pr_err("SELinux: %s: unrecognized SID %u\n",
898*4882a593Smuzhiyun 		       __func__, new_sid);
899*4882a593Smuzhiyun 		goto out;
900*4882a593Smuzhiyun 	}
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	rc = 0;
903*4882a593Smuzhiyun 	/* type/domain unchanged */
904*4882a593Smuzhiyun 	if (old_entry->context.type == new_entry->context.type)
905*4882a593Smuzhiyun 		goto out;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	index = new_entry->context.type;
908*4882a593Smuzhiyun 	while (true) {
909*4882a593Smuzhiyun 		type = policydb->type_val_to_struct[index - 1];
910*4882a593Smuzhiyun 		BUG_ON(!type);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 		/* not bounded anymore */
913*4882a593Smuzhiyun 		rc = -EPERM;
914*4882a593Smuzhiyun 		if (!type->bounds)
915*4882a593Smuzhiyun 			break;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 		/* @newsid is bounded by @oldsid */
918*4882a593Smuzhiyun 		rc = 0;
919*4882a593Smuzhiyun 		if (type->bounds == old_entry->context.type)
920*4882a593Smuzhiyun 			break;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 		index = type->bounds;
923*4882a593Smuzhiyun 	}
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	if (rc) {
926*4882a593Smuzhiyun 		char *old_name = NULL;
927*4882a593Smuzhiyun 		char *new_name = NULL;
928*4882a593Smuzhiyun 		u32 length;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 		if (!sidtab_entry_to_string(policydb, sidtab, old_entry,
931*4882a593Smuzhiyun 					    &old_name, &length) &&
932*4882a593Smuzhiyun 		    !sidtab_entry_to_string(policydb, sidtab, new_entry,
933*4882a593Smuzhiyun 					    &new_name, &length)) {
934*4882a593Smuzhiyun 			audit_log(audit_context(),
935*4882a593Smuzhiyun 				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
936*4882a593Smuzhiyun 				  "op=security_bounded_transition "
937*4882a593Smuzhiyun 				  "seresult=denied "
938*4882a593Smuzhiyun 				  "oldcontext=%s newcontext=%s",
939*4882a593Smuzhiyun 				  old_name, new_name);
940*4882a593Smuzhiyun 		}
941*4882a593Smuzhiyun 		kfree(new_name);
942*4882a593Smuzhiyun 		kfree(old_name);
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun out:
945*4882a593Smuzhiyun 	rcu_read_unlock();
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	return rc;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
avd_init(struct selinux_policy * policy,struct av_decision * avd)950*4882a593Smuzhiyun static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	avd->allowed = 0;
953*4882a593Smuzhiyun 	avd->auditallow = 0;
954*4882a593Smuzhiyun 	avd->auditdeny = 0xffffffff;
955*4882a593Smuzhiyun 	if (policy)
956*4882a593Smuzhiyun 		avd->seqno = policy->latest_granting;
957*4882a593Smuzhiyun 	else
958*4882a593Smuzhiyun 		avd->seqno = 0;
959*4882a593Smuzhiyun 	avd->flags = 0;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun 
services_compute_xperms_decision(struct extended_perms_decision * xpermd,struct avtab_node * node)962*4882a593Smuzhiyun void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
963*4882a593Smuzhiyun 					struct avtab_node *node)
964*4882a593Smuzhiyun {
965*4882a593Smuzhiyun 	unsigned int i;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
968*4882a593Smuzhiyun 		if (xpermd->driver != node->datum.u.xperms->driver)
969*4882a593Smuzhiyun 			return;
970*4882a593Smuzhiyun 	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
971*4882a593Smuzhiyun 		if (!security_xperm_test(node->datum.u.xperms->perms.p,
972*4882a593Smuzhiyun 					xpermd->driver))
973*4882a593Smuzhiyun 			return;
974*4882a593Smuzhiyun 	} else {
975*4882a593Smuzhiyun 		BUG();
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
979*4882a593Smuzhiyun 		xpermd->used |= XPERMS_ALLOWED;
980*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
981*4882a593Smuzhiyun 			memset(xpermd->allowed->p, 0xff,
982*4882a593Smuzhiyun 					sizeof(xpermd->allowed->p));
983*4882a593Smuzhiyun 		}
984*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
985*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
986*4882a593Smuzhiyun 				xpermd->allowed->p[i] |=
987*4882a593Smuzhiyun 					node->datum.u.xperms->perms.p[i];
988*4882a593Smuzhiyun 		}
989*4882a593Smuzhiyun 	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
990*4882a593Smuzhiyun 		xpermd->used |= XPERMS_AUDITALLOW;
991*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
992*4882a593Smuzhiyun 			memset(xpermd->auditallow->p, 0xff,
993*4882a593Smuzhiyun 					sizeof(xpermd->auditallow->p));
994*4882a593Smuzhiyun 		}
995*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
996*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
997*4882a593Smuzhiyun 				xpermd->auditallow->p[i] |=
998*4882a593Smuzhiyun 					node->datum.u.xperms->perms.p[i];
999*4882a593Smuzhiyun 		}
1000*4882a593Smuzhiyun 	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
1001*4882a593Smuzhiyun 		xpermd->used |= XPERMS_DONTAUDIT;
1002*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
1003*4882a593Smuzhiyun 			memset(xpermd->dontaudit->p, 0xff,
1004*4882a593Smuzhiyun 					sizeof(xpermd->dontaudit->p));
1005*4882a593Smuzhiyun 		}
1006*4882a593Smuzhiyun 		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
1007*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
1008*4882a593Smuzhiyun 				xpermd->dontaudit->p[i] |=
1009*4882a593Smuzhiyun 					node->datum.u.xperms->perms.p[i];
1010*4882a593Smuzhiyun 		}
1011*4882a593Smuzhiyun 	} else {
1012*4882a593Smuzhiyun 		BUG();
1013*4882a593Smuzhiyun 	}
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun 
security_compute_xperms_decision(struct selinux_state * state,u32 ssid,u32 tsid,u16 orig_tclass,u8 driver,struct extended_perms_decision * xpermd)1016*4882a593Smuzhiyun void security_compute_xperms_decision(struct selinux_state *state,
1017*4882a593Smuzhiyun 				      u32 ssid,
1018*4882a593Smuzhiyun 				      u32 tsid,
1019*4882a593Smuzhiyun 				      u16 orig_tclass,
1020*4882a593Smuzhiyun 				      u8 driver,
1021*4882a593Smuzhiyun 				      struct extended_perms_decision *xpermd)
1022*4882a593Smuzhiyun {
1023*4882a593Smuzhiyun 	struct selinux_policy *policy;
1024*4882a593Smuzhiyun 	struct policydb *policydb;
1025*4882a593Smuzhiyun 	struct sidtab *sidtab;
1026*4882a593Smuzhiyun 	u16 tclass;
1027*4882a593Smuzhiyun 	struct context *scontext, *tcontext;
1028*4882a593Smuzhiyun 	struct avtab_key avkey;
1029*4882a593Smuzhiyun 	struct avtab_node *node;
1030*4882a593Smuzhiyun 	struct ebitmap *sattr, *tattr;
1031*4882a593Smuzhiyun 	struct ebitmap_node *snode, *tnode;
1032*4882a593Smuzhiyun 	unsigned int i, j;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	xpermd->driver = driver;
1035*4882a593Smuzhiyun 	xpermd->used = 0;
1036*4882a593Smuzhiyun 	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1037*4882a593Smuzhiyun 	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1038*4882a593Smuzhiyun 	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	rcu_read_lock();
1041*4882a593Smuzhiyun 	if (!selinux_initialized(state))
1042*4882a593Smuzhiyun 		goto allow;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1045*4882a593Smuzhiyun 	policydb = &policy->policydb;
1046*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	scontext = sidtab_search(sidtab, ssid);
1049*4882a593Smuzhiyun 	if (!scontext) {
1050*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1051*4882a593Smuzhiyun 		       __func__, ssid);
1052*4882a593Smuzhiyun 		goto out;
1053*4882a593Smuzhiyun 	}
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	tcontext = sidtab_search(sidtab, tsid);
1056*4882a593Smuzhiyun 	if (!tcontext) {
1057*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1058*4882a593Smuzhiyun 		       __func__, tsid);
1059*4882a593Smuzhiyun 		goto out;
1060*4882a593Smuzhiyun 	}
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	tclass = unmap_class(&policy->map, orig_tclass);
1063*4882a593Smuzhiyun 	if (unlikely(orig_tclass && !tclass)) {
1064*4882a593Smuzhiyun 		if (policydb->allow_unknown)
1065*4882a593Smuzhiyun 			goto allow;
1066*4882a593Smuzhiyun 		goto out;
1067*4882a593Smuzhiyun 	}
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1071*4882a593Smuzhiyun 		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
1072*4882a593Smuzhiyun 		goto out;
1073*4882a593Smuzhiyun 	}
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	avkey.target_class = tclass;
1076*4882a593Smuzhiyun 	avkey.specified = AVTAB_XPERMS;
1077*4882a593Smuzhiyun 	sattr = &policydb->type_attr_map_array[scontext->type - 1];
1078*4882a593Smuzhiyun 	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1079*4882a593Smuzhiyun 	ebitmap_for_each_positive_bit(sattr, snode, i) {
1080*4882a593Smuzhiyun 		ebitmap_for_each_positive_bit(tattr, tnode, j) {
1081*4882a593Smuzhiyun 			avkey.source_type = i + 1;
1082*4882a593Smuzhiyun 			avkey.target_type = j + 1;
1083*4882a593Smuzhiyun 			for (node = avtab_search_node(&policydb->te_avtab,
1084*4882a593Smuzhiyun 						      &avkey);
1085*4882a593Smuzhiyun 			     node;
1086*4882a593Smuzhiyun 			     node = avtab_search_node_next(node, avkey.specified))
1087*4882a593Smuzhiyun 				services_compute_xperms_decision(xpermd, node);
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 			cond_compute_xperms(&policydb->te_cond_avtab,
1090*4882a593Smuzhiyun 						&avkey, xpermd);
1091*4882a593Smuzhiyun 		}
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun out:
1094*4882a593Smuzhiyun 	rcu_read_unlock();
1095*4882a593Smuzhiyun 	return;
1096*4882a593Smuzhiyun allow:
1097*4882a593Smuzhiyun 	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1098*4882a593Smuzhiyun 	goto out;
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun /**
1102*4882a593Smuzhiyun  * security_compute_av - Compute access vector decisions.
1103*4882a593Smuzhiyun  * @ssid: source security identifier
1104*4882a593Smuzhiyun  * @tsid: target security identifier
1105*4882a593Smuzhiyun  * @tclass: target security class
1106*4882a593Smuzhiyun  * @avd: access vector decisions
1107*4882a593Smuzhiyun  * @xperms: extended permissions
1108*4882a593Smuzhiyun  *
1109*4882a593Smuzhiyun  * Compute a set of access vector decisions based on the
1110*4882a593Smuzhiyun  * SID pair (@ssid, @tsid) for the permissions in @tclass.
1111*4882a593Smuzhiyun  */
security_compute_av(struct selinux_state * state,u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision * avd,struct extended_perms * xperms)1112*4882a593Smuzhiyun void security_compute_av(struct selinux_state *state,
1113*4882a593Smuzhiyun 			 u32 ssid,
1114*4882a593Smuzhiyun 			 u32 tsid,
1115*4882a593Smuzhiyun 			 u16 orig_tclass,
1116*4882a593Smuzhiyun 			 struct av_decision *avd,
1117*4882a593Smuzhiyun 			 struct extended_perms *xperms)
1118*4882a593Smuzhiyun {
1119*4882a593Smuzhiyun 	struct selinux_policy *policy;
1120*4882a593Smuzhiyun 	struct policydb *policydb;
1121*4882a593Smuzhiyun 	struct sidtab *sidtab;
1122*4882a593Smuzhiyun 	u16 tclass;
1123*4882a593Smuzhiyun 	struct context *scontext = NULL, *tcontext = NULL;
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	rcu_read_lock();
1126*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1127*4882a593Smuzhiyun 	avd_init(policy, avd);
1128*4882a593Smuzhiyun 	xperms->len = 0;
1129*4882a593Smuzhiyun 	if (!selinux_initialized(state))
1130*4882a593Smuzhiyun 		goto allow;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	policydb = &policy->policydb;
1133*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	scontext = sidtab_search(sidtab, ssid);
1136*4882a593Smuzhiyun 	if (!scontext) {
1137*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1138*4882a593Smuzhiyun 		       __func__, ssid);
1139*4882a593Smuzhiyun 		goto out;
1140*4882a593Smuzhiyun 	}
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	/* permissive domain? */
1143*4882a593Smuzhiyun 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
1144*4882a593Smuzhiyun 		avd->flags |= AVD_FLAGS_PERMISSIVE;
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	tcontext = sidtab_search(sidtab, tsid);
1147*4882a593Smuzhiyun 	if (!tcontext) {
1148*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1149*4882a593Smuzhiyun 		       __func__, tsid);
1150*4882a593Smuzhiyun 		goto out;
1151*4882a593Smuzhiyun 	}
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	tclass = unmap_class(&policy->map, orig_tclass);
1154*4882a593Smuzhiyun 	if (unlikely(orig_tclass && !tclass)) {
1155*4882a593Smuzhiyun 		if (policydb->allow_unknown)
1156*4882a593Smuzhiyun 			goto allow;
1157*4882a593Smuzhiyun 		goto out;
1158*4882a593Smuzhiyun 	}
1159*4882a593Smuzhiyun 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1160*4882a593Smuzhiyun 				  xperms);
1161*4882a593Smuzhiyun 	map_decision(&policy->map, orig_tclass, avd,
1162*4882a593Smuzhiyun 		     policydb->allow_unknown);
1163*4882a593Smuzhiyun out:
1164*4882a593Smuzhiyun 	rcu_read_unlock();
1165*4882a593Smuzhiyun 	return;
1166*4882a593Smuzhiyun allow:
1167*4882a593Smuzhiyun 	avd->allowed = 0xffffffff;
1168*4882a593Smuzhiyun 	goto out;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun 
security_compute_av_user(struct selinux_state * state,u32 ssid,u32 tsid,u16 tclass,struct av_decision * avd)1171*4882a593Smuzhiyun void security_compute_av_user(struct selinux_state *state,
1172*4882a593Smuzhiyun 			      u32 ssid,
1173*4882a593Smuzhiyun 			      u32 tsid,
1174*4882a593Smuzhiyun 			      u16 tclass,
1175*4882a593Smuzhiyun 			      struct av_decision *avd)
1176*4882a593Smuzhiyun {
1177*4882a593Smuzhiyun 	struct selinux_policy *policy;
1178*4882a593Smuzhiyun 	struct policydb *policydb;
1179*4882a593Smuzhiyun 	struct sidtab *sidtab;
1180*4882a593Smuzhiyun 	struct context *scontext = NULL, *tcontext = NULL;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	rcu_read_lock();
1183*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1184*4882a593Smuzhiyun 	avd_init(policy, avd);
1185*4882a593Smuzhiyun 	if (!selinux_initialized(state))
1186*4882a593Smuzhiyun 		goto allow;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	policydb = &policy->policydb;
1189*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	scontext = sidtab_search(sidtab, ssid);
1192*4882a593Smuzhiyun 	if (!scontext) {
1193*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1194*4882a593Smuzhiyun 		       __func__, ssid);
1195*4882a593Smuzhiyun 		goto out;
1196*4882a593Smuzhiyun 	}
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	/* permissive domain? */
1199*4882a593Smuzhiyun 	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
1200*4882a593Smuzhiyun 		avd->flags |= AVD_FLAGS_PERMISSIVE;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	tcontext = sidtab_search(sidtab, tsid);
1203*4882a593Smuzhiyun 	if (!tcontext) {
1204*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1205*4882a593Smuzhiyun 		       __func__, tsid);
1206*4882a593Smuzhiyun 		goto out;
1207*4882a593Smuzhiyun 	}
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	if (unlikely(!tclass)) {
1210*4882a593Smuzhiyun 		if (policydb->allow_unknown)
1211*4882a593Smuzhiyun 			goto allow;
1212*4882a593Smuzhiyun 		goto out;
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1216*4882a593Smuzhiyun 				  NULL);
1217*4882a593Smuzhiyun  out:
1218*4882a593Smuzhiyun 	rcu_read_unlock();
1219*4882a593Smuzhiyun 	return;
1220*4882a593Smuzhiyun allow:
1221*4882a593Smuzhiyun 	avd->allowed = 0xffffffff;
1222*4882a593Smuzhiyun 	goto out;
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun /*
1226*4882a593Smuzhiyun  * Write the security context string representation of
1227*4882a593Smuzhiyun  * the context structure `context' into a dynamically
1228*4882a593Smuzhiyun  * allocated string of the correct size.  Set `*scontext'
1229*4882a593Smuzhiyun  * to point to this string and set `*scontext_len' to
1230*4882a593Smuzhiyun  * the length of the string.
1231*4882a593Smuzhiyun  */
context_struct_to_string(struct policydb * p,struct context * context,char ** scontext,u32 * scontext_len)1232*4882a593Smuzhiyun static int context_struct_to_string(struct policydb *p,
1233*4882a593Smuzhiyun 				    struct context *context,
1234*4882a593Smuzhiyun 				    char **scontext, u32 *scontext_len)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	char *scontextp;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	if (scontext)
1239*4882a593Smuzhiyun 		*scontext = NULL;
1240*4882a593Smuzhiyun 	*scontext_len = 0;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	if (context->len) {
1243*4882a593Smuzhiyun 		*scontext_len = context->len;
1244*4882a593Smuzhiyun 		if (scontext) {
1245*4882a593Smuzhiyun 			*scontext = kstrdup(context->str, GFP_ATOMIC);
1246*4882a593Smuzhiyun 			if (!(*scontext))
1247*4882a593Smuzhiyun 				return -ENOMEM;
1248*4882a593Smuzhiyun 		}
1249*4882a593Smuzhiyun 		return 0;
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	/* Compute the size of the context. */
1253*4882a593Smuzhiyun 	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1254*4882a593Smuzhiyun 	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1255*4882a593Smuzhiyun 	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1256*4882a593Smuzhiyun 	*scontext_len += mls_compute_context_len(p, context);
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	if (!scontext)
1259*4882a593Smuzhiyun 		return 0;
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 	/* Allocate space for the context; caller must free this space. */
1262*4882a593Smuzhiyun 	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
1263*4882a593Smuzhiyun 	if (!scontextp)
1264*4882a593Smuzhiyun 		return -ENOMEM;
1265*4882a593Smuzhiyun 	*scontext = scontextp;
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	/*
1268*4882a593Smuzhiyun 	 * Copy the user name, role name and type name into the context.
1269*4882a593Smuzhiyun 	 */
1270*4882a593Smuzhiyun 	scontextp += sprintf(scontextp, "%s:%s:%s",
1271*4882a593Smuzhiyun 		sym_name(p, SYM_USERS, context->user - 1),
1272*4882a593Smuzhiyun 		sym_name(p, SYM_ROLES, context->role - 1),
1273*4882a593Smuzhiyun 		sym_name(p, SYM_TYPES, context->type - 1));
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	mls_sid_to_context(p, context, &scontextp);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	*scontextp = 0;
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	return 0;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun 
sidtab_entry_to_string(struct policydb * p,struct sidtab * sidtab,struct sidtab_entry * entry,char ** scontext,u32 * scontext_len)1282*4882a593Smuzhiyun static int sidtab_entry_to_string(struct policydb *p,
1283*4882a593Smuzhiyun 				  struct sidtab *sidtab,
1284*4882a593Smuzhiyun 				  struct sidtab_entry *entry,
1285*4882a593Smuzhiyun 				  char **scontext, u32 *scontext_len)
1286*4882a593Smuzhiyun {
1287*4882a593Smuzhiyun 	int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	if (rc != -ENOENT)
1290*4882a593Smuzhiyun 		return rc;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	rc = context_struct_to_string(p, &entry->context, scontext,
1293*4882a593Smuzhiyun 				      scontext_len);
1294*4882a593Smuzhiyun 	if (!rc && scontext)
1295*4882a593Smuzhiyun 		sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
1296*4882a593Smuzhiyun 	return rc;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun #include "initial_sid_to_string.h"
1300*4882a593Smuzhiyun 
security_sidtab_hash_stats(struct selinux_state * state,char * page)1301*4882a593Smuzhiyun int security_sidtab_hash_stats(struct selinux_state *state, char *page)
1302*4882a593Smuzhiyun {
1303*4882a593Smuzhiyun 	struct selinux_policy *policy;
1304*4882a593Smuzhiyun 	int rc;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
1307*4882a593Smuzhiyun 		pr_err("SELinux: %s:  called before initial load_policy\n",
1308*4882a593Smuzhiyun 		       __func__);
1309*4882a593Smuzhiyun 		return -EINVAL;
1310*4882a593Smuzhiyun 	}
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	rcu_read_lock();
1313*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1314*4882a593Smuzhiyun 	rc = sidtab_hash_stats(policy->sidtab, page);
1315*4882a593Smuzhiyun 	rcu_read_unlock();
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	return rc;
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun 
security_get_initial_sid_context(u32 sid)1320*4882a593Smuzhiyun const char *security_get_initial_sid_context(u32 sid)
1321*4882a593Smuzhiyun {
1322*4882a593Smuzhiyun 	if (unlikely(sid > SECINITSID_NUM))
1323*4882a593Smuzhiyun 		return NULL;
1324*4882a593Smuzhiyun 	return initial_sid_to_string[sid];
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun 
security_sid_to_context_core(struct selinux_state * state,u32 sid,char ** scontext,u32 * scontext_len,int force,int only_invalid)1327*4882a593Smuzhiyun static int security_sid_to_context_core(struct selinux_state *state,
1328*4882a593Smuzhiyun 					u32 sid, char **scontext,
1329*4882a593Smuzhiyun 					u32 *scontext_len, int force,
1330*4882a593Smuzhiyun 					int only_invalid)
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun 	struct selinux_policy *policy;
1333*4882a593Smuzhiyun 	struct policydb *policydb;
1334*4882a593Smuzhiyun 	struct sidtab *sidtab;
1335*4882a593Smuzhiyun 	struct sidtab_entry *entry;
1336*4882a593Smuzhiyun 	int rc = 0;
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 	if (scontext)
1339*4882a593Smuzhiyun 		*scontext = NULL;
1340*4882a593Smuzhiyun 	*scontext_len  = 0;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
1343*4882a593Smuzhiyun 		if (sid <= SECINITSID_NUM) {
1344*4882a593Smuzhiyun 			char *scontextp;
1345*4882a593Smuzhiyun 			const char *s = initial_sid_to_string[sid];
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 			if (!s)
1348*4882a593Smuzhiyun 				return -EINVAL;
1349*4882a593Smuzhiyun 			*scontext_len = strlen(s) + 1;
1350*4882a593Smuzhiyun 			if (!scontext)
1351*4882a593Smuzhiyun 				return 0;
1352*4882a593Smuzhiyun 			scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
1353*4882a593Smuzhiyun 			if (!scontextp)
1354*4882a593Smuzhiyun 				return -ENOMEM;
1355*4882a593Smuzhiyun 			*scontext = scontextp;
1356*4882a593Smuzhiyun 			return 0;
1357*4882a593Smuzhiyun 		}
1358*4882a593Smuzhiyun 		pr_err("SELinux: %s:  called before initial "
1359*4882a593Smuzhiyun 		       "load_policy on unknown SID %d\n", __func__, sid);
1360*4882a593Smuzhiyun 		return -EINVAL;
1361*4882a593Smuzhiyun 	}
1362*4882a593Smuzhiyun 	rcu_read_lock();
1363*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1364*4882a593Smuzhiyun 	policydb = &policy->policydb;
1365*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	if (force)
1368*4882a593Smuzhiyun 		entry = sidtab_search_entry_force(sidtab, sid);
1369*4882a593Smuzhiyun 	else
1370*4882a593Smuzhiyun 		entry = sidtab_search_entry(sidtab, sid);
1371*4882a593Smuzhiyun 	if (!entry) {
1372*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1373*4882a593Smuzhiyun 			__func__, sid);
1374*4882a593Smuzhiyun 		rc = -EINVAL;
1375*4882a593Smuzhiyun 		goto out_unlock;
1376*4882a593Smuzhiyun 	}
1377*4882a593Smuzhiyun 	if (only_invalid && !entry->context.len)
1378*4882a593Smuzhiyun 		goto out_unlock;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
1381*4882a593Smuzhiyun 				    scontext_len);
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun out_unlock:
1384*4882a593Smuzhiyun 	rcu_read_unlock();
1385*4882a593Smuzhiyun 	return rc;
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun /**
1390*4882a593Smuzhiyun  * security_sid_to_context - Obtain a context for a given SID.
1391*4882a593Smuzhiyun  * @sid: security identifier, SID
1392*4882a593Smuzhiyun  * @scontext: security context
1393*4882a593Smuzhiyun  * @scontext_len: length in bytes
1394*4882a593Smuzhiyun  *
1395*4882a593Smuzhiyun  * Write the string representation of the context associated with @sid
1396*4882a593Smuzhiyun  * into a dynamically allocated string of the correct size.  Set @scontext
1397*4882a593Smuzhiyun  * to point to this string and set @scontext_len to the length of the string.
1398*4882a593Smuzhiyun  */
security_sid_to_context(struct selinux_state * state,u32 sid,char ** scontext,u32 * scontext_len)1399*4882a593Smuzhiyun int security_sid_to_context(struct selinux_state *state,
1400*4882a593Smuzhiyun 			    u32 sid, char **scontext, u32 *scontext_len)
1401*4882a593Smuzhiyun {
1402*4882a593Smuzhiyun 	return security_sid_to_context_core(state, sid, scontext,
1403*4882a593Smuzhiyun 					    scontext_len, 0, 0);
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun 
security_sid_to_context_force(struct selinux_state * state,u32 sid,char ** scontext,u32 * scontext_len)1406*4882a593Smuzhiyun int security_sid_to_context_force(struct selinux_state *state, u32 sid,
1407*4882a593Smuzhiyun 				  char **scontext, u32 *scontext_len)
1408*4882a593Smuzhiyun {
1409*4882a593Smuzhiyun 	return security_sid_to_context_core(state, sid, scontext,
1410*4882a593Smuzhiyun 					    scontext_len, 1, 0);
1411*4882a593Smuzhiyun }
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun /**
1414*4882a593Smuzhiyun  * security_sid_to_context_inval - Obtain a context for a given SID if it
1415*4882a593Smuzhiyun  *                                 is invalid.
1416*4882a593Smuzhiyun  * @sid: security identifier, SID
1417*4882a593Smuzhiyun  * @scontext: security context
1418*4882a593Smuzhiyun  * @scontext_len: length in bytes
1419*4882a593Smuzhiyun  *
1420*4882a593Smuzhiyun  * Write the string representation of the context associated with @sid
1421*4882a593Smuzhiyun  * into a dynamically allocated string of the correct size, but only if the
1422*4882a593Smuzhiyun  * context is invalid in the current policy.  Set @scontext to point to
1423*4882a593Smuzhiyun  * this string (or NULL if the context is valid) and set @scontext_len to
1424*4882a593Smuzhiyun  * the length of the string (or 0 if the context is valid).
1425*4882a593Smuzhiyun  */
security_sid_to_context_inval(struct selinux_state * state,u32 sid,char ** scontext,u32 * scontext_len)1426*4882a593Smuzhiyun int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
1427*4882a593Smuzhiyun 				  char **scontext, u32 *scontext_len)
1428*4882a593Smuzhiyun {
1429*4882a593Smuzhiyun 	return security_sid_to_context_core(state, sid, scontext,
1430*4882a593Smuzhiyun 					    scontext_len, 1, 1);
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun /*
1434*4882a593Smuzhiyun  * Caveat:  Mutates scontext.
1435*4882a593Smuzhiyun  */
string_to_context_struct(struct policydb * pol,struct sidtab * sidtabp,char * scontext,struct context * ctx,u32 def_sid)1436*4882a593Smuzhiyun static int string_to_context_struct(struct policydb *pol,
1437*4882a593Smuzhiyun 				    struct sidtab *sidtabp,
1438*4882a593Smuzhiyun 				    char *scontext,
1439*4882a593Smuzhiyun 				    struct context *ctx,
1440*4882a593Smuzhiyun 				    u32 def_sid)
1441*4882a593Smuzhiyun {
1442*4882a593Smuzhiyun 	struct role_datum *role;
1443*4882a593Smuzhiyun 	struct type_datum *typdatum;
1444*4882a593Smuzhiyun 	struct user_datum *usrdatum;
1445*4882a593Smuzhiyun 	char *scontextp, *p, oldc;
1446*4882a593Smuzhiyun 	int rc = 0;
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	context_init(ctx);
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	/* Parse the security context. */
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	rc = -EINVAL;
1453*4882a593Smuzhiyun 	scontextp = (char *) scontext;
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	/* Extract the user. */
1456*4882a593Smuzhiyun 	p = scontextp;
1457*4882a593Smuzhiyun 	while (*p && *p != ':')
1458*4882a593Smuzhiyun 		p++;
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	if (*p == 0)
1461*4882a593Smuzhiyun 		goto out;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	*p++ = 0;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	usrdatum = symtab_search(&pol->p_users, scontextp);
1466*4882a593Smuzhiyun 	if (!usrdatum)
1467*4882a593Smuzhiyun 		goto out;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	ctx->user = usrdatum->value;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	/* Extract role. */
1472*4882a593Smuzhiyun 	scontextp = p;
1473*4882a593Smuzhiyun 	while (*p && *p != ':')
1474*4882a593Smuzhiyun 		p++;
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	if (*p == 0)
1477*4882a593Smuzhiyun 		goto out;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun 	*p++ = 0;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	role = symtab_search(&pol->p_roles, scontextp);
1482*4882a593Smuzhiyun 	if (!role)
1483*4882a593Smuzhiyun 		goto out;
1484*4882a593Smuzhiyun 	ctx->role = role->value;
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun 	/* Extract type. */
1487*4882a593Smuzhiyun 	scontextp = p;
1488*4882a593Smuzhiyun 	while (*p && *p != ':')
1489*4882a593Smuzhiyun 		p++;
1490*4882a593Smuzhiyun 	oldc = *p;
1491*4882a593Smuzhiyun 	*p++ = 0;
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	typdatum = symtab_search(&pol->p_types, scontextp);
1494*4882a593Smuzhiyun 	if (!typdatum || typdatum->attribute)
1495*4882a593Smuzhiyun 		goto out;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	ctx->type = typdatum->value;
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
1500*4882a593Smuzhiyun 	if (rc)
1501*4882a593Smuzhiyun 		goto out;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	/* Check the validity of the new context. */
1504*4882a593Smuzhiyun 	rc = -EINVAL;
1505*4882a593Smuzhiyun 	if (!policydb_context_isvalid(pol, ctx))
1506*4882a593Smuzhiyun 		goto out;
1507*4882a593Smuzhiyun 	rc = 0;
1508*4882a593Smuzhiyun out:
1509*4882a593Smuzhiyun 	if (rc)
1510*4882a593Smuzhiyun 		context_destroy(ctx);
1511*4882a593Smuzhiyun 	return rc;
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun 
security_context_to_sid_core(struct selinux_state * state,const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags,int force)1514*4882a593Smuzhiyun static int security_context_to_sid_core(struct selinux_state *state,
1515*4882a593Smuzhiyun 					const char *scontext, u32 scontext_len,
1516*4882a593Smuzhiyun 					u32 *sid, u32 def_sid, gfp_t gfp_flags,
1517*4882a593Smuzhiyun 					int force)
1518*4882a593Smuzhiyun {
1519*4882a593Smuzhiyun 	struct selinux_policy *policy;
1520*4882a593Smuzhiyun 	struct policydb *policydb;
1521*4882a593Smuzhiyun 	struct sidtab *sidtab;
1522*4882a593Smuzhiyun 	char *scontext2, *str = NULL;
1523*4882a593Smuzhiyun 	struct context context;
1524*4882a593Smuzhiyun 	int rc = 0;
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	/* An empty security context is never valid. */
1527*4882a593Smuzhiyun 	if (!scontext_len)
1528*4882a593Smuzhiyun 		return -EINVAL;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 	/* Copy the string to allow changes and ensure a NUL terminator */
1531*4882a593Smuzhiyun 	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1532*4882a593Smuzhiyun 	if (!scontext2)
1533*4882a593Smuzhiyun 		return -ENOMEM;
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
1536*4882a593Smuzhiyun 		int i;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 		for (i = 1; i < SECINITSID_NUM; i++) {
1539*4882a593Smuzhiyun 			const char *s = initial_sid_to_string[i];
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 			if (s && !strcmp(s, scontext2)) {
1542*4882a593Smuzhiyun 				*sid = i;
1543*4882a593Smuzhiyun 				goto out;
1544*4882a593Smuzhiyun 			}
1545*4882a593Smuzhiyun 		}
1546*4882a593Smuzhiyun 		*sid = SECINITSID_KERNEL;
1547*4882a593Smuzhiyun 		goto out;
1548*4882a593Smuzhiyun 	}
1549*4882a593Smuzhiyun 	*sid = SECSID_NULL;
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	if (force) {
1552*4882a593Smuzhiyun 		/* Save another copy for storing in uninterpreted form */
1553*4882a593Smuzhiyun 		rc = -ENOMEM;
1554*4882a593Smuzhiyun 		str = kstrdup(scontext2, gfp_flags);
1555*4882a593Smuzhiyun 		if (!str)
1556*4882a593Smuzhiyun 			goto out;
1557*4882a593Smuzhiyun 	}
1558*4882a593Smuzhiyun retry:
1559*4882a593Smuzhiyun 	rcu_read_lock();
1560*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1561*4882a593Smuzhiyun 	policydb = &policy->policydb;
1562*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1563*4882a593Smuzhiyun 	rc = string_to_context_struct(policydb, sidtab, scontext2,
1564*4882a593Smuzhiyun 				      &context, def_sid);
1565*4882a593Smuzhiyun 	if (rc == -EINVAL && force) {
1566*4882a593Smuzhiyun 		context.str = str;
1567*4882a593Smuzhiyun 		context.len = strlen(str) + 1;
1568*4882a593Smuzhiyun 		str = NULL;
1569*4882a593Smuzhiyun 	} else if (rc)
1570*4882a593Smuzhiyun 		goto out_unlock;
1571*4882a593Smuzhiyun 	rc = sidtab_context_to_sid(sidtab, &context, sid);
1572*4882a593Smuzhiyun 	if (rc == -ESTALE) {
1573*4882a593Smuzhiyun 		rcu_read_unlock();
1574*4882a593Smuzhiyun 		if (context.str) {
1575*4882a593Smuzhiyun 			str = context.str;
1576*4882a593Smuzhiyun 			context.str = NULL;
1577*4882a593Smuzhiyun 		}
1578*4882a593Smuzhiyun 		context_destroy(&context);
1579*4882a593Smuzhiyun 		goto retry;
1580*4882a593Smuzhiyun 	}
1581*4882a593Smuzhiyun 	context_destroy(&context);
1582*4882a593Smuzhiyun out_unlock:
1583*4882a593Smuzhiyun 	rcu_read_unlock();
1584*4882a593Smuzhiyun out:
1585*4882a593Smuzhiyun 	kfree(scontext2);
1586*4882a593Smuzhiyun 	kfree(str);
1587*4882a593Smuzhiyun 	return rc;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun /**
1591*4882a593Smuzhiyun  * security_context_to_sid - Obtain a SID for a given security context.
1592*4882a593Smuzhiyun  * @scontext: security context
1593*4882a593Smuzhiyun  * @scontext_len: length in bytes
1594*4882a593Smuzhiyun  * @sid: security identifier, SID
1595*4882a593Smuzhiyun  * @gfp: context for the allocation
1596*4882a593Smuzhiyun  *
1597*4882a593Smuzhiyun  * Obtains a SID associated with the security context that
1598*4882a593Smuzhiyun  * has the string representation specified by @scontext.
1599*4882a593Smuzhiyun  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1600*4882a593Smuzhiyun  * memory is available, or 0 on success.
1601*4882a593Smuzhiyun  */
security_context_to_sid(struct selinux_state * state,const char * scontext,u32 scontext_len,u32 * sid,gfp_t gfp)1602*4882a593Smuzhiyun int security_context_to_sid(struct selinux_state *state,
1603*4882a593Smuzhiyun 			    const char *scontext, u32 scontext_len, u32 *sid,
1604*4882a593Smuzhiyun 			    gfp_t gfp)
1605*4882a593Smuzhiyun {
1606*4882a593Smuzhiyun 	return security_context_to_sid_core(state, scontext, scontext_len,
1607*4882a593Smuzhiyun 					    sid, SECSID_NULL, gfp, 0);
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun 
security_context_str_to_sid(struct selinux_state * state,const char * scontext,u32 * sid,gfp_t gfp)1610*4882a593Smuzhiyun int security_context_str_to_sid(struct selinux_state *state,
1611*4882a593Smuzhiyun 				const char *scontext, u32 *sid, gfp_t gfp)
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun 	return security_context_to_sid(state, scontext, strlen(scontext),
1614*4882a593Smuzhiyun 				       sid, gfp);
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun /**
1618*4882a593Smuzhiyun  * security_context_to_sid_default - Obtain a SID for a given security context,
1619*4882a593Smuzhiyun  * falling back to specified default if needed.
1620*4882a593Smuzhiyun  *
1621*4882a593Smuzhiyun  * @scontext: security context
1622*4882a593Smuzhiyun  * @scontext_len: length in bytes
1623*4882a593Smuzhiyun  * @sid: security identifier, SID
1624*4882a593Smuzhiyun  * @def_sid: default SID to assign on error
1625*4882a593Smuzhiyun  *
1626*4882a593Smuzhiyun  * Obtains a SID associated with the security context that
1627*4882a593Smuzhiyun  * has the string representation specified by @scontext.
1628*4882a593Smuzhiyun  * The default SID is passed to the MLS layer to be used to allow
1629*4882a593Smuzhiyun  * kernel labeling of the MLS field if the MLS field is not present
1630*4882a593Smuzhiyun  * (for upgrading to MLS without full relabel).
1631*4882a593Smuzhiyun  * Implicitly forces adding of the context even if it cannot be mapped yet.
1632*4882a593Smuzhiyun  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1633*4882a593Smuzhiyun  * memory is available, or 0 on success.
1634*4882a593Smuzhiyun  */
security_context_to_sid_default(struct selinux_state * state,const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags)1635*4882a593Smuzhiyun int security_context_to_sid_default(struct selinux_state *state,
1636*4882a593Smuzhiyun 				    const char *scontext, u32 scontext_len,
1637*4882a593Smuzhiyun 				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1638*4882a593Smuzhiyun {
1639*4882a593Smuzhiyun 	return security_context_to_sid_core(state, scontext, scontext_len,
1640*4882a593Smuzhiyun 					    sid, def_sid, gfp_flags, 1);
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun 
security_context_to_sid_force(struct selinux_state * state,const char * scontext,u32 scontext_len,u32 * sid)1643*4882a593Smuzhiyun int security_context_to_sid_force(struct selinux_state *state,
1644*4882a593Smuzhiyun 				  const char *scontext, u32 scontext_len,
1645*4882a593Smuzhiyun 				  u32 *sid)
1646*4882a593Smuzhiyun {
1647*4882a593Smuzhiyun 	return security_context_to_sid_core(state, scontext, scontext_len,
1648*4882a593Smuzhiyun 					    sid, SECSID_NULL, GFP_KERNEL, 1);
1649*4882a593Smuzhiyun }
1650*4882a593Smuzhiyun 
compute_sid_handle_invalid_context(struct selinux_state * state,struct selinux_policy * policy,struct sidtab_entry * sentry,struct sidtab_entry * tentry,u16 tclass,struct context * newcontext)1651*4882a593Smuzhiyun static int compute_sid_handle_invalid_context(
1652*4882a593Smuzhiyun 	struct selinux_state *state,
1653*4882a593Smuzhiyun 	struct selinux_policy *policy,
1654*4882a593Smuzhiyun 	struct sidtab_entry *sentry,
1655*4882a593Smuzhiyun 	struct sidtab_entry *tentry,
1656*4882a593Smuzhiyun 	u16 tclass,
1657*4882a593Smuzhiyun 	struct context *newcontext)
1658*4882a593Smuzhiyun {
1659*4882a593Smuzhiyun 	struct policydb *policydb = &policy->policydb;
1660*4882a593Smuzhiyun 	struct sidtab *sidtab = policy->sidtab;
1661*4882a593Smuzhiyun 	char *s = NULL, *t = NULL, *n = NULL;
1662*4882a593Smuzhiyun 	u32 slen, tlen, nlen;
1663*4882a593Smuzhiyun 	struct audit_buffer *ab;
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
1666*4882a593Smuzhiyun 		goto out;
1667*4882a593Smuzhiyun 	if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
1668*4882a593Smuzhiyun 		goto out;
1669*4882a593Smuzhiyun 	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
1670*4882a593Smuzhiyun 		goto out;
1671*4882a593Smuzhiyun 	ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1672*4882a593Smuzhiyun 	audit_log_format(ab,
1673*4882a593Smuzhiyun 			 "op=security_compute_sid invalid_context=");
1674*4882a593Smuzhiyun 	/* no need to record the NUL with untrusted strings */
1675*4882a593Smuzhiyun 	audit_log_n_untrustedstring(ab, n, nlen - 1);
1676*4882a593Smuzhiyun 	audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1677*4882a593Smuzhiyun 			 s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1678*4882a593Smuzhiyun 	audit_log_end(ab);
1679*4882a593Smuzhiyun out:
1680*4882a593Smuzhiyun 	kfree(s);
1681*4882a593Smuzhiyun 	kfree(t);
1682*4882a593Smuzhiyun 	kfree(n);
1683*4882a593Smuzhiyun 	if (!enforcing_enabled(state))
1684*4882a593Smuzhiyun 		return 0;
1685*4882a593Smuzhiyun 	return -EACCES;
1686*4882a593Smuzhiyun }
1687*4882a593Smuzhiyun 
filename_compute_type(struct policydb * policydb,struct context * newcontext,u32 stype,u32 ttype,u16 tclass,const char * objname)1688*4882a593Smuzhiyun static void filename_compute_type(struct policydb *policydb,
1689*4882a593Smuzhiyun 				  struct context *newcontext,
1690*4882a593Smuzhiyun 				  u32 stype, u32 ttype, u16 tclass,
1691*4882a593Smuzhiyun 				  const char *objname)
1692*4882a593Smuzhiyun {
1693*4882a593Smuzhiyun 	struct filename_trans_key ft;
1694*4882a593Smuzhiyun 	struct filename_trans_datum *datum;
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 	/*
1697*4882a593Smuzhiyun 	 * Most filename trans rules are going to live in specific directories
1698*4882a593Smuzhiyun 	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
1699*4882a593Smuzhiyun 	 * if the ttype does not contain any rules.
1700*4882a593Smuzhiyun 	 */
1701*4882a593Smuzhiyun 	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1702*4882a593Smuzhiyun 		return;
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	ft.ttype = ttype;
1705*4882a593Smuzhiyun 	ft.tclass = tclass;
1706*4882a593Smuzhiyun 	ft.name = objname;
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun 	datum = policydb_filenametr_search(policydb, &ft);
1709*4882a593Smuzhiyun 	while (datum) {
1710*4882a593Smuzhiyun 		if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
1711*4882a593Smuzhiyun 			newcontext->type = datum->otype;
1712*4882a593Smuzhiyun 			return;
1713*4882a593Smuzhiyun 		}
1714*4882a593Smuzhiyun 		datum = datum->next;
1715*4882a593Smuzhiyun 	}
1716*4882a593Smuzhiyun }
1717*4882a593Smuzhiyun 
security_compute_sid(struct selinux_state * state,u32 ssid,u32 tsid,u16 orig_tclass,u32 specified,const char * objname,u32 * out_sid,bool kern)1718*4882a593Smuzhiyun static int security_compute_sid(struct selinux_state *state,
1719*4882a593Smuzhiyun 				u32 ssid,
1720*4882a593Smuzhiyun 				u32 tsid,
1721*4882a593Smuzhiyun 				u16 orig_tclass,
1722*4882a593Smuzhiyun 				u32 specified,
1723*4882a593Smuzhiyun 				const char *objname,
1724*4882a593Smuzhiyun 				u32 *out_sid,
1725*4882a593Smuzhiyun 				bool kern)
1726*4882a593Smuzhiyun {
1727*4882a593Smuzhiyun 	struct selinux_policy *policy;
1728*4882a593Smuzhiyun 	struct policydb *policydb;
1729*4882a593Smuzhiyun 	struct sidtab *sidtab;
1730*4882a593Smuzhiyun 	struct class_datum *cladatum;
1731*4882a593Smuzhiyun 	struct context *scontext, *tcontext, newcontext;
1732*4882a593Smuzhiyun 	struct sidtab_entry *sentry, *tentry;
1733*4882a593Smuzhiyun 	struct avtab_key avkey;
1734*4882a593Smuzhiyun 	struct avtab_datum *avdatum;
1735*4882a593Smuzhiyun 	struct avtab_node *node;
1736*4882a593Smuzhiyun 	u16 tclass;
1737*4882a593Smuzhiyun 	int rc = 0;
1738*4882a593Smuzhiyun 	bool sock;
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
1741*4882a593Smuzhiyun 		switch (orig_tclass) {
1742*4882a593Smuzhiyun 		case SECCLASS_PROCESS: /* kernel value */
1743*4882a593Smuzhiyun 			*out_sid = ssid;
1744*4882a593Smuzhiyun 			break;
1745*4882a593Smuzhiyun 		default:
1746*4882a593Smuzhiyun 			*out_sid = tsid;
1747*4882a593Smuzhiyun 			break;
1748*4882a593Smuzhiyun 		}
1749*4882a593Smuzhiyun 		goto out;
1750*4882a593Smuzhiyun 	}
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun retry:
1753*4882a593Smuzhiyun 	cladatum = NULL;
1754*4882a593Smuzhiyun 	context_init(&newcontext);
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun 	rcu_read_lock();
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 	if (kern) {
1761*4882a593Smuzhiyun 		tclass = unmap_class(&policy->map, orig_tclass);
1762*4882a593Smuzhiyun 		sock = security_is_socket_class(orig_tclass);
1763*4882a593Smuzhiyun 	} else {
1764*4882a593Smuzhiyun 		tclass = orig_tclass;
1765*4882a593Smuzhiyun 		sock = security_is_socket_class(map_class(&policy->map,
1766*4882a593Smuzhiyun 							  tclass));
1767*4882a593Smuzhiyun 	}
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 	policydb = &policy->policydb;
1770*4882a593Smuzhiyun 	sidtab = policy->sidtab;
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun 	sentry = sidtab_search_entry(sidtab, ssid);
1773*4882a593Smuzhiyun 	if (!sentry) {
1774*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1775*4882a593Smuzhiyun 		       __func__, ssid);
1776*4882a593Smuzhiyun 		rc = -EINVAL;
1777*4882a593Smuzhiyun 		goto out_unlock;
1778*4882a593Smuzhiyun 	}
1779*4882a593Smuzhiyun 	tentry = sidtab_search_entry(sidtab, tsid);
1780*4882a593Smuzhiyun 	if (!tentry) {
1781*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
1782*4882a593Smuzhiyun 		       __func__, tsid);
1783*4882a593Smuzhiyun 		rc = -EINVAL;
1784*4882a593Smuzhiyun 		goto out_unlock;
1785*4882a593Smuzhiyun 	}
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 	scontext = &sentry->context;
1788*4882a593Smuzhiyun 	tcontext = &tentry->context;
1789*4882a593Smuzhiyun 
1790*4882a593Smuzhiyun 	if (tclass && tclass <= policydb->p_classes.nprim)
1791*4882a593Smuzhiyun 		cladatum = policydb->class_val_to_struct[tclass - 1];
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun 	/* Set the user identity. */
1794*4882a593Smuzhiyun 	switch (specified) {
1795*4882a593Smuzhiyun 	case AVTAB_TRANSITION:
1796*4882a593Smuzhiyun 	case AVTAB_CHANGE:
1797*4882a593Smuzhiyun 		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1798*4882a593Smuzhiyun 			newcontext.user = tcontext->user;
1799*4882a593Smuzhiyun 		} else {
1800*4882a593Smuzhiyun 			/* notice this gets both DEFAULT_SOURCE and unset */
1801*4882a593Smuzhiyun 			/* Use the process user identity. */
1802*4882a593Smuzhiyun 			newcontext.user = scontext->user;
1803*4882a593Smuzhiyun 		}
1804*4882a593Smuzhiyun 		break;
1805*4882a593Smuzhiyun 	case AVTAB_MEMBER:
1806*4882a593Smuzhiyun 		/* Use the related object owner. */
1807*4882a593Smuzhiyun 		newcontext.user = tcontext->user;
1808*4882a593Smuzhiyun 		break;
1809*4882a593Smuzhiyun 	}
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun 	/* Set the role to default values. */
1812*4882a593Smuzhiyun 	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
1813*4882a593Smuzhiyun 		newcontext.role = scontext->role;
1814*4882a593Smuzhiyun 	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1815*4882a593Smuzhiyun 		newcontext.role = tcontext->role;
1816*4882a593Smuzhiyun 	} else {
1817*4882a593Smuzhiyun 		if ((tclass == policydb->process_class) || sock)
1818*4882a593Smuzhiyun 			newcontext.role = scontext->role;
1819*4882a593Smuzhiyun 		else
1820*4882a593Smuzhiyun 			newcontext.role = OBJECT_R_VAL;
1821*4882a593Smuzhiyun 	}
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	/* Set the type to default values. */
1824*4882a593Smuzhiyun 	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1825*4882a593Smuzhiyun 		newcontext.type = scontext->type;
1826*4882a593Smuzhiyun 	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1827*4882a593Smuzhiyun 		newcontext.type = tcontext->type;
1828*4882a593Smuzhiyun 	} else {
1829*4882a593Smuzhiyun 		if ((tclass == policydb->process_class) || sock) {
1830*4882a593Smuzhiyun 			/* Use the type of process. */
1831*4882a593Smuzhiyun 			newcontext.type = scontext->type;
1832*4882a593Smuzhiyun 		} else {
1833*4882a593Smuzhiyun 			/* Use the type of the related object. */
1834*4882a593Smuzhiyun 			newcontext.type = tcontext->type;
1835*4882a593Smuzhiyun 		}
1836*4882a593Smuzhiyun 	}
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun 	/* Look for a type transition/member/change rule. */
1839*4882a593Smuzhiyun 	avkey.source_type = scontext->type;
1840*4882a593Smuzhiyun 	avkey.target_type = tcontext->type;
1841*4882a593Smuzhiyun 	avkey.target_class = tclass;
1842*4882a593Smuzhiyun 	avkey.specified = specified;
1843*4882a593Smuzhiyun 	avdatum = avtab_search(&policydb->te_avtab, &avkey);
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 	/* If no permanent rule, also check for enabled conditional rules */
1846*4882a593Smuzhiyun 	if (!avdatum) {
1847*4882a593Smuzhiyun 		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1848*4882a593Smuzhiyun 		for (; node; node = avtab_search_node_next(node, specified)) {
1849*4882a593Smuzhiyun 			if (node->key.specified & AVTAB_ENABLED) {
1850*4882a593Smuzhiyun 				avdatum = &node->datum;
1851*4882a593Smuzhiyun 				break;
1852*4882a593Smuzhiyun 			}
1853*4882a593Smuzhiyun 		}
1854*4882a593Smuzhiyun 	}
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun 	if (avdatum) {
1857*4882a593Smuzhiyun 		/* Use the type from the type transition/member/change rule. */
1858*4882a593Smuzhiyun 		newcontext.type = avdatum->u.data;
1859*4882a593Smuzhiyun 	}
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun 	/* if we have a objname this is a file trans check so check those rules */
1862*4882a593Smuzhiyun 	if (objname)
1863*4882a593Smuzhiyun 		filename_compute_type(policydb, &newcontext, scontext->type,
1864*4882a593Smuzhiyun 				      tcontext->type, tclass, objname);
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun 	/* Check for class-specific changes. */
1867*4882a593Smuzhiyun 	if (specified & AVTAB_TRANSITION) {
1868*4882a593Smuzhiyun 		/* Look for a role transition rule. */
1869*4882a593Smuzhiyun 		struct role_trans_datum *rtd;
1870*4882a593Smuzhiyun 		struct role_trans_key rtk = {
1871*4882a593Smuzhiyun 			.role = scontext->role,
1872*4882a593Smuzhiyun 			.type = tcontext->type,
1873*4882a593Smuzhiyun 			.tclass = tclass,
1874*4882a593Smuzhiyun 		};
1875*4882a593Smuzhiyun 
1876*4882a593Smuzhiyun 		rtd = policydb_roletr_search(policydb, &rtk);
1877*4882a593Smuzhiyun 		if (rtd)
1878*4882a593Smuzhiyun 			newcontext.role = rtd->new_role;
1879*4882a593Smuzhiyun 	}
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 	/* Set the MLS attributes.
1882*4882a593Smuzhiyun 	   This is done last because it may allocate memory. */
1883*4882a593Smuzhiyun 	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
1884*4882a593Smuzhiyun 			     &newcontext, sock);
1885*4882a593Smuzhiyun 	if (rc)
1886*4882a593Smuzhiyun 		goto out_unlock;
1887*4882a593Smuzhiyun 
1888*4882a593Smuzhiyun 	/* Check the validity of the context. */
1889*4882a593Smuzhiyun 	if (!policydb_context_isvalid(policydb, &newcontext)) {
1890*4882a593Smuzhiyun 		rc = compute_sid_handle_invalid_context(state, policy, sentry,
1891*4882a593Smuzhiyun 							tentry, tclass,
1892*4882a593Smuzhiyun 							&newcontext);
1893*4882a593Smuzhiyun 		if (rc)
1894*4882a593Smuzhiyun 			goto out_unlock;
1895*4882a593Smuzhiyun 	}
1896*4882a593Smuzhiyun 	/* Obtain the sid for the context. */
1897*4882a593Smuzhiyun 	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
1898*4882a593Smuzhiyun 	if (rc == -ESTALE) {
1899*4882a593Smuzhiyun 		rcu_read_unlock();
1900*4882a593Smuzhiyun 		context_destroy(&newcontext);
1901*4882a593Smuzhiyun 		goto retry;
1902*4882a593Smuzhiyun 	}
1903*4882a593Smuzhiyun out_unlock:
1904*4882a593Smuzhiyun 	rcu_read_unlock();
1905*4882a593Smuzhiyun 	context_destroy(&newcontext);
1906*4882a593Smuzhiyun out:
1907*4882a593Smuzhiyun 	return rc;
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun /**
1911*4882a593Smuzhiyun  * security_transition_sid - Compute the SID for a new subject/object.
1912*4882a593Smuzhiyun  * @ssid: source security identifier
1913*4882a593Smuzhiyun  * @tsid: target security identifier
1914*4882a593Smuzhiyun  * @tclass: target security class
1915*4882a593Smuzhiyun  * @out_sid: security identifier for new subject/object
1916*4882a593Smuzhiyun  *
1917*4882a593Smuzhiyun  * Compute a SID to use for labeling a new subject or object in the
1918*4882a593Smuzhiyun  * class @tclass based on a SID pair (@ssid, @tsid).
1919*4882a593Smuzhiyun  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
1920*4882a593Smuzhiyun  * if insufficient memory is available, or %0 if the new SID was
1921*4882a593Smuzhiyun  * computed successfully.
1922*4882a593Smuzhiyun  */
security_transition_sid(struct selinux_state * state,u32 ssid,u32 tsid,u16 tclass,const struct qstr * qstr,u32 * out_sid)1923*4882a593Smuzhiyun int security_transition_sid(struct selinux_state *state,
1924*4882a593Smuzhiyun 			    u32 ssid, u32 tsid, u16 tclass,
1925*4882a593Smuzhiyun 			    const struct qstr *qstr, u32 *out_sid)
1926*4882a593Smuzhiyun {
1927*4882a593Smuzhiyun 	return security_compute_sid(state, ssid, tsid, tclass,
1928*4882a593Smuzhiyun 				    AVTAB_TRANSITION,
1929*4882a593Smuzhiyun 				    qstr ? qstr->name : NULL, out_sid, true);
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun 
security_transition_sid_user(struct selinux_state * state,u32 ssid,u32 tsid,u16 tclass,const char * objname,u32 * out_sid)1932*4882a593Smuzhiyun int security_transition_sid_user(struct selinux_state *state,
1933*4882a593Smuzhiyun 				 u32 ssid, u32 tsid, u16 tclass,
1934*4882a593Smuzhiyun 				 const char *objname, u32 *out_sid)
1935*4882a593Smuzhiyun {
1936*4882a593Smuzhiyun 	return security_compute_sid(state, ssid, tsid, tclass,
1937*4882a593Smuzhiyun 				    AVTAB_TRANSITION,
1938*4882a593Smuzhiyun 				    objname, out_sid, false);
1939*4882a593Smuzhiyun }
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun /**
1942*4882a593Smuzhiyun  * security_member_sid - Compute the SID for member selection.
1943*4882a593Smuzhiyun  * @ssid: source security identifier
1944*4882a593Smuzhiyun  * @tsid: target security identifier
1945*4882a593Smuzhiyun  * @tclass: target security class
1946*4882a593Smuzhiyun  * @out_sid: security identifier for selected member
1947*4882a593Smuzhiyun  *
1948*4882a593Smuzhiyun  * Compute a SID to use when selecting a member of a polyinstantiated
1949*4882a593Smuzhiyun  * object of class @tclass based on a SID pair (@ssid, @tsid).
1950*4882a593Smuzhiyun  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
1951*4882a593Smuzhiyun  * if insufficient memory is available, or %0 if the SID was
1952*4882a593Smuzhiyun  * computed successfully.
1953*4882a593Smuzhiyun  */
security_member_sid(struct selinux_state * state,u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1954*4882a593Smuzhiyun int security_member_sid(struct selinux_state *state,
1955*4882a593Smuzhiyun 			u32 ssid,
1956*4882a593Smuzhiyun 			u32 tsid,
1957*4882a593Smuzhiyun 			u16 tclass,
1958*4882a593Smuzhiyun 			u32 *out_sid)
1959*4882a593Smuzhiyun {
1960*4882a593Smuzhiyun 	return security_compute_sid(state, ssid, tsid, tclass,
1961*4882a593Smuzhiyun 				    AVTAB_MEMBER, NULL,
1962*4882a593Smuzhiyun 				    out_sid, false);
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun 
1965*4882a593Smuzhiyun /**
1966*4882a593Smuzhiyun  * security_change_sid - Compute the SID for object relabeling.
1967*4882a593Smuzhiyun  * @ssid: source security identifier
1968*4882a593Smuzhiyun  * @tsid: target security identifier
1969*4882a593Smuzhiyun  * @tclass: target security class
1970*4882a593Smuzhiyun  * @out_sid: security identifier for selected member
1971*4882a593Smuzhiyun  *
1972*4882a593Smuzhiyun  * Compute a SID to use for relabeling an object of class @tclass
1973*4882a593Smuzhiyun  * based on a SID pair (@ssid, @tsid).
1974*4882a593Smuzhiyun  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
1975*4882a593Smuzhiyun  * if insufficient memory is available, or %0 if the SID was
1976*4882a593Smuzhiyun  * computed successfully.
1977*4882a593Smuzhiyun  */
security_change_sid(struct selinux_state * state,u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1978*4882a593Smuzhiyun int security_change_sid(struct selinux_state *state,
1979*4882a593Smuzhiyun 			u32 ssid,
1980*4882a593Smuzhiyun 			u32 tsid,
1981*4882a593Smuzhiyun 			u16 tclass,
1982*4882a593Smuzhiyun 			u32 *out_sid)
1983*4882a593Smuzhiyun {
1984*4882a593Smuzhiyun 	return security_compute_sid(state,
1985*4882a593Smuzhiyun 				    ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1986*4882a593Smuzhiyun 				    out_sid, false);
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun 
convert_context_handle_invalid_context(struct selinux_state * state,struct policydb * policydb,struct context * context)1989*4882a593Smuzhiyun static inline int convert_context_handle_invalid_context(
1990*4882a593Smuzhiyun 	struct selinux_state *state,
1991*4882a593Smuzhiyun 	struct policydb *policydb,
1992*4882a593Smuzhiyun 	struct context *context)
1993*4882a593Smuzhiyun {
1994*4882a593Smuzhiyun 	char *s;
1995*4882a593Smuzhiyun 	u32 len;
1996*4882a593Smuzhiyun 
1997*4882a593Smuzhiyun 	if (enforcing_enabled(state))
1998*4882a593Smuzhiyun 		return -EINVAL;
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	if (!context_struct_to_string(policydb, context, &s, &len)) {
2001*4882a593Smuzhiyun 		pr_warn("SELinux:  Context %s would be invalid if enforcing\n",
2002*4882a593Smuzhiyun 			s);
2003*4882a593Smuzhiyun 		kfree(s);
2004*4882a593Smuzhiyun 	}
2005*4882a593Smuzhiyun 	return 0;
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun /*
2009*4882a593Smuzhiyun  * Convert the values in the security context
2010*4882a593Smuzhiyun  * structure `oldc' from the values specified
2011*4882a593Smuzhiyun  * in the policy `p->oldp' to the values specified
2012*4882a593Smuzhiyun  * in the policy `p->newp', storing the new context
2013*4882a593Smuzhiyun  * in `newc'.  Verify that the context is valid
2014*4882a593Smuzhiyun  * under the new policy.
2015*4882a593Smuzhiyun  */
convert_context(struct context * oldc,struct context * newc,void * p,gfp_t gfp_flags)2016*4882a593Smuzhiyun static int convert_context(struct context *oldc, struct context *newc, void *p,
2017*4882a593Smuzhiyun 			   gfp_t gfp_flags)
2018*4882a593Smuzhiyun {
2019*4882a593Smuzhiyun 	struct convert_context_args *args;
2020*4882a593Smuzhiyun 	struct ocontext *oc;
2021*4882a593Smuzhiyun 	struct role_datum *role;
2022*4882a593Smuzhiyun 	struct type_datum *typdatum;
2023*4882a593Smuzhiyun 	struct user_datum *usrdatum;
2024*4882a593Smuzhiyun 	char *s;
2025*4882a593Smuzhiyun 	u32 len;
2026*4882a593Smuzhiyun 	int rc;
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	args = p;
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	if (oldc->str) {
2031*4882a593Smuzhiyun 		s = kstrdup(oldc->str, gfp_flags);
2032*4882a593Smuzhiyun 		if (!s)
2033*4882a593Smuzhiyun 			return -ENOMEM;
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 		rc = string_to_context_struct(args->newp, NULL, s,
2036*4882a593Smuzhiyun 					      newc, SECSID_NULL);
2037*4882a593Smuzhiyun 		if (rc == -EINVAL) {
2038*4882a593Smuzhiyun 			/*
2039*4882a593Smuzhiyun 			 * Retain string representation for later mapping.
2040*4882a593Smuzhiyun 			 *
2041*4882a593Smuzhiyun 			 * IMPORTANT: We need to copy the contents of oldc->str
2042*4882a593Smuzhiyun 			 * back into s again because string_to_context_struct()
2043*4882a593Smuzhiyun 			 * may have garbled it.
2044*4882a593Smuzhiyun 			 */
2045*4882a593Smuzhiyun 			memcpy(s, oldc->str, oldc->len);
2046*4882a593Smuzhiyun 			context_init(newc);
2047*4882a593Smuzhiyun 			newc->str = s;
2048*4882a593Smuzhiyun 			newc->len = oldc->len;
2049*4882a593Smuzhiyun 			return 0;
2050*4882a593Smuzhiyun 		}
2051*4882a593Smuzhiyun 		kfree(s);
2052*4882a593Smuzhiyun 		if (rc) {
2053*4882a593Smuzhiyun 			/* Other error condition, e.g. ENOMEM. */
2054*4882a593Smuzhiyun 			pr_err("SELinux:   Unable to map context %s, rc = %d.\n",
2055*4882a593Smuzhiyun 			       oldc->str, -rc);
2056*4882a593Smuzhiyun 			return rc;
2057*4882a593Smuzhiyun 		}
2058*4882a593Smuzhiyun 		pr_info("SELinux:  Context %s became valid (mapped).\n",
2059*4882a593Smuzhiyun 			oldc->str);
2060*4882a593Smuzhiyun 		return 0;
2061*4882a593Smuzhiyun 	}
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 	context_init(newc);
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	/* Convert the user. */
2066*4882a593Smuzhiyun 	rc = -EINVAL;
2067*4882a593Smuzhiyun 	usrdatum = symtab_search(&args->newp->p_users,
2068*4882a593Smuzhiyun 				 sym_name(args->oldp,
2069*4882a593Smuzhiyun 					  SYM_USERS, oldc->user - 1));
2070*4882a593Smuzhiyun 	if (!usrdatum)
2071*4882a593Smuzhiyun 		goto bad;
2072*4882a593Smuzhiyun 	newc->user = usrdatum->value;
2073*4882a593Smuzhiyun 
2074*4882a593Smuzhiyun 	/* Convert the role. */
2075*4882a593Smuzhiyun 	rc = -EINVAL;
2076*4882a593Smuzhiyun 	role = symtab_search(&args->newp->p_roles,
2077*4882a593Smuzhiyun 			     sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
2078*4882a593Smuzhiyun 	if (!role)
2079*4882a593Smuzhiyun 		goto bad;
2080*4882a593Smuzhiyun 	newc->role = role->value;
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 	/* Convert the type. */
2083*4882a593Smuzhiyun 	rc = -EINVAL;
2084*4882a593Smuzhiyun 	typdatum = symtab_search(&args->newp->p_types,
2085*4882a593Smuzhiyun 				 sym_name(args->oldp,
2086*4882a593Smuzhiyun 					  SYM_TYPES, oldc->type - 1));
2087*4882a593Smuzhiyun 	if (!typdatum)
2088*4882a593Smuzhiyun 		goto bad;
2089*4882a593Smuzhiyun 	newc->type = typdatum->value;
2090*4882a593Smuzhiyun 
2091*4882a593Smuzhiyun 	/* Convert the MLS fields if dealing with MLS policies */
2092*4882a593Smuzhiyun 	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2093*4882a593Smuzhiyun 		rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
2094*4882a593Smuzhiyun 		if (rc)
2095*4882a593Smuzhiyun 			goto bad;
2096*4882a593Smuzhiyun 	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
2097*4882a593Smuzhiyun 		/*
2098*4882a593Smuzhiyun 		 * Switching between non-MLS and MLS policy:
2099*4882a593Smuzhiyun 		 * ensure that the MLS fields of the context for all
2100*4882a593Smuzhiyun 		 * existing entries in the sidtab are filled in with a
2101*4882a593Smuzhiyun 		 * suitable default value, likely taken from one of the
2102*4882a593Smuzhiyun 		 * initial SIDs.
2103*4882a593Smuzhiyun 		 */
2104*4882a593Smuzhiyun 		oc = args->newp->ocontexts[OCON_ISID];
2105*4882a593Smuzhiyun 		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
2106*4882a593Smuzhiyun 			oc = oc->next;
2107*4882a593Smuzhiyun 		rc = -EINVAL;
2108*4882a593Smuzhiyun 		if (!oc) {
2109*4882a593Smuzhiyun 			pr_err("SELinux:  unable to look up"
2110*4882a593Smuzhiyun 				" the initial SIDs list\n");
2111*4882a593Smuzhiyun 			goto bad;
2112*4882a593Smuzhiyun 		}
2113*4882a593Smuzhiyun 		rc = mls_range_set(newc, &oc->context[0].range);
2114*4882a593Smuzhiyun 		if (rc)
2115*4882a593Smuzhiyun 			goto bad;
2116*4882a593Smuzhiyun 	}
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	/* Check the validity of the new context. */
2119*4882a593Smuzhiyun 	if (!policydb_context_isvalid(args->newp, newc)) {
2120*4882a593Smuzhiyun 		rc = convert_context_handle_invalid_context(args->state,
2121*4882a593Smuzhiyun 							args->oldp,
2122*4882a593Smuzhiyun 							oldc);
2123*4882a593Smuzhiyun 		if (rc)
2124*4882a593Smuzhiyun 			goto bad;
2125*4882a593Smuzhiyun 	}
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 	return 0;
2128*4882a593Smuzhiyun bad:
2129*4882a593Smuzhiyun 	/* Map old representation to string and save it. */
2130*4882a593Smuzhiyun 	rc = context_struct_to_string(args->oldp, oldc, &s, &len);
2131*4882a593Smuzhiyun 	if (rc)
2132*4882a593Smuzhiyun 		return rc;
2133*4882a593Smuzhiyun 	context_destroy(newc);
2134*4882a593Smuzhiyun 	newc->str = s;
2135*4882a593Smuzhiyun 	newc->len = len;
2136*4882a593Smuzhiyun 	pr_info("SELinux:  Context %s became invalid (unmapped).\n",
2137*4882a593Smuzhiyun 		newc->str);
2138*4882a593Smuzhiyun 	return 0;
2139*4882a593Smuzhiyun }
2140*4882a593Smuzhiyun 
security_load_policycaps(struct selinux_state * state,struct selinux_policy * policy)2141*4882a593Smuzhiyun static void security_load_policycaps(struct selinux_state *state,
2142*4882a593Smuzhiyun 				struct selinux_policy *policy)
2143*4882a593Smuzhiyun {
2144*4882a593Smuzhiyun 	struct policydb *p;
2145*4882a593Smuzhiyun 	unsigned int i;
2146*4882a593Smuzhiyun 	struct ebitmap_node *node;
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun 	p = &policy->policydb;
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
2151*4882a593Smuzhiyun 		WRITE_ONCE(state->policycap[i],
2152*4882a593Smuzhiyun 			ebitmap_get_bit(&p->policycaps, i));
2153*4882a593Smuzhiyun 
2154*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
2155*4882a593Smuzhiyun 		pr_info("SELinux:  policy capability %s=%d\n",
2156*4882a593Smuzhiyun 			selinux_policycap_names[i],
2157*4882a593Smuzhiyun 			ebitmap_get_bit(&p->policycaps, i));
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
2160*4882a593Smuzhiyun 		if (i >= ARRAY_SIZE(selinux_policycap_names))
2161*4882a593Smuzhiyun 			pr_info("SELinux:  unknown policy capability %u\n",
2162*4882a593Smuzhiyun 				i);
2163*4882a593Smuzhiyun 	}
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 	state->android_netlink_route = p->android_netlink_route;
2166*4882a593Smuzhiyun 	state->android_netlink_getneigh = p->android_netlink_getneigh;
2167*4882a593Smuzhiyun 	selinux_nlmsg_init();
2168*4882a593Smuzhiyun }
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun static int security_preserve_bools(struct selinux_policy *oldpolicy,
2171*4882a593Smuzhiyun 				struct selinux_policy *newpolicy);
2172*4882a593Smuzhiyun 
selinux_policy_free(struct selinux_policy * policy)2173*4882a593Smuzhiyun static void selinux_policy_free(struct selinux_policy *policy)
2174*4882a593Smuzhiyun {
2175*4882a593Smuzhiyun 	if (!policy)
2176*4882a593Smuzhiyun 		return;
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun 	sidtab_destroy(policy->sidtab);
2179*4882a593Smuzhiyun 	kfree(policy->map.mapping);
2180*4882a593Smuzhiyun 	policydb_destroy(&policy->policydb);
2181*4882a593Smuzhiyun 	kfree(policy->sidtab);
2182*4882a593Smuzhiyun 	kfree(policy);
2183*4882a593Smuzhiyun }
2184*4882a593Smuzhiyun 
selinux_policy_cond_free(struct selinux_policy * policy)2185*4882a593Smuzhiyun static void selinux_policy_cond_free(struct selinux_policy *policy)
2186*4882a593Smuzhiyun {
2187*4882a593Smuzhiyun 	cond_policydb_destroy_dup(&policy->policydb);
2188*4882a593Smuzhiyun 	kfree(policy);
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun 
selinux_policy_cancel(struct selinux_state * state,struct selinux_load_state * load_state)2191*4882a593Smuzhiyun void selinux_policy_cancel(struct selinux_state *state,
2192*4882a593Smuzhiyun 			   struct selinux_load_state *load_state)
2193*4882a593Smuzhiyun {
2194*4882a593Smuzhiyun 	struct selinux_policy *oldpolicy;
2195*4882a593Smuzhiyun 
2196*4882a593Smuzhiyun 	oldpolicy = rcu_dereference_protected(state->policy,
2197*4882a593Smuzhiyun 					lockdep_is_held(&state->policy_mutex));
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun 	sidtab_cancel_convert(oldpolicy->sidtab);
2200*4882a593Smuzhiyun 	selinux_policy_free(load_state->policy);
2201*4882a593Smuzhiyun 	kfree(load_state->convert_data);
2202*4882a593Smuzhiyun }
2203*4882a593Smuzhiyun 
selinux_notify_policy_change(struct selinux_state * state,u32 seqno)2204*4882a593Smuzhiyun static void selinux_notify_policy_change(struct selinux_state *state,
2205*4882a593Smuzhiyun 					u32 seqno)
2206*4882a593Smuzhiyun {
2207*4882a593Smuzhiyun 	/* Flush external caches and notify userspace of policy load */
2208*4882a593Smuzhiyun 	avc_ss_reset(state->avc, seqno);
2209*4882a593Smuzhiyun 	selnl_notify_policyload(seqno);
2210*4882a593Smuzhiyun 	selinux_status_update_policyload(state, seqno);
2211*4882a593Smuzhiyun 	selinux_netlbl_cache_invalidate();
2212*4882a593Smuzhiyun 	selinux_xfrm_notify_policyload();
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun 
selinux_policy_commit(struct selinux_state * state,struct selinux_load_state * load_state)2215*4882a593Smuzhiyun void selinux_policy_commit(struct selinux_state *state,
2216*4882a593Smuzhiyun 			   struct selinux_load_state *load_state)
2217*4882a593Smuzhiyun {
2218*4882a593Smuzhiyun 	struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
2219*4882a593Smuzhiyun 	unsigned long flags;
2220*4882a593Smuzhiyun 	u32 seqno;
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	oldpolicy = rcu_dereference_protected(state->policy,
2223*4882a593Smuzhiyun 					lockdep_is_held(&state->policy_mutex));
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	/* If switching between different policy types, log MLS status */
2226*4882a593Smuzhiyun 	if (oldpolicy) {
2227*4882a593Smuzhiyun 		if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
2228*4882a593Smuzhiyun 			pr_info("SELinux: Disabling MLS support...\n");
2229*4882a593Smuzhiyun 		else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
2230*4882a593Smuzhiyun 			pr_info("SELinux: Enabling MLS support...\n");
2231*4882a593Smuzhiyun 	}
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 	/* Set latest granting seqno for new policy. */
2234*4882a593Smuzhiyun 	if (oldpolicy)
2235*4882a593Smuzhiyun 		newpolicy->latest_granting = oldpolicy->latest_granting + 1;
2236*4882a593Smuzhiyun 	else
2237*4882a593Smuzhiyun 		newpolicy->latest_granting = 1;
2238*4882a593Smuzhiyun 	seqno = newpolicy->latest_granting;
2239*4882a593Smuzhiyun 
2240*4882a593Smuzhiyun 	/* Install the new policy. */
2241*4882a593Smuzhiyun 	if (oldpolicy) {
2242*4882a593Smuzhiyun 		sidtab_freeze_begin(oldpolicy->sidtab, &flags);
2243*4882a593Smuzhiyun 		rcu_assign_pointer(state->policy, newpolicy);
2244*4882a593Smuzhiyun 		sidtab_freeze_end(oldpolicy->sidtab, &flags);
2245*4882a593Smuzhiyun 	} else {
2246*4882a593Smuzhiyun 		rcu_assign_pointer(state->policy, newpolicy);
2247*4882a593Smuzhiyun 	}
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 	/* Load the policycaps from the new policy */
2250*4882a593Smuzhiyun 	security_load_policycaps(state, newpolicy);
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2253*4882a593Smuzhiyun 		/*
2254*4882a593Smuzhiyun 		 * After first policy load, the security server is
2255*4882a593Smuzhiyun 		 * marked as initialized and ready to handle requests and
2256*4882a593Smuzhiyun 		 * any objects created prior to policy load are then labeled.
2257*4882a593Smuzhiyun 		 */
2258*4882a593Smuzhiyun 		selinux_mark_initialized(state);
2259*4882a593Smuzhiyun 		selinux_complete_init();
2260*4882a593Smuzhiyun 		trace_android_vh_selinux_is_initialized(state);
2261*4882a593Smuzhiyun 	}
2262*4882a593Smuzhiyun 
2263*4882a593Smuzhiyun 	/* Free the old policy */
2264*4882a593Smuzhiyun 	synchronize_rcu();
2265*4882a593Smuzhiyun 	selinux_policy_free(oldpolicy);
2266*4882a593Smuzhiyun 	kfree(load_state->convert_data);
2267*4882a593Smuzhiyun 
2268*4882a593Smuzhiyun 	/* Notify others of the policy change */
2269*4882a593Smuzhiyun 	selinux_notify_policy_change(state, seqno);
2270*4882a593Smuzhiyun }
2271*4882a593Smuzhiyun 
2272*4882a593Smuzhiyun /**
2273*4882a593Smuzhiyun  * security_load_policy - Load a security policy configuration.
2274*4882a593Smuzhiyun  * @data: binary policy data
2275*4882a593Smuzhiyun  * @len: length of data in bytes
2276*4882a593Smuzhiyun  *
2277*4882a593Smuzhiyun  * Load a new set of security policy configuration data,
2278*4882a593Smuzhiyun  * validate it and convert the SID table as necessary.
2279*4882a593Smuzhiyun  * This function will flush the access vector cache after
2280*4882a593Smuzhiyun  * loading the new policy.
2281*4882a593Smuzhiyun  */
security_load_policy(struct selinux_state * state,void * data,size_t len,struct selinux_load_state * load_state)2282*4882a593Smuzhiyun int security_load_policy(struct selinux_state *state, void *data, size_t len,
2283*4882a593Smuzhiyun 			 struct selinux_load_state *load_state)
2284*4882a593Smuzhiyun {
2285*4882a593Smuzhiyun 	struct selinux_policy *newpolicy, *oldpolicy;
2286*4882a593Smuzhiyun 	struct selinux_policy_convert_data *convert_data;
2287*4882a593Smuzhiyun 	int rc = 0;
2288*4882a593Smuzhiyun 	struct policy_file file = { data, len }, *fp = &file;
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
2291*4882a593Smuzhiyun 	if (!newpolicy)
2292*4882a593Smuzhiyun 		return -ENOMEM;
2293*4882a593Smuzhiyun 
2294*4882a593Smuzhiyun 	newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
2295*4882a593Smuzhiyun 	if (!newpolicy->sidtab) {
2296*4882a593Smuzhiyun 		rc = -ENOMEM;
2297*4882a593Smuzhiyun 		goto err_policy;
2298*4882a593Smuzhiyun 	}
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun 	rc = policydb_read(&newpolicy->policydb, fp);
2301*4882a593Smuzhiyun 	if (rc)
2302*4882a593Smuzhiyun 		goto err_sidtab;
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun 	newpolicy->policydb.len = len;
2305*4882a593Smuzhiyun 	rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
2306*4882a593Smuzhiyun 				&newpolicy->map);
2307*4882a593Smuzhiyun 	if (rc)
2308*4882a593Smuzhiyun 		goto err_policydb;
2309*4882a593Smuzhiyun 
2310*4882a593Smuzhiyun 	rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
2311*4882a593Smuzhiyun 	if (rc) {
2312*4882a593Smuzhiyun 		pr_err("SELinux:  unable to load the initial SIDs\n");
2313*4882a593Smuzhiyun 		goto err_mapping;
2314*4882a593Smuzhiyun 	}
2315*4882a593Smuzhiyun 
2316*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2317*4882a593Smuzhiyun 		/* First policy load, so no need to preserve state from old policy */
2318*4882a593Smuzhiyun 		load_state->policy = newpolicy;
2319*4882a593Smuzhiyun 		load_state->convert_data = NULL;
2320*4882a593Smuzhiyun 		return 0;
2321*4882a593Smuzhiyun 	}
2322*4882a593Smuzhiyun 
2323*4882a593Smuzhiyun 	oldpolicy = rcu_dereference_protected(state->policy,
2324*4882a593Smuzhiyun 					lockdep_is_held(&state->policy_mutex));
2325*4882a593Smuzhiyun 
2326*4882a593Smuzhiyun 	/* Preserve active boolean values from the old policy */
2327*4882a593Smuzhiyun 	rc = security_preserve_bools(oldpolicy, newpolicy);
2328*4882a593Smuzhiyun 	if (rc) {
2329*4882a593Smuzhiyun 		pr_err("SELinux:  unable to preserve booleans\n");
2330*4882a593Smuzhiyun 		goto err_free_isids;
2331*4882a593Smuzhiyun 	}
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
2334*4882a593Smuzhiyun 	if (!convert_data) {
2335*4882a593Smuzhiyun 		rc = -ENOMEM;
2336*4882a593Smuzhiyun 		goto err_free_isids;
2337*4882a593Smuzhiyun 	}
2338*4882a593Smuzhiyun 
2339*4882a593Smuzhiyun 	/*
2340*4882a593Smuzhiyun 	 * Convert the internal representations of contexts
2341*4882a593Smuzhiyun 	 * in the new SID table.
2342*4882a593Smuzhiyun 	 */
2343*4882a593Smuzhiyun 	convert_data->args.state = state;
2344*4882a593Smuzhiyun 	convert_data->args.oldp = &oldpolicy->policydb;
2345*4882a593Smuzhiyun 	convert_data->args.newp = &newpolicy->policydb;
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun 	convert_data->sidtab_params.func = convert_context;
2348*4882a593Smuzhiyun 	convert_data->sidtab_params.args = &convert_data->args;
2349*4882a593Smuzhiyun 	convert_data->sidtab_params.target = newpolicy->sidtab;
2350*4882a593Smuzhiyun 
2351*4882a593Smuzhiyun 	rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
2352*4882a593Smuzhiyun 	if (rc) {
2353*4882a593Smuzhiyun 		pr_err("SELinux:  unable to convert the internal"
2354*4882a593Smuzhiyun 			" representation of contexts in the new SID"
2355*4882a593Smuzhiyun 			" table\n");
2356*4882a593Smuzhiyun 		goto err_free_convert_data;
2357*4882a593Smuzhiyun 	}
2358*4882a593Smuzhiyun 
2359*4882a593Smuzhiyun 	load_state->policy = newpolicy;
2360*4882a593Smuzhiyun 	load_state->convert_data = convert_data;
2361*4882a593Smuzhiyun 	return 0;
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun err_free_convert_data:
2364*4882a593Smuzhiyun 	kfree(convert_data);
2365*4882a593Smuzhiyun err_free_isids:
2366*4882a593Smuzhiyun 	sidtab_destroy(newpolicy->sidtab);
2367*4882a593Smuzhiyun err_mapping:
2368*4882a593Smuzhiyun 	kfree(newpolicy->map.mapping);
2369*4882a593Smuzhiyun err_policydb:
2370*4882a593Smuzhiyun 	policydb_destroy(&newpolicy->policydb);
2371*4882a593Smuzhiyun err_sidtab:
2372*4882a593Smuzhiyun 	kfree(newpolicy->sidtab);
2373*4882a593Smuzhiyun err_policy:
2374*4882a593Smuzhiyun 	kfree(newpolicy);
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	return rc;
2377*4882a593Smuzhiyun }
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun /**
2380*4882a593Smuzhiyun  * ocontext_to_sid - Helper to safely get sid for an ocontext
2381*4882a593Smuzhiyun  * @sidtab: SID table
2382*4882a593Smuzhiyun  * @c: ocontext structure
2383*4882a593Smuzhiyun  * @index: index of the context entry (0 or 1)
2384*4882a593Smuzhiyun  * @out_sid: pointer to the resulting SID value
2385*4882a593Smuzhiyun  *
2386*4882a593Smuzhiyun  * For all ocontexts except OCON_ISID the SID fields are populated
2387*4882a593Smuzhiyun  * on-demand when needed. Since updating the SID value is an SMP-sensitive
2388*4882a593Smuzhiyun  * operation, this helper must be used to do that safely.
2389*4882a593Smuzhiyun  *
2390*4882a593Smuzhiyun  * WARNING: This function may return -ESTALE, indicating that the caller
2391*4882a593Smuzhiyun  * must retry the operation after re-acquiring the policy pointer!
2392*4882a593Smuzhiyun  */
ocontext_to_sid(struct sidtab * sidtab,struct ocontext * c,size_t index,u32 * out_sid)2393*4882a593Smuzhiyun static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
2394*4882a593Smuzhiyun 			   size_t index, u32 *out_sid)
2395*4882a593Smuzhiyun {
2396*4882a593Smuzhiyun 	int rc;
2397*4882a593Smuzhiyun 	u32 sid;
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun 	/* Ensure the associated sidtab entry is visible to this thread. */
2400*4882a593Smuzhiyun 	sid = smp_load_acquire(&c->sid[index]);
2401*4882a593Smuzhiyun 	if (!sid) {
2402*4882a593Smuzhiyun 		rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
2403*4882a593Smuzhiyun 		if (rc)
2404*4882a593Smuzhiyun 			return rc;
2405*4882a593Smuzhiyun 
2406*4882a593Smuzhiyun 		/*
2407*4882a593Smuzhiyun 		 * Ensure the new sidtab entry is visible to other threads
2408*4882a593Smuzhiyun 		 * when they see the SID.
2409*4882a593Smuzhiyun 		 */
2410*4882a593Smuzhiyun 		smp_store_release(&c->sid[index], sid);
2411*4882a593Smuzhiyun 	}
2412*4882a593Smuzhiyun 	*out_sid = sid;
2413*4882a593Smuzhiyun 	return 0;
2414*4882a593Smuzhiyun }
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun /**
2417*4882a593Smuzhiyun  * security_port_sid - Obtain the SID for a port.
2418*4882a593Smuzhiyun  * @protocol: protocol number
2419*4882a593Smuzhiyun  * @port: port number
2420*4882a593Smuzhiyun  * @out_sid: security identifier
2421*4882a593Smuzhiyun  */
security_port_sid(struct selinux_state * state,u8 protocol,u16 port,u32 * out_sid)2422*4882a593Smuzhiyun int security_port_sid(struct selinux_state *state,
2423*4882a593Smuzhiyun 		      u8 protocol, u16 port, u32 *out_sid)
2424*4882a593Smuzhiyun {
2425*4882a593Smuzhiyun 	struct selinux_policy *policy;
2426*4882a593Smuzhiyun 	struct policydb *policydb;
2427*4882a593Smuzhiyun 	struct sidtab *sidtab;
2428*4882a593Smuzhiyun 	struct ocontext *c;
2429*4882a593Smuzhiyun 	int rc;
2430*4882a593Smuzhiyun 
2431*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2432*4882a593Smuzhiyun 		*out_sid = SECINITSID_PORT;
2433*4882a593Smuzhiyun 		return 0;
2434*4882a593Smuzhiyun 	}
2435*4882a593Smuzhiyun 
2436*4882a593Smuzhiyun retry:
2437*4882a593Smuzhiyun 	rc = 0;
2438*4882a593Smuzhiyun 	rcu_read_lock();
2439*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2440*4882a593Smuzhiyun 	policydb = &policy->policydb;
2441*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	c = policydb->ocontexts[OCON_PORT];
2444*4882a593Smuzhiyun 	while (c) {
2445*4882a593Smuzhiyun 		if (c->u.port.protocol == protocol &&
2446*4882a593Smuzhiyun 		    c->u.port.low_port <= port &&
2447*4882a593Smuzhiyun 		    c->u.port.high_port >= port)
2448*4882a593Smuzhiyun 			break;
2449*4882a593Smuzhiyun 		c = c->next;
2450*4882a593Smuzhiyun 	}
2451*4882a593Smuzhiyun 
2452*4882a593Smuzhiyun 	if (c) {
2453*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
2454*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2455*4882a593Smuzhiyun 			rcu_read_unlock();
2456*4882a593Smuzhiyun 			goto retry;
2457*4882a593Smuzhiyun 		}
2458*4882a593Smuzhiyun 		if (rc)
2459*4882a593Smuzhiyun 			goto out;
2460*4882a593Smuzhiyun 	} else {
2461*4882a593Smuzhiyun 		*out_sid = SECINITSID_PORT;
2462*4882a593Smuzhiyun 	}
2463*4882a593Smuzhiyun 
2464*4882a593Smuzhiyun out:
2465*4882a593Smuzhiyun 	rcu_read_unlock();
2466*4882a593Smuzhiyun 	return rc;
2467*4882a593Smuzhiyun }
2468*4882a593Smuzhiyun 
2469*4882a593Smuzhiyun /**
2470*4882a593Smuzhiyun  * security_pkey_sid - Obtain the SID for a pkey.
2471*4882a593Smuzhiyun  * @subnet_prefix: Subnet Prefix
2472*4882a593Smuzhiyun  * @pkey_num: pkey number
2473*4882a593Smuzhiyun  * @out_sid: security identifier
2474*4882a593Smuzhiyun  */
security_ib_pkey_sid(struct selinux_state * state,u64 subnet_prefix,u16 pkey_num,u32 * out_sid)2475*4882a593Smuzhiyun int security_ib_pkey_sid(struct selinux_state *state,
2476*4882a593Smuzhiyun 			 u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2477*4882a593Smuzhiyun {
2478*4882a593Smuzhiyun 	struct selinux_policy *policy;
2479*4882a593Smuzhiyun 	struct policydb *policydb;
2480*4882a593Smuzhiyun 	struct sidtab *sidtab;
2481*4882a593Smuzhiyun 	struct ocontext *c;
2482*4882a593Smuzhiyun 	int rc;
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2485*4882a593Smuzhiyun 		*out_sid = SECINITSID_UNLABELED;
2486*4882a593Smuzhiyun 		return 0;
2487*4882a593Smuzhiyun 	}
2488*4882a593Smuzhiyun 
2489*4882a593Smuzhiyun retry:
2490*4882a593Smuzhiyun 	rc = 0;
2491*4882a593Smuzhiyun 	rcu_read_lock();
2492*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2493*4882a593Smuzhiyun 	policydb = &policy->policydb;
2494*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2495*4882a593Smuzhiyun 
2496*4882a593Smuzhiyun 	c = policydb->ocontexts[OCON_IBPKEY];
2497*4882a593Smuzhiyun 	while (c) {
2498*4882a593Smuzhiyun 		if (c->u.ibpkey.low_pkey <= pkey_num &&
2499*4882a593Smuzhiyun 		    c->u.ibpkey.high_pkey >= pkey_num &&
2500*4882a593Smuzhiyun 		    c->u.ibpkey.subnet_prefix == subnet_prefix)
2501*4882a593Smuzhiyun 			break;
2502*4882a593Smuzhiyun 
2503*4882a593Smuzhiyun 		c = c->next;
2504*4882a593Smuzhiyun 	}
2505*4882a593Smuzhiyun 
2506*4882a593Smuzhiyun 	if (c) {
2507*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
2508*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2509*4882a593Smuzhiyun 			rcu_read_unlock();
2510*4882a593Smuzhiyun 			goto retry;
2511*4882a593Smuzhiyun 		}
2512*4882a593Smuzhiyun 		if (rc)
2513*4882a593Smuzhiyun 			goto out;
2514*4882a593Smuzhiyun 	} else
2515*4882a593Smuzhiyun 		*out_sid = SECINITSID_UNLABELED;
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun out:
2518*4882a593Smuzhiyun 	rcu_read_unlock();
2519*4882a593Smuzhiyun 	return rc;
2520*4882a593Smuzhiyun }
2521*4882a593Smuzhiyun 
2522*4882a593Smuzhiyun /**
2523*4882a593Smuzhiyun  * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2524*4882a593Smuzhiyun  * @dev_name: device name
2525*4882a593Smuzhiyun  * @port: port number
2526*4882a593Smuzhiyun  * @out_sid: security identifier
2527*4882a593Smuzhiyun  */
security_ib_endport_sid(struct selinux_state * state,const char * dev_name,u8 port_num,u32 * out_sid)2528*4882a593Smuzhiyun int security_ib_endport_sid(struct selinux_state *state,
2529*4882a593Smuzhiyun 			    const char *dev_name, u8 port_num, u32 *out_sid)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun 	struct selinux_policy *policy;
2532*4882a593Smuzhiyun 	struct policydb *policydb;
2533*4882a593Smuzhiyun 	struct sidtab *sidtab;
2534*4882a593Smuzhiyun 	struct ocontext *c;
2535*4882a593Smuzhiyun 	int rc;
2536*4882a593Smuzhiyun 
2537*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2538*4882a593Smuzhiyun 		*out_sid = SECINITSID_UNLABELED;
2539*4882a593Smuzhiyun 		return 0;
2540*4882a593Smuzhiyun 	}
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun retry:
2543*4882a593Smuzhiyun 	rc = 0;
2544*4882a593Smuzhiyun 	rcu_read_lock();
2545*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2546*4882a593Smuzhiyun 	policydb = &policy->policydb;
2547*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2548*4882a593Smuzhiyun 
2549*4882a593Smuzhiyun 	c = policydb->ocontexts[OCON_IBENDPORT];
2550*4882a593Smuzhiyun 	while (c) {
2551*4882a593Smuzhiyun 		if (c->u.ibendport.port == port_num &&
2552*4882a593Smuzhiyun 		    !strncmp(c->u.ibendport.dev_name,
2553*4882a593Smuzhiyun 			     dev_name,
2554*4882a593Smuzhiyun 			     IB_DEVICE_NAME_MAX))
2555*4882a593Smuzhiyun 			break;
2556*4882a593Smuzhiyun 
2557*4882a593Smuzhiyun 		c = c->next;
2558*4882a593Smuzhiyun 	}
2559*4882a593Smuzhiyun 
2560*4882a593Smuzhiyun 	if (c) {
2561*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
2562*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2563*4882a593Smuzhiyun 			rcu_read_unlock();
2564*4882a593Smuzhiyun 			goto retry;
2565*4882a593Smuzhiyun 		}
2566*4882a593Smuzhiyun 		if (rc)
2567*4882a593Smuzhiyun 			goto out;
2568*4882a593Smuzhiyun 	} else
2569*4882a593Smuzhiyun 		*out_sid = SECINITSID_UNLABELED;
2570*4882a593Smuzhiyun 
2571*4882a593Smuzhiyun out:
2572*4882a593Smuzhiyun 	rcu_read_unlock();
2573*4882a593Smuzhiyun 	return rc;
2574*4882a593Smuzhiyun }
2575*4882a593Smuzhiyun 
2576*4882a593Smuzhiyun /**
2577*4882a593Smuzhiyun  * security_netif_sid - Obtain the SID for a network interface.
2578*4882a593Smuzhiyun  * @name: interface name
2579*4882a593Smuzhiyun  * @if_sid: interface SID
2580*4882a593Smuzhiyun  */
security_netif_sid(struct selinux_state * state,char * name,u32 * if_sid)2581*4882a593Smuzhiyun int security_netif_sid(struct selinux_state *state,
2582*4882a593Smuzhiyun 		       char *name, u32 *if_sid)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun 	struct selinux_policy *policy;
2585*4882a593Smuzhiyun 	struct policydb *policydb;
2586*4882a593Smuzhiyun 	struct sidtab *sidtab;
2587*4882a593Smuzhiyun 	int rc;
2588*4882a593Smuzhiyun 	struct ocontext *c;
2589*4882a593Smuzhiyun 
2590*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2591*4882a593Smuzhiyun 		*if_sid = SECINITSID_NETIF;
2592*4882a593Smuzhiyun 		return 0;
2593*4882a593Smuzhiyun 	}
2594*4882a593Smuzhiyun 
2595*4882a593Smuzhiyun retry:
2596*4882a593Smuzhiyun 	rc = 0;
2597*4882a593Smuzhiyun 	rcu_read_lock();
2598*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2599*4882a593Smuzhiyun 	policydb = &policy->policydb;
2600*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2601*4882a593Smuzhiyun 
2602*4882a593Smuzhiyun 	c = policydb->ocontexts[OCON_NETIF];
2603*4882a593Smuzhiyun 	while (c) {
2604*4882a593Smuzhiyun 		if (strcmp(name, c->u.name) == 0)
2605*4882a593Smuzhiyun 			break;
2606*4882a593Smuzhiyun 		c = c->next;
2607*4882a593Smuzhiyun 	}
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun 	if (c) {
2610*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, if_sid);
2611*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2612*4882a593Smuzhiyun 			rcu_read_unlock();
2613*4882a593Smuzhiyun 			goto retry;
2614*4882a593Smuzhiyun 		}
2615*4882a593Smuzhiyun 		if (rc)
2616*4882a593Smuzhiyun 			goto out;
2617*4882a593Smuzhiyun 	} else
2618*4882a593Smuzhiyun 		*if_sid = SECINITSID_NETIF;
2619*4882a593Smuzhiyun 
2620*4882a593Smuzhiyun out:
2621*4882a593Smuzhiyun 	rcu_read_unlock();
2622*4882a593Smuzhiyun 	return rc;
2623*4882a593Smuzhiyun }
2624*4882a593Smuzhiyun 
match_ipv6_addrmask(u32 * input,u32 * addr,u32 * mask)2625*4882a593Smuzhiyun static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
2626*4882a593Smuzhiyun {
2627*4882a593Smuzhiyun 	int i, fail = 0;
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun 	for (i = 0; i < 4; i++)
2630*4882a593Smuzhiyun 		if (addr[i] != (input[i] & mask[i])) {
2631*4882a593Smuzhiyun 			fail = 1;
2632*4882a593Smuzhiyun 			break;
2633*4882a593Smuzhiyun 		}
2634*4882a593Smuzhiyun 
2635*4882a593Smuzhiyun 	return !fail;
2636*4882a593Smuzhiyun }
2637*4882a593Smuzhiyun 
2638*4882a593Smuzhiyun /**
2639*4882a593Smuzhiyun  * security_node_sid - Obtain the SID for a node (host).
2640*4882a593Smuzhiyun  * @domain: communication domain aka address family
2641*4882a593Smuzhiyun  * @addrp: address
2642*4882a593Smuzhiyun  * @addrlen: address length in bytes
2643*4882a593Smuzhiyun  * @out_sid: security identifier
2644*4882a593Smuzhiyun  */
security_node_sid(struct selinux_state * state,u16 domain,void * addrp,u32 addrlen,u32 * out_sid)2645*4882a593Smuzhiyun int security_node_sid(struct selinux_state *state,
2646*4882a593Smuzhiyun 		      u16 domain,
2647*4882a593Smuzhiyun 		      void *addrp,
2648*4882a593Smuzhiyun 		      u32 addrlen,
2649*4882a593Smuzhiyun 		      u32 *out_sid)
2650*4882a593Smuzhiyun {
2651*4882a593Smuzhiyun 	struct selinux_policy *policy;
2652*4882a593Smuzhiyun 	struct policydb *policydb;
2653*4882a593Smuzhiyun 	struct sidtab *sidtab;
2654*4882a593Smuzhiyun 	int rc;
2655*4882a593Smuzhiyun 	struct ocontext *c;
2656*4882a593Smuzhiyun 
2657*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2658*4882a593Smuzhiyun 		*out_sid = SECINITSID_NODE;
2659*4882a593Smuzhiyun 		return 0;
2660*4882a593Smuzhiyun 	}
2661*4882a593Smuzhiyun 
2662*4882a593Smuzhiyun retry:
2663*4882a593Smuzhiyun 	rcu_read_lock();
2664*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2665*4882a593Smuzhiyun 	policydb = &policy->policydb;
2666*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 	switch (domain) {
2669*4882a593Smuzhiyun 	case AF_INET: {
2670*4882a593Smuzhiyun 		u32 addr;
2671*4882a593Smuzhiyun 
2672*4882a593Smuzhiyun 		rc = -EINVAL;
2673*4882a593Smuzhiyun 		if (addrlen != sizeof(u32))
2674*4882a593Smuzhiyun 			goto out;
2675*4882a593Smuzhiyun 
2676*4882a593Smuzhiyun 		addr = *((u32 *)addrp);
2677*4882a593Smuzhiyun 
2678*4882a593Smuzhiyun 		c = policydb->ocontexts[OCON_NODE];
2679*4882a593Smuzhiyun 		while (c) {
2680*4882a593Smuzhiyun 			if (c->u.node.addr == (addr & c->u.node.mask))
2681*4882a593Smuzhiyun 				break;
2682*4882a593Smuzhiyun 			c = c->next;
2683*4882a593Smuzhiyun 		}
2684*4882a593Smuzhiyun 		break;
2685*4882a593Smuzhiyun 	}
2686*4882a593Smuzhiyun 
2687*4882a593Smuzhiyun 	case AF_INET6:
2688*4882a593Smuzhiyun 		rc = -EINVAL;
2689*4882a593Smuzhiyun 		if (addrlen != sizeof(u64) * 2)
2690*4882a593Smuzhiyun 			goto out;
2691*4882a593Smuzhiyun 		c = policydb->ocontexts[OCON_NODE6];
2692*4882a593Smuzhiyun 		while (c) {
2693*4882a593Smuzhiyun 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
2694*4882a593Smuzhiyun 						c->u.node6.mask))
2695*4882a593Smuzhiyun 				break;
2696*4882a593Smuzhiyun 			c = c->next;
2697*4882a593Smuzhiyun 		}
2698*4882a593Smuzhiyun 		break;
2699*4882a593Smuzhiyun 
2700*4882a593Smuzhiyun 	default:
2701*4882a593Smuzhiyun 		rc = 0;
2702*4882a593Smuzhiyun 		*out_sid = SECINITSID_NODE;
2703*4882a593Smuzhiyun 		goto out;
2704*4882a593Smuzhiyun 	}
2705*4882a593Smuzhiyun 
2706*4882a593Smuzhiyun 	if (c) {
2707*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, out_sid);
2708*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2709*4882a593Smuzhiyun 			rcu_read_unlock();
2710*4882a593Smuzhiyun 			goto retry;
2711*4882a593Smuzhiyun 		}
2712*4882a593Smuzhiyun 		if (rc)
2713*4882a593Smuzhiyun 			goto out;
2714*4882a593Smuzhiyun 	} else {
2715*4882a593Smuzhiyun 		*out_sid = SECINITSID_NODE;
2716*4882a593Smuzhiyun 	}
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun 	rc = 0;
2719*4882a593Smuzhiyun out:
2720*4882a593Smuzhiyun 	rcu_read_unlock();
2721*4882a593Smuzhiyun 	return rc;
2722*4882a593Smuzhiyun }
2723*4882a593Smuzhiyun 
2724*4882a593Smuzhiyun #define SIDS_NEL 25
2725*4882a593Smuzhiyun 
2726*4882a593Smuzhiyun /**
2727*4882a593Smuzhiyun  * security_get_user_sids - Obtain reachable SIDs for a user.
2728*4882a593Smuzhiyun  * @fromsid: starting SID
2729*4882a593Smuzhiyun  * @username: username
2730*4882a593Smuzhiyun  * @sids: array of reachable SIDs for user
2731*4882a593Smuzhiyun  * @nel: number of elements in @sids
2732*4882a593Smuzhiyun  *
2733*4882a593Smuzhiyun  * Generate the set of SIDs for legal security contexts
2734*4882a593Smuzhiyun  * for a given user that can be reached by @fromsid.
2735*4882a593Smuzhiyun  * Set *@sids to point to a dynamically allocated
2736*4882a593Smuzhiyun  * array containing the set of SIDs.  Set *@nel to the
2737*4882a593Smuzhiyun  * number of elements in the array.
2738*4882a593Smuzhiyun  */
2739*4882a593Smuzhiyun 
security_get_user_sids(struct selinux_state * state,u32 fromsid,char * username,u32 ** sids,u32 * nel)2740*4882a593Smuzhiyun int security_get_user_sids(struct selinux_state *state,
2741*4882a593Smuzhiyun 			   u32 fromsid,
2742*4882a593Smuzhiyun 			   char *username,
2743*4882a593Smuzhiyun 			   u32 **sids,
2744*4882a593Smuzhiyun 			   u32 *nel)
2745*4882a593Smuzhiyun {
2746*4882a593Smuzhiyun 	struct selinux_policy *policy;
2747*4882a593Smuzhiyun 	struct policydb *policydb;
2748*4882a593Smuzhiyun 	struct sidtab *sidtab;
2749*4882a593Smuzhiyun 	struct context *fromcon, usercon;
2750*4882a593Smuzhiyun 	u32 *mysids = NULL, *mysids2, sid;
2751*4882a593Smuzhiyun 	u32 i, j, mynel, maxnel = SIDS_NEL;
2752*4882a593Smuzhiyun 	struct user_datum *user;
2753*4882a593Smuzhiyun 	struct role_datum *role;
2754*4882a593Smuzhiyun 	struct ebitmap_node *rnode, *tnode;
2755*4882a593Smuzhiyun 	int rc;
2756*4882a593Smuzhiyun 
2757*4882a593Smuzhiyun 	*sids = NULL;
2758*4882a593Smuzhiyun 	*nel = 0;
2759*4882a593Smuzhiyun 
2760*4882a593Smuzhiyun 	if (!selinux_initialized(state))
2761*4882a593Smuzhiyun 		return 0;
2762*4882a593Smuzhiyun 
2763*4882a593Smuzhiyun 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
2764*4882a593Smuzhiyun 	if (!mysids)
2765*4882a593Smuzhiyun 		return -ENOMEM;
2766*4882a593Smuzhiyun 
2767*4882a593Smuzhiyun retry:
2768*4882a593Smuzhiyun 	mynel = 0;
2769*4882a593Smuzhiyun 	rcu_read_lock();
2770*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2771*4882a593Smuzhiyun 	policydb = &policy->policydb;
2772*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2773*4882a593Smuzhiyun 
2774*4882a593Smuzhiyun 	context_init(&usercon);
2775*4882a593Smuzhiyun 
2776*4882a593Smuzhiyun 	rc = -EINVAL;
2777*4882a593Smuzhiyun 	fromcon = sidtab_search(sidtab, fromsid);
2778*4882a593Smuzhiyun 	if (!fromcon)
2779*4882a593Smuzhiyun 		goto out_unlock;
2780*4882a593Smuzhiyun 
2781*4882a593Smuzhiyun 	rc = -EINVAL;
2782*4882a593Smuzhiyun 	user = symtab_search(&policydb->p_users, username);
2783*4882a593Smuzhiyun 	if (!user)
2784*4882a593Smuzhiyun 		goto out_unlock;
2785*4882a593Smuzhiyun 
2786*4882a593Smuzhiyun 	usercon.user = user->value;
2787*4882a593Smuzhiyun 
2788*4882a593Smuzhiyun 	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2789*4882a593Smuzhiyun 		role = policydb->role_val_to_struct[i];
2790*4882a593Smuzhiyun 		usercon.role = i + 1;
2791*4882a593Smuzhiyun 		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
2792*4882a593Smuzhiyun 			usercon.type = j + 1;
2793*4882a593Smuzhiyun 
2794*4882a593Smuzhiyun 			if (mls_setup_user_range(policydb, fromcon, user,
2795*4882a593Smuzhiyun 						 &usercon))
2796*4882a593Smuzhiyun 				continue;
2797*4882a593Smuzhiyun 
2798*4882a593Smuzhiyun 			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
2799*4882a593Smuzhiyun 			if (rc == -ESTALE) {
2800*4882a593Smuzhiyun 				rcu_read_unlock();
2801*4882a593Smuzhiyun 				goto retry;
2802*4882a593Smuzhiyun 			}
2803*4882a593Smuzhiyun 			if (rc)
2804*4882a593Smuzhiyun 				goto out_unlock;
2805*4882a593Smuzhiyun 			if (mynel < maxnel) {
2806*4882a593Smuzhiyun 				mysids[mynel++] = sid;
2807*4882a593Smuzhiyun 			} else {
2808*4882a593Smuzhiyun 				rc = -ENOMEM;
2809*4882a593Smuzhiyun 				maxnel += SIDS_NEL;
2810*4882a593Smuzhiyun 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
2811*4882a593Smuzhiyun 				if (!mysids2)
2812*4882a593Smuzhiyun 					goto out_unlock;
2813*4882a593Smuzhiyun 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
2814*4882a593Smuzhiyun 				kfree(mysids);
2815*4882a593Smuzhiyun 				mysids = mysids2;
2816*4882a593Smuzhiyun 				mysids[mynel++] = sid;
2817*4882a593Smuzhiyun 			}
2818*4882a593Smuzhiyun 		}
2819*4882a593Smuzhiyun 	}
2820*4882a593Smuzhiyun 	rc = 0;
2821*4882a593Smuzhiyun out_unlock:
2822*4882a593Smuzhiyun 	rcu_read_unlock();
2823*4882a593Smuzhiyun 	if (rc || !mynel) {
2824*4882a593Smuzhiyun 		kfree(mysids);
2825*4882a593Smuzhiyun 		return rc;
2826*4882a593Smuzhiyun 	}
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun 	rc = -ENOMEM;
2829*4882a593Smuzhiyun 	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
2830*4882a593Smuzhiyun 	if (!mysids2) {
2831*4882a593Smuzhiyun 		kfree(mysids);
2832*4882a593Smuzhiyun 		return rc;
2833*4882a593Smuzhiyun 	}
2834*4882a593Smuzhiyun 	for (i = 0, j = 0; i < mynel; i++) {
2835*4882a593Smuzhiyun 		struct av_decision dummy_avd;
2836*4882a593Smuzhiyun 		rc = avc_has_perm_noaudit(state,
2837*4882a593Smuzhiyun 					  fromsid, mysids[i],
2838*4882a593Smuzhiyun 					  SECCLASS_PROCESS, /* kernel value */
2839*4882a593Smuzhiyun 					  PROCESS__TRANSITION, AVC_STRICT,
2840*4882a593Smuzhiyun 					  &dummy_avd);
2841*4882a593Smuzhiyun 		if (!rc)
2842*4882a593Smuzhiyun 			mysids2[j++] = mysids[i];
2843*4882a593Smuzhiyun 		cond_resched();
2844*4882a593Smuzhiyun 	}
2845*4882a593Smuzhiyun 	kfree(mysids);
2846*4882a593Smuzhiyun 	*sids = mysids2;
2847*4882a593Smuzhiyun 	*nel = j;
2848*4882a593Smuzhiyun 	return 0;
2849*4882a593Smuzhiyun }
2850*4882a593Smuzhiyun 
2851*4882a593Smuzhiyun /**
2852*4882a593Smuzhiyun  * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
2853*4882a593Smuzhiyun  * @fstype: filesystem type
2854*4882a593Smuzhiyun  * @path: path from root of mount
2855*4882a593Smuzhiyun  * @sclass: file security class
2856*4882a593Smuzhiyun  * @sid: SID for path
2857*4882a593Smuzhiyun  *
2858*4882a593Smuzhiyun  * Obtain a SID to use for a file in a filesystem that
2859*4882a593Smuzhiyun  * cannot support xattr or use a fixed labeling behavior like
2860*4882a593Smuzhiyun  * transition SIDs or task SIDs.
2861*4882a593Smuzhiyun  *
2862*4882a593Smuzhiyun  * WARNING: This function may return -ESTALE, indicating that the caller
2863*4882a593Smuzhiyun  * must retry the operation after re-acquiring the policy pointer!
2864*4882a593Smuzhiyun  */
__security_genfs_sid(struct selinux_policy * policy,const char * fstype,char * path,u16 orig_sclass,u32 * sid)2865*4882a593Smuzhiyun static inline int __security_genfs_sid(struct selinux_policy *policy,
2866*4882a593Smuzhiyun 				       const char *fstype,
2867*4882a593Smuzhiyun 				       char *path,
2868*4882a593Smuzhiyun 				       u16 orig_sclass,
2869*4882a593Smuzhiyun 				       u32 *sid)
2870*4882a593Smuzhiyun {
2871*4882a593Smuzhiyun 	struct policydb *policydb = &policy->policydb;
2872*4882a593Smuzhiyun 	struct sidtab *sidtab = policy->sidtab;
2873*4882a593Smuzhiyun 	int len;
2874*4882a593Smuzhiyun 	u16 sclass;
2875*4882a593Smuzhiyun 	struct genfs *genfs;
2876*4882a593Smuzhiyun 	struct ocontext *c;
2877*4882a593Smuzhiyun 	int cmp = 0;
2878*4882a593Smuzhiyun 
2879*4882a593Smuzhiyun 	while (path[0] == '/' && path[1] == '/')
2880*4882a593Smuzhiyun 		path++;
2881*4882a593Smuzhiyun 
2882*4882a593Smuzhiyun 	sclass = unmap_class(&policy->map, orig_sclass);
2883*4882a593Smuzhiyun 	*sid = SECINITSID_UNLABELED;
2884*4882a593Smuzhiyun 
2885*4882a593Smuzhiyun 	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
2886*4882a593Smuzhiyun 		cmp = strcmp(fstype, genfs->fstype);
2887*4882a593Smuzhiyun 		if (cmp <= 0)
2888*4882a593Smuzhiyun 			break;
2889*4882a593Smuzhiyun 	}
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 	if (!genfs || cmp)
2892*4882a593Smuzhiyun 		return -ENOENT;
2893*4882a593Smuzhiyun 
2894*4882a593Smuzhiyun 	for (c = genfs->head; c; c = c->next) {
2895*4882a593Smuzhiyun 		len = strlen(c->u.name);
2896*4882a593Smuzhiyun 		if ((!c->v.sclass || sclass == c->v.sclass) &&
2897*4882a593Smuzhiyun 		    (strncmp(c->u.name, path, len) == 0))
2898*4882a593Smuzhiyun 			break;
2899*4882a593Smuzhiyun 	}
2900*4882a593Smuzhiyun 
2901*4882a593Smuzhiyun 	if (!c)
2902*4882a593Smuzhiyun 		return -ENOENT;
2903*4882a593Smuzhiyun 
2904*4882a593Smuzhiyun 	return ocontext_to_sid(sidtab, c, 0, sid);
2905*4882a593Smuzhiyun }
2906*4882a593Smuzhiyun 
2907*4882a593Smuzhiyun /**
2908*4882a593Smuzhiyun  * security_genfs_sid - Obtain a SID for a file in a filesystem
2909*4882a593Smuzhiyun  * @fstype: filesystem type
2910*4882a593Smuzhiyun  * @path: path from root of mount
2911*4882a593Smuzhiyun  * @sclass: file security class
2912*4882a593Smuzhiyun  * @sid: SID for path
2913*4882a593Smuzhiyun  *
2914*4882a593Smuzhiyun  * Acquire policy_rwlock before calling __security_genfs_sid() and release
2915*4882a593Smuzhiyun  * it afterward.
2916*4882a593Smuzhiyun  */
security_genfs_sid(struct selinux_state * state,const char * fstype,char * path,u16 orig_sclass,u32 * sid)2917*4882a593Smuzhiyun int security_genfs_sid(struct selinux_state *state,
2918*4882a593Smuzhiyun 		       const char *fstype,
2919*4882a593Smuzhiyun 		       char *path,
2920*4882a593Smuzhiyun 		       u16 orig_sclass,
2921*4882a593Smuzhiyun 		       u32 *sid)
2922*4882a593Smuzhiyun {
2923*4882a593Smuzhiyun 	struct selinux_policy *policy;
2924*4882a593Smuzhiyun 	int retval;
2925*4882a593Smuzhiyun 
2926*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2927*4882a593Smuzhiyun 		*sid = SECINITSID_UNLABELED;
2928*4882a593Smuzhiyun 		return 0;
2929*4882a593Smuzhiyun 	}
2930*4882a593Smuzhiyun 
2931*4882a593Smuzhiyun 	do {
2932*4882a593Smuzhiyun 		rcu_read_lock();
2933*4882a593Smuzhiyun 		policy = rcu_dereference(state->policy);
2934*4882a593Smuzhiyun 		retval = __security_genfs_sid(policy, fstype, path,
2935*4882a593Smuzhiyun 					      orig_sclass, sid);
2936*4882a593Smuzhiyun 		rcu_read_unlock();
2937*4882a593Smuzhiyun 	} while (retval == -ESTALE);
2938*4882a593Smuzhiyun 	return retval;
2939*4882a593Smuzhiyun }
2940*4882a593Smuzhiyun 
selinux_policy_genfs_sid(struct selinux_policy * policy,const char * fstype,char * path,u16 orig_sclass,u32 * sid)2941*4882a593Smuzhiyun int selinux_policy_genfs_sid(struct selinux_policy *policy,
2942*4882a593Smuzhiyun 			const char *fstype,
2943*4882a593Smuzhiyun 			char *path,
2944*4882a593Smuzhiyun 			u16 orig_sclass,
2945*4882a593Smuzhiyun 			u32 *sid)
2946*4882a593Smuzhiyun {
2947*4882a593Smuzhiyun 	/* no lock required, policy is not yet accessible by other threads */
2948*4882a593Smuzhiyun 	return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
2949*4882a593Smuzhiyun }
2950*4882a593Smuzhiyun 
2951*4882a593Smuzhiyun /**
2952*4882a593Smuzhiyun  * security_fs_use - Determine how to handle labeling for a filesystem.
2953*4882a593Smuzhiyun  * @sb: superblock in question
2954*4882a593Smuzhiyun  */
security_fs_use(struct selinux_state * state,struct super_block * sb)2955*4882a593Smuzhiyun int security_fs_use(struct selinux_state *state, struct super_block *sb)
2956*4882a593Smuzhiyun {
2957*4882a593Smuzhiyun 	struct selinux_policy *policy;
2958*4882a593Smuzhiyun 	struct policydb *policydb;
2959*4882a593Smuzhiyun 	struct sidtab *sidtab;
2960*4882a593Smuzhiyun 	int rc;
2961*4882a593Smuzhiyun 	struct ocontext *c;
2962*4882a593Smuzhiyun 	struct superblock_security_struct *sbsec = sb->s_security;
2963*4882a593Smuzhiyun 	const char *fstype = sb->s_type->name;
2964*4882a593Smuzhiyun 
2965*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
2966*4882a593Smuzhiyun 		sbsec->behavior = SECURITY_FS_USE_NONE;
2967*4882a593Smuzhiyun 		sbsec->sid = SECINITSID_UNLABELED;
2968*4882a593Smuzhiyun 		return 0;
2969*4882a593Smuzhiyun 	}
2970*4882a593Smuzhiyun 
2971*4882a593Smuzhiyun retry:
2972*4882a593Smuzhiyun 	rc = 0;
2973*4882a593Smuzhiyun 	rcu_read_lock();
2974*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
2975*4882a593Smuzhiyun 	policydb = &policy->policydb;
2976*4882a593Smuzhiyun 	sidtab = policy->sidtab;
2977*4882a593Smuzhiyun 
2978*4882a593Smuzhiyun 	c = policydb->ocontexts[OCON_FSUSE];
2979*4882a593Smuzhiyun 	while (c) {
2980*4882a593Smuzhiyun 		if (strcmp(fstype, c->u.name) == 0)
2981*4882a593Smuzhiyun 			break;
2982*4882a593Smuzhiyun 		c = c->next;
2983*4882a593Smuzhiyun 	}
2984*4882a593Smuzhiyun 
2985*4882a593Smuzhiyun 	if (c) {
2986*4882a593Smuzhiyun 		sbsec->behavior = c->v.behavior;
2987*4882a593Smuzhiyun 		rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
2988*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2989*4882a593Smuzhiyun 			rcu_read_unlock();
2990*4882a593Smuzhiyun 			goto retry;
2991*4882a593Smuzhiyun 		}
2992*4882a593Smuzhiyun 		if (rc)
2993*4882a593Smuzhiyun 			goto out;
2994*4882a593Smuzhiyun 	} else {
2995*4882a593Smuzhiyun 		rc = __security_genfs_sid(policy, fstype, "/",
2996*4882a593Smuzhiyun 					SECCLASS_DIR, &sbsec->sid);
2997*4882a593Smuzhiyun 		if (rc == -ESTALE) {
2998*4882a593Smuzhiyun 			rcu_read_unlock();
2999*4882a593Smuzhiyun 			goto retry;
3000*4882a593Smuzhiyun 		}
3001*4882a593Smuzhiyun 		if (rc) {
3002*4882a593Smuzhiyun 			sbsec->behavior = SECURITY_FS_USE_NONE;
3003*4882a593Smuzhiyun 			rc = 0;
3004*4882a593Smuzhiyun 		} else {
3005*4882a593Smuzhiyun 			sbsec->behavior = SECURITY_FS_USE_GENFS;
3006*4882a593Smuzhiyun 		}
3007*4882a593Smuzhiyun 	}
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun out:
3010*4882a593Smuzhiyun 	rcu_read_unlock();
3011*4882a593Smuzhiyun 	return rc;
3012*4882a593Smuzhiyun }
3013*4882a593Smuzhiyun 
security_get_bools(struct selinux_policy * policy,u32 * len,char *** names,int ** values)3014*4882a593Smuzhiyun int security_get_bools(struct selinux_policy *policy,
3015*4882a593Smuzhiyun 		       u32 *len, char ***names, int **values)
3016*4882a593Smuzhiyun {
3017*4882a593Smuzhiyun 	struct policydb *policydb;
3018*4882a593Smuzhiyun 	u32 i;
3019*4882a593Smuzhiyun 	int rc;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun 	policydb = &policy->policydb;
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	*names = NULL;
3024*4882a593Smuzhiyun 	*values = NULL;
3025*4882a593Smuzhiyun 
3026*4882a593Smuzhiyun 	rc = 0;
3027*4882a593Smuzhiyun 	*len = policydb->p_bools.nprim;
3028*4882a593Smuzhiyun 	if (!*len)
3029*4882a593Smuzhiyun 		goto out;
3030*4882a593Smuzhiyun 
3031*4882a593Smuzhiyun 	rc = -ENOMEM;
3032*4882a593Smuzhiyun 	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
3033*4882a593Smuzhiyun 	if (!*names)
3034*4882a593Smuzhiyun 		goto err;
3035*4882a593Smuzhiyun 
3036*4882a593Smuzhiyun 	rc = -ENOMEM;
3037*4882a593Smuzhiyun 	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
3038*4882a593Smuzhiyun 	if (!*values)
3039*4882a593Smuzhiyun 		goto err;
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun 	for (i = 0; i < *len; i++) {
3042*4882a593Smuzhiyun 		(*values)[i] = policydb->bool_val_to_struct[i]->state;
3043*4882a593Smuzhiyun 
3044*4882a593Smuzhiyun 		rc = -ENOMEM;
3045*4882a593Smuzhiyun 		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
3046*4882a593Smuzhiyun 				      GFP_ATOMIC);
3047*4882a593Smuzhiyun 		if (!(*names)[i])
3048*4882a593Smuzhiyun 			goto err;
3049*4882a593Smuzhiyun 	}
3050*4882a593Smuzhiyun 	rc = 0;
3051*4882a593Smuzhiyun out:
3052*4882a593Smuzhiyun 	return rc;
3053*4882a593Smuzhiyun err:
3054*4882a593Smuzhiyun 	if (*names) {
3055*4882a593Smuzhiyun 		for (i = 0; i < *len; i++)
3056*4882a593Smuzhiyun 			kfree((*names)[i]);
3057*4882a593Smuzhiyun 		kfree(*names);
3058*4882a593Smuzhiyun 	}
3059*4882a593Smuzhiyun 	kfree(*values);
3060*4882a593Smuzhiyun 	*len = 0;
3061*4882a593Smuzhiyun 	*names = NULL;
3062*4882a593Smuzhiyun 	*values = NULL;
3063*4882a593Smuzhiyun 	goto out;
3064*4882a593Smuzhiyun }
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun 
security_set_bools(struct selinux_state * state,u32 len,int * values)3067*4882a593Smuzhiyun int security_set_bools(struct selinux_state *state, u32 len, int *values)
3068*4882a593Smuzhiyun {
3069*4882a593Smuzhiyun 	struct selinux_policy *newpolicy, *oldpolicy;
3070*4882a593Smuzhiyun 	int rc;
3071*4882a593Smuzhiyun 	u32 i, seqno = 0;
3072*4882a593Smuzhiyun 
3073*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3074*4882a593Smuzhiyun 		return -EINVAL;
3075*4882a593Smuzhiyun 
3076*4882a593Smuzhiyun 	oldpolicy = rcu_dereference_protected(state->policy,
3077*4882a593Smuzhiyun 					lockdep_is_held(&state->policy_mutex));
3078*4882a593Smuzhiyun 
3079*4882a593Smuzhiyun 	/* Consistency check on number of booleans, should never fail */
3080*4882a593Smuzhiyun 	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
3081*4882a593Smuzhiyun 		return -EINVAL;
3082*4882a593Smuzhiyun 
3083*4882a593Smuzhiyun 	newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
3084*4882a593Smuzhiyun 	if (!newpolicy)
3085*4882a593Smuzhiyun 		return -ENOMEM;
3086*4882a593Smuzhiyun 
3087*4882a593Smuzhiyun 	/*
3088*4882a593Smuzhiyun 	 * Deep copy only the parts of the policydb that might be
3089*4882a593Smuzhiyun 	 * modified as a result of changing booleans.
3090*4882a593Smuzhiyun 	 */
3091*4882a593Smuzhiyun 	rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
3092*4882a593Smuzhiyun 	if (rc) {
3093*4882a593Smuzhiyun 		kfree(newpolicy);
3094*4882a593Smuzhiyun 		return -ENOMEM;
3095*4882a593Smuzhiyun 	}
3096*4882a593Smuzhiyun 
3097*4882a593Smuzhiyun 	/* Update the boolean states in the copy */
3098*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
3099*4882a593Smuzhiyun 		int new_state = !!values[i];
3100*4882a593Smuzhiyun 		int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
3101*4882a593Smuzhiyun 
3102*4882a593Smuzhiyun 		if (new_state != old_state) {
3103*4882a593Smuzhiyun 			audit_log(audit_context(), GFP_ATOMIC,
3104*4882a593Smuzhiyun 				AUDIT_MAC_CONFIG_CHANGE,
3105*4882a593Smuzhiyun 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
3106*4882a593Smuzhiyun 				sym_name(&newpolicy->policydb, SYM_BOOLS, i),
3107*4882a593Smuzhiyun 				new_state,
3108*4882a593Smuzhiyun 				old_state,
3109*4882a593Smuzhiyun 				from_kuid(&init_user_ns, audit_get_loginuid(current)),
3110*4882a593Smuzhiyun 				audit_get_sessionid(current));
3111*4882a593Smuzhiyun 			newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
3112*4882a593Smuzhiyun 		}
3113*4882a593Smuzhiyun 	}
3114*4882a593Smuzhiyun 
3115*4882a593Smuzhiyun 	/* Re-evaluate the conditional rules in the copy */
3116*4882a593Smuzhiyun 	evaluate_cond_nodes(&newpolicy->policydb);
3117*4882a593Smuzhiyun 
3118*4882a593Smuzhiyun 	/* Set latest granting seqno for new policy */
3119*4882a593Smuzhiyun 	newpolicy->latest_granting = oldpolicy->latest_granting + 1;
3120*4882a593Smuzhiyun 	seqno = newpolicy->latest_granting;
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun 	/* Install the new policy */
3123*4882a593Smuzhiyun 	rcu_assign_pointer(state->policy, newpolicy);
3124*4882a593Smuzhiyun 
3125*4882a593Smuzhiyun 	/*
3126*4882a593Smuzhiyun 	 * Free the conditional portions of the old policydb
3127*4882a593Smuzhiyun 	 * that were copied for the new policy, and the oldpolicy
3128*4882a593Smuzhiyun 	 * structure itself but not what it references.
3129*4882a593Smuzhiyun 	 */
3130*4882a593Smuzhiyun 	synchronize_rcu();
3131*4882a593Smuzhiyun 	selinux_policy_cond_free(oldpolicy);
3132*4882a593Smuzhiyun 
3133*4882a593Smuzhiyun 	/* Notify others of the policy change */
3134*4882a593Smuzhiyun 	selinux_notify_policy_change(state, seqno);
3135*4882a593Smuzhiyun 	return 0;
3136*4882a593Smuzhiyun }
3137*4882a593Smuzhiyun 
security_get_bool_value(struct selinux_state * state,u32 index)3138*4882a593Smuzhiyun int security_get_bool_value(struct selinux_state *state,
3139*4882a593Smuzhiyun 			    u32 index)
3140*4882a593Smuzhiyun {
3141*4882a593Smuzhiyun 	struct selinux_policy *policy;
3142*4882a593Smuzhiyun 	struct policydb *policydb;
3143*4882a593Smuzhiyun 	int rc;
3144*4882a593Smuzhiyun 	u32 len;
3145*4882a593Smuzhiyun 
3146*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3147*4882a593Smuzhiyun 		return 0;
3148*4882a593Smuzhiyun 
3149*4882a593Smuzhiyun 	rcu_read_lock();
3150*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3151*4882a593Smuzhiyun 	policydb = &policy->policydb;
3152*4882a593Smuzhiyun 
3153*4882a593Smuzhiyun 	rc = -EFAULT;
3154*4882a593Smuzhiyun 	len = policydb->p_bools.nprim;
3155*4882a593Smuzhiyun 	if (index >= len)
3156*4882a593Smuzhiyun 		goto out;
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun 	rc = policydb->bool_val_to_struct[index]->state;
3159*4882a593Smuzhiyun out:
3160*4882a593Smuzhiyun 	rcu_read_unlock();
3161*4882a593Smuzhiyun 	return rc;
3162*4882a593Smuzhiyun }
3163*4882a593Smuzhiyun 
security_preserve_bools(struct selinux_policy * oldpolicy,struct selinux_policy * newpolicy)3164*4882a593Smuzhiyun static int security_preserve_bools(struct selinux_policy *oldpolicy,
3165*4882a593Smuzhiyun 				struct selinux_policy *newpolicy)
3166*4882a593Smuzhiyun {
3167*4882a593Smuzhiyun 	int rc, *bvalues = NULL;
3168*4882a593Smuzhiyun 	char **bnames = NULL;
3169*4882a593Smuzhiyun 	struct cond_bool_datum *booldatum;
3170*4882a593Smuzhiyun 	u32 i, nbools = 0;
3171*4882a593Smuzhiyun 
3172*4882a593Smuzhiyun 	rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
3173*4882a593Smuzhiyun 	if (rc)
3174*4882a593Smuzhiyun 		goto out;
3175*4882a593Smuzhiyun 	for (i = 0; i < nbools; i++) {
3176*4882a593Smuzhiyun 		booldatum = symtab_search(&newpolicy->policydb.p_bools,
3177*4882a593Smuzhiyun 					bnames[i]);
3178*4882a593Smuzhiyun 		if (booldatum)
3179*4882a593Smuzhiyun 			booldatum->state = bvalues[i];
3180*4882a593Smuzhiyun 	}
3181*4882a593Smuzhiyun 	evaluate_cond_nodes(&newpolicy->policydb);
3182*4882a593Smuzhiyun 
3183*4882a593Smuzhiyun out:
3184*4882a593Smuzhiyun 	if (bnames) {
3185*4882a593Smuzhiyun 		for (i = 0; i < nbools; i++)
3186*4882a593Smuzhiyun 			kfree(bnames[i]);
3187*4882a593Smuzhiyun 	}
3188*4882a593Smuzhiyun 	kfree(bnames);
3189*4882a593Smuzhiyun 	kfree(bvalues);
3190*4882a593Smuzhiyun 	return rc;
3191*4882a593Smuzhiyun }
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun /*
3194*4882a593Smuzhiyun  * security_sid_mls_copy() - computes a new sid based on the given
3195*4882a593Smuzhiyun  * sid and the mls portion of mls_sid.
3196*4882a593Smuzhiyun  */
security_sid_mls_copy(struct selinux_state * state,u32 sid,u32 mls_sid,u32 * new_sid)3197*4882a593Smuzhiyun int security_sid_mls_copy(struct selinux_state *state,
3198*4882a593Smuzhiyun 			  u32 sid, u32 mls_sid, u32 *new_sid)
3199*4882a593Smuzhiyun {
3200*4882a593Smuzhiyun 	struct selinux_policy *policy;
3201*4882a593Smuzhiyun 	struct policydb *policydb;
3202*4882a593Smuzhiyun 	struct sidtab *sidtab;
3203*4882a593Smuzhiyun 	struct context *context1;
3204*4882a593Smuzhiyun 	struct context *context2;
3205*4882a593Smuzhiyun 	struct context newcon;
3206*4882a593Smuzhiyun 	char *s;
3207*4882a593Smuzhiyun 	u32 len;
3208*4882a593Smuzhiyun 	int rc;
3209*4882a593Smuzhiyun 
3210*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
3211*4882a593Smuzhiyun 		*new_sid = sid;
3212*4882a593Smuzhiyun 		return 0;
3213*4882a593Smuzhiyun 	}
3214*4882a593Smuzhiyun 
3215*4882a593Smuzhiyun retry:
3216*4882a593Smuzhiyun 	rc = 0;
3217*4882a593Smuzhiyun 	context_init(&newcon);
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun 	rcu_read_lock();
3220*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3221*4882a593Smuzhiyun 	policydb = &policy->policydb;
3222*4882a593Smuzhiyun 	sidtab = policy->sidtab;
3223*4882a593Smuzhiyun 
3224*4882a593Smuzhiyun 	if (!policydb->mls_enabled) {
3225*4882a593Smuzhiyun 		*new_sid = sid;
3226*4882a593Smuzhiyun 		goto out_unlock;
3227*4882a593Smuzhiyun 	}
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun 	rc = -EINVAL;
3230*4882a593Smuzhiyun 	context1 = sidtab_search(sidtab, sid);
3231*4882a593Smuzhiyun 	if (!context1) {
3232*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3233*4882a593Smuzhiyun 			__func__, sid);
3234*4882a593Smuzhiyun 		goto out_unlock;
3235*4882a593Smuzhiyun 	}
3236*4882a593Smuzhiyun 
3237*4882a593Smuzhiyun 	rc = -EINVAL;
3238*4882a593Smuzhiyun 	context2 = sidtab_search(sidtab, mls_sid);
3239*4882a593Smuzhiyun 	if (!context2) {
3240*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3241*4882a593Smuzhiyun 			__func__, mls_sid);
3242*4882a593Smuzhiyun 		goto out_unlock;
3243*4882a593Smuzhiyun 	}
3244*4882a593Smuzhiyun 
3245*4882a593Smuzhiyun 	newcon.user = context1->user;
3246*4882a593Smuzhiyun 	newcon.role = context1->role;
3247*4882a593Smuzhiyun 	newcon.type = context1->type;
3248*4882a593Smuzhiyun 	rc = mls_context_cpy(&newcon, context2);
3249*4882a593Smuzhiyun 	if (rc)
3250*4882a593Smuzhiyun 		goto out_unlock;
3251*4882a593Smuzhiyun 
3252*4882a593Smuzhiyun 	/* Check the validity of the new context. */
3253*4882a593Smuzhiyun 	if (!policydb_context_isvalid(policydb, &newcon)) {
3254*4882a593Smuzhiyun 		rc = convert_context_handle_invalid_context(state, policydb,
3255*4882a593Smuzhiyun 							&newcon);
3256*4882a593Smuzhiyun 		if (rc) {
3257*4882a593Smuzhiyun 			if (!context_struct_to_string(policydb, &newcon, &s,
3258*4882a593Smuzhiyun 						      &len)) {
3259*4882a593Smuzhiyun 				struct audit_buffer *ab;
3260*4882a593Smuzhiyun 
3261*4882a593Smuzhiyun 				ab = audit_log_start(audit_context(),
3262*4882a593Smuzhiyun 						     GFP_ATOMIC,
3263*4882a593Smuzhiyun 						     AUDIT_SELINUX_ERR);
3264*4882a593Smuzhiyun 				audit_log_format(ab,
3265*4882a593Smuzhiyun 						 "op=security_sid_mls_copy invalid_context=");
3266*4882a593Smuzhiyun 				/* don't record NUL with untrusted strings */
3267*4882a593Smuzhiyun 				audit_log_n_untrustedstring(ab, s, len - 1);
3268*4882a593Smuzhiyun 				audit_log_end(ab);
3269*4882a593Smuzhiyun 				kfree(s);
3270*4882a593Smuzhiyun 			}
3271*4882a593Smuzhiyun 			goto out_unlock;
3272*4882a593Smuzhiyun 		}
3273*4882a593Smuzhiyun 	}
3274*4882a593Smuzhiyun 	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
3275*4882a593Smuzhiyun 	if (rc == -ESTALE) {
3276*4882a593Smuzhiyun 		rcu_read_unlock();
3277*4882a593Smuzhiyun 		context_destroy(&newcon);
3278*4882a593Smuzhiyun 		goto retry;
3279*4882a593Smuzhiyun 	}
3280*4882a593Smuzhiyun out_unlock:
3281*4882a593Smuzhiyun 	rcu_read_unlock();
3282*4882a593Smuzhiyun 	context_destroy(&newcon);
3283*4882a593Smuzhiyun 	return rc;
3284*4882a593Smuzhiyun }
3285*4882a593Smuzhiyun 
3286*4882a593Smuzhiyun /**
3287*4882a593Smuzhiyun  * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3288*4882a593Smuzhiyun  * @nlbl_sid: NetLabel SID
3289*4882a593Smuzhiyun  * @nlbl_type: NetLabel labeling protocol type
3290*4882a593Smuzhiyun  * @xfrm_sid: XFRM SID
3291*4882a593Smuzhiyun  *
3292*4882a593Smuzhiyun  * Description:
3293*4882a593Smuzhiyun  * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3294*4882a593Smuzhiyun  * resolved into a single SID it is returned via @peer_sid and the function
3295*4882a593Smuzhiyun  * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
3296*4882a593Smuzhiyun  * returns a negative value.  A table summarizing the behavior is below:
3297*4882a593Smuzhiyun  *
3298*4882a593Smuzhiyun  *                                 | function return |      @sid
3299*4882a593Smuzhiyun  *   ------------------------------+-----------------+-----------------
3300*4882a593Smuzhiyun  *   no peer labels                |        0        |    SECSID_NULL
3301*4882a593Smuzhiyun  *   single peer label             |        0        |    <peer_label>
3302*4882a593Smuzhiyun  *   multiple, consistent labels   |        0        |    <peer_label>
3303*4882a593Smuzhiyun  *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
3304*4882a593Smuzhiyun  *
3305*4882a593Smuzhiyun  */
security_net_peersid_resolve(struct selinux_state * state,u32 nlbl_sid,u32 nlbl_type,u32 xfrm_sid,u32 * peer_sid)3306*4882a593Smuzhiyun int security_net_peersid_resolve(struct selinux_state *state,
3307*4882a593Smuzhiyun 				 u32 nlbl_sid, u32 nlbl_type,
3308*4882a593Smuzhiyun 				 u32 xfrm_sid,
3309*4882a593Smuzhiyun 				 u32 *peer_sid)
3310*4882a593Smuzhiyun {
3311*4882a593Smuzhiyun 	struct selinux_policy *policy;
3312*4882a593Smuzhiyun 	struct policydb *policydb;
3313*4882a593Smuzhiyun 	struct sidtab *sidtab;
3314*4882a593Smuzhiyun 	int rc;
3315*4882a593Smuzhiyun 	struct context *nlbl_ctx;
3316*4882a593Smuzhiyun 	struct context *xfrm_ctx;
3317*4882a593Smuzhiyun 
3318*4882a593Smuzhiyun 	*peer_sid = SECSID_NULL;
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun 	/* handle the common (which also happens to be the set of easy) cases
3321*4882a593Smuzhiyun 	 * right away, these two if statements catch everything involving a
3322*4882a593Smuzhiyun 	 * single or absent peer SID/label */
3323*4882a593Smuzhiyun 	if (xfrm_sid == SECSID_NULL) {
3324*4882a593Smuzhiyun 		*peer_sid = nlbl_sid;
3325*4882a593Smuzhiyun 		return 0;
3326*4882a593Smuzhiyun 	}
3327*4882a593Smuzhiyun 	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3328*4882a593Smuzhiyun 	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3329*4882a593Smuzhiyun 	 * is present */
3330*4882a593Smuzhiyun 	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3331*4882a593Smuzhiyun 		*peer_sid = xfrm_sid;
3332*4882a593Smuzhiyun 		return 0;
3333*4882a593Smuzhiyun 	}
3334*4882a593Smuzhiyun 
3335*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3336*4882a593Smuzhiyun 		return 0;
3337*4882a593Smuzhiyun 
3338*4882a593Smuzhiyun 	rcu_read_lock();
3339*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3340*4882a593Smuzhiyun 	policydb = &policy->policydb;
3341*4882a593Smuzhiyun 	sidtab = policy->sidtab;
3342*4882a593Smuzhiyun 
3343*4882a593Smuzhiyun 	/*
3344*4882a593Smuzhiyun 	 * We don't need to check initialized here since the only way both
3345*4882a593Smuzhiyun 	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3346*4882a593Smuzhiyun 	 * security server was initialized and state->initialized was true.
3347*4882a593Smuzhiyun 	 */
3348*4882a593Smuzhiyun 	if (!policydb->mls_enabled) {
3349*4882a593Smuzhiyun 		rc = 0;
3350*4882a593Smuzhiyun 		goto out;
3351*4882a593Smuzhiyun 	}
3352*4882a593Smuzhiyun 
3353*4882a593Smuzhiyun 	rc = -EINVAL;
3354*4882a593Smuzhiyun 	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3355*4882a593Smuzhiyun 	if (!nlbl_ctx) {
3356*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3357*4882a593Smuzhiyun 		       __func__, nlbl_sid);
3358*4882a593Smuzhiyun 		goto out;
3359*4882a593Smuzhiyun 	}
3360*4882a593Smuzhiyun 	rc = -EINVAL;
3361*4882a593Smuzhiyun 	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3362*4882a593Smuzhiyun 	if (!xfrm_ctx) {
3363*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized SID %d\n",
3364*4882a593Smuzhiyun 		       __func__, xfrm_sid);
3365*4882a593Smuzhiyun 		goto out;
3366*4882a593Smuzhiyun 	}
3367*4882a593Smuzhiyun 	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
3368*4882a593Smuzhiyun 	if (rc)
3369*4882a593Smuzhiyun 		goto out;
3370*4882a593Smuzhiyun 
3371*4882a593Smuzhiyun 	/* at present NetLabel SIDs/labels really only carry MLS
3372*4882a593Smuzhiyun 	 * information so if the MLS portion of the NetLabel SID
3373*4882a593Smuzhiyun 	 * matches the MLS portion of the labeled XFRM SID/label
3374*4882a593Smuzhiyun 	 * then pass along the XFRM SID as it is the most
3375*4882a593Smuzhiyun 	 * expressive */
3376*4882a593Smuzhiyun 	*peer_sid = xfrm_sid;
3377*4882a593Smuzhiyun out:
3378*4882a593Smuzhiyun 	rcu_read_unlock();
3379*4882a593Smuzhiyun 	return rc;
3380*4882a593Smuzhiyun }
3381*4882a593Smuzhiyun 
get_classes_callback(void * k,void * d,void * args)3382*4882a593Smuzhiyun static int get_classes_callback(void *k, void *d, void *args)
3383*4882a593Smuzhiyun {
3384*4882a593Smuzhiyun 	struct class_datum *datum = d;
3385*4882a593Smuzhiyun 	char *name = k, **classes = args;
3386*4882a593Smuzhiyun 	int value = datum->value - 1;
3387*4882a593Smuzhiyun 
3388*4882a593Smuzhiyun 	classes[value] = kstrdup(name, GFP_ATOMIC);
3389*4882a593Smuzhiyun 	if (!classes[value])
3390*4882a593Smuzhiyun 		return -ENOMEM;
3391*4882a593Smuzhiyun 
3392*4882a593Smuzhiyun 	return 0;
3393*4882a593Smuzhiyun }
3394*4882a593Smuzhiyun 
security_get_classes(struct selinux_policy * policy,char *** classes,int * nclasses)3395*4882a593Smuzhiyun int security_get_classes(struct selinux_policy *policy,
3396*4882a593Smuzhiyun 			 char ***classes, int *nclasses)
3397*4882a593Smuzhiyun {
3398*4882a593Smuzhiyun 	struct policydb *policydb;
3399*4882a593Smuzhiyun 	int rc;
3400*4882a593Smuzhiyun 
3401*4882a593Smuzhiyun 	policydb = &policy->policydb;
3402*4882a593Smuzhiyun 
3403*4882a593Smuzhiyun 	rc = -ENOMEM;
3404*4882a593Smuzhiyun 	*nclasses = policydb->p_classes.nprim;
3405*4882a593Smuzhiyun 	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
3406*4882a593Smuzhiyun 	if (!*classes)
3407*4882a593Smuzhiyun 		goto out;
3408*4882a593Smuzhiyun 
3409*4882a593Smuzhiyun 	rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
3410*4882a593Smuzhiyun 			 *classes);
3411*4882a593Smuzhiyun 	if (rc) {
3412*4882a593Smuzhiyun 		int i;
3413*4882a593Smuzhiyun 		for (i = 0; i < *nclasses; i++)
3414*4882a593Smuzhiyun 			kfree((*classes)[i]);
3415*4882a593Smuzhiyun 		kfree(*classes);
3416*4882a593Smuzhiyun 	}
3417*4882a593Smuzhiyun 
3418*4882a593Smuzhiyun out:
3419*4882a593Smuzhiyun 	return rc;
3420*4882a593Smuzhiyun }
3421*4882a593Smuzhiyun 
get_permissions_callback(void * k,void * d,void * args)3422*4882a593Smuzhiyun static int get_permissions_callback(void *k, void *d, void *args)
3423*4882a593Smuzhiyun {
3424*4882a593Smuzhiyun 	struct perm_datum *datum = d;
3425*4882a593Smuzhiyun 	char *name = k, **perms = args;
3426*4882a593Smuzhiyun 	int value = datum->value - 1;
3427*4882a593Smuzhiyun 
3428*4882a593Smuzhiyun 	perms[value] = kstrdup(name, GFP_ATOMIC);
3429*4882a593Smuzhiyun 	if (!perms[value])
3430*4882a593Smuzhiyun 		return -ENOMEM;
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun 	return 0;
3433*4882a593Smuzhiyun }
3434*4882a593Smuzhiyun 
security_get_permissions(struct selinux_policy * policy,char * class,char *** perms,int * nperms)3435*4882a593Smuzhiyun int security_get_permissions(struct selinux_policy *policy,
3436*4882a593Smuzhiyun 			     char *class, char ***perms, int *nperms)
3437*4882a593Smuzhiyun {
3438*4882a593Smuzhiyun 	struct policydb *policydb;
3439*4882a593Smuzhiyun 	int rc, i;
3440*4882a593Smuzhiyun 	struct class_datum *match;
3441*4882a593Smuzhiyun 
3442*4882a593Smuzhiyun 	policydb = &policy->policydb;
3443*4882a593Smuzhiyun 
3444*4882a593Smuzhiyun 	rc = -EINVAL;
3445*4882a593Smuzhiyun 	match = symtab_search(&policydb->p_classes, class);
3446*4882a593Smuzhiyun 	if (!match) {
3447*4882a593Smuzhiyun 		pr_err("SELinux: %s:  unrecognized class %s\n",
3448*4882a593Smuzhiyun 			__func__, class);
3449*4882a593Smuzhiyun 		goto out;
3450*4882a593Smuzhiyun 	}
3451*4882a593Smuzhiyun 
3452*4882a593Smuzhiyun 	rc = -ENOMEM;
3453*4882a593Smuzhiyun 	*nperms = match->permissions.nprim;
3454*4882a593Smuzhiyun 	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
3455*4882a593Smuzhiyun 	if (!*perms)
3456*4882a593Smuzhiyun 		goto out;
3457*4882a593Smuzhiyun 
3458*4882a593Smuzhiyun 	if (match->comdatum) {
3459*4882a593Smuzhiyun 		rc = hashtab_map(&match->comdatum->permissions.table,
3460*4882a593Smuzhiyun 				 get_permissions_callback, *perms);
3461*4882a593Smuzhiyun 		if (rc)
3462*4882a593Smuzhiyun 			goto err;
3463*4882a593Smuzhiyun 	}
3464*4882a593Smuzhiyun 
3465*4882a593Smuzhiyun 	rc = hashtab_map(&match->permissions.table, get_permissions_callback,
3466*4882a593Smuzhiyun 			 *perms);
3467*4882a593Smuzhiyun 	if (rc)
3468*4882a593Smuzhiyun 		goto err;
3469*4882a593Smuzhiyun 
3470*4882a593Smuzhiyun out:
3471*4882a593Smuzhiyun 	return rc;
3472*4882a593Smuzhiyun 
3473*4882a593Smuzhiyun err:
3474*4882a593Smuzhiyun 	for (i = 0; i < *nperms; i++)
3475*4882a593Smuzhiyun 		kfree((*perms)[i]);
3476*4882a593Smuzhiyun 	kfree(*perms);
3477*4882a593Smuzhiyun 	return rc;
3478*4882a593Smuzhiyun }
3479*4882a593Smuzhiyun 
security_get_reject_unknown(struct selinux_state * state)3480*4882a593Smuzhiyun int security_get_reject_unknown(struct selinux_state *state)
3481*4882a593Smuzhiyun {
3482*4882a593Smuzhiyun 	struct selinux_policy *policy;
3483*4882a593Smuzhiyun 	int value;
3484*4882a593Smuzhiyun 
3485*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3486*4882a593Smuzhiyun 		return 0;
3487*4882a593Smuzhiyun 
3488*4882a593Smuzhiyun 	rcu_read_lock();
3489*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3490*4882a593Smuzhiyun 	value = policy->policydb.reject_unknown;
3491*4882a593Smuzhiyun 	rcu_read_unlock();
3492*4882a593Smuzhiyun 	return value;
3493*4882a593Smuzhiyun }
3494*4882a593Smuzhiyun 
security_get_allow_unknown(struct selinux_state * state)3495*4882a593Smuzhiyun int security_get_allow_unknown(struct selinux_state *state)
3496*4882a593Smuzhiyun {
3497*4882a593Smuzhiyun 	struct selinux_policy *policy;
3498*4882a593Smuzhiyun 	int value;
3499*4882a593Smuzhiyun 
3500*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3501*4882a593Smuzhiyun 		return 0;
3502*4882a593Smuzhiyun 
3503*4882a593Smuzhiyun 	rcu_read_lock();
3504*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3505*4882a593Smuzhiyun 	value = policy->policydb.allow_unknown;
3506*4882a593Smuzhiyun 	rcu_read_unlock();
3507*4882a593Smuzhiyun 	return value;
3508*4882a593Smuzhiyun }
3509*4882a593Smuzhiyun 
3510*4882a593Smuzhiyun /**
3511*4882a593Smuzhiyun  * security_policycap_supported - Check for a specific policy capability
3512*4882a593Smuzhiyun  * @req_cap: capability
3513*4882a593Smuzhiyun  *
3514*4882a593Smuzhiyun  * Description:
3515*4882a593Smuzhiyun  * This function queries the currently loaded policy to see if it supports the
3516*4882a593Smuzhiyun  * capability specified by @req_cap.  Returns true (1) if the capability is
3517*4882a593Smuzhiyun  * supported, false (0) if it isn't supported.
3518*4882a593Smuzhiyun  *
3519*4882a593Smuzhiyun  */
security_policycap_supported(struct selinux_state * state,unsigned int req_cap)3520*4882a593Smuzhiyun int security_policycap_supported(struct selinux_state *state,
3521*4882a593Smuzhiyun 				 unsigned int req_cap)
3522*4882a593Smuzhiyun {
3523*4882a593Smuzhiyun 	struct selinux_policy *policy;
3524*4882a593Smuzhiyun 	int rc;
3525*4882a593Smuzhiyun 
3526*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3527*4882a593Smuzhiyun 		return 0;
3528*4882a593Smuzhiyun 
3529*4882a593Smuzhiyun 	rcu_read_lock();
3530*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3531*4882a593Smuzhiyun 	rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
3532*4882a593Smuzhiyun 	rcu_read_unlock();
3533*4882a593Smuzhiyun 
3534*4882a593Smuzhiyun 	return rc;
3535*4882a593Smuzhiyun }
3536*4882a593Smuzhiyun 
3537*4882a593Smuzhiyun struct selinux_audit_rule {
3538*4882a593Smuzhiyun 	u32 au_seqno;
3539*4882a593Smuzhiyun 	struct context au_ctxt;
3540*4882a593Smuzhiyun };
3541*4882a593Smuzhiyun 
selinux_audit_rule_free(void * vrule)3542*4882a593Smuzhiyun void selinux_audit_rule_free(void *vrule)
3543*4882a593Smuzhiyun {
3544*4882a593Smuzhiyun 	struct selinux_audit_rule *rule = vrule;
3545*4882a593Smuzhiyun 
3546*4882a593Smuzhiyun 	if (rule) {
3547*4882a593Smuzhiyun 		context_destroy(&rule->au_ctxt);
3548*4882a593Smuzhiyun 		kfree(rule);
3549*4882a593Smuzhiyun 	}
3550*4882a593Smuzhiyun }
3551*4882a593Smuzhiyun 
selinux_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule)3552*4882a593Smuzhiyun int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3553*4882a593Smuzhiyun {
3554*4882a593Smuzhiyun 	struct selinux_state *state = &selinux_state;
3555*4882a593Smuzhiyun 	struct selinux_policy *policy;
3556*4882a593Smuzhiyun 	struct policydb *policydb;
3557*4882a593Smuzhiyun 	struct selinux_audit_rule *tmprule;
3558*4882a593Smuzhiyun 	struct role_datum *roledatum;
3559*4882a593Smuzhiyun 	struct type_datum *typedatum;
3560*4882a593Smuzhiyun 	struct user_datum *userdatum;
3561*4882a593Smuzhiyun 	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3562*4882a593Smuzhiyun 	int rc = 0;
3563*4882a593Smuzhiyun 
3564*4882a593Smuzhiyun 	*rule = NULL;
3565*4882a593Smuzhiyun 
3566*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3567*4882a593Smuzhiyun 		return -EOPNOTSUPP;
3568*4882a593Smuzhiyun 
3569*4882a593Smuzhiyun 	switch (field) {
3570*4882a593Smuzhiyun 	case AUDIT_SUBJ_USER:
3571*4882a593Smuzhiyun 	case AUDIT_SUBJ_ROLE:
3572*4882a593Smuzhiyun 	case AUDIT_SUBJ_TYPE:
3573*4882a593Smuzhiyun 	case AUDIT_OBJ_USER:
3574*4882a593Smuzhiyun 	case AUDIT_OBJ_ROLE:
3575*4882a593Smuzhiyun 	case AUDIT_OBJ_TYPE:
3576*4882a593Smuzhiyun 		/* only 'equals' and 'not equals' fit user, role, and type */
3577*4882a593Smuzhiyun 		if (op != Audit_equal && op != Audit_not_equal)
3578*4882a593Smuzhiyun 			return -EINVAL;
3579*4882a593Smuzhiyun 		break;
3580*4882a593Smuzhiyun 	case AUDIT_SUBJ_SEN:
3581*4882a593Smuzhiyun 	case AUDIT_SUBJ_CLR:
3582*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_LOW:
3583*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_HIGH:
3584*4882a593Smuzhiyun 		/* we do not allow a range, indicated by the presence of '-' */
3585*4882a593Smuzhiyun 		if (strchr(rulestr, '-'))
3586*4882a593Smuzhiyun 			return -EINVAL;
3587*4882a593Smuzhiyun 		break;
3588*4882a593Smuzhiyun 	default:
3589*4882a593Smuzhiyun 		/* only the above fields are valid */
3590*4882a593Smuzhiyun 		return -EINVAL;
3591*4882a593Smuzhiyun 	}
3592*4882a593Smuzhiyun 
3593*4882a593Smuzhiyun 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
3594*4882a593Smuzhiyun 	if (!tmprule)
3595*4882a593Smuzhiyun 		return -ENOMEM;
3596*4882a593Smuzhiyun 
3597*4882a593Smuzhiyun 	context_init(&tmprule->au_ctxt);
3598*4882a593Smuzhiyun 
3599*4882a593Smuzhiyun 	rcu_read_lock();
3600*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3601*4882a593Smuzhiyun 	policydb = &policy->policydb;
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun 	tmprule->au_seqno = policy->latest_granting;
3604*4882a593Smuzhiyun 
3605*4882a593Smuzhiyun 	switch (field) {
3606*4882a593Smuzhiyun 	case AUDIT_SUBJ_USER:
3607*4882a593Smuzhiyun 	case AUDIT_OBJ_USER:
3608*4882a593Smuzhiyun 		rc = -EINVAL;
3609*4882a593Smuzhiyun 		userdatum = symtab_search(&policydb->p_users, rulestr);
3610*4882a593Smuzhiyun 		if (!userdatum)
3611*4882a593Smuzhiyun 			goto out;
3612*4882a593Smuzhiyun 		tmprule->au_ctxt.user = userdatum->value;
3613*4882a593Smuzhiyun 		break;
3614*4882a593Smuzhiyun 	case AUDIT_SUBJ_ROLE:
3615*4882a593Smuzhiyun 	case AUDIT_OBJ_ROLE:
3616*4882a593Smuzhiyun 		rc = -EINVAL;
3617*4882a593Smuzhiyun 		roledatum = symtab_search(&policydb->p_roles, rulestr);
3618*4882a593Smuzhiyun 		if (!roledatum)
3619*4882a593Smuzhiyun 			goto out;
3620*4882a593Smuzhiyun 		tmprule->au_ctxt.role = roledatum->value;
3621*4882a593Smuzhiyun 		break;
3622*4882a593Smuzhiyun 	case AUDIT_SUBJ_TYPE:
3623*4882a593Smuzhiyun 	case AUDIT_OBJ_TYPE:
3624*4882a593Smuzhiyun 		rc = -EINVAL;
3625*4882a593Smuzhiyun 		typedatum = symtab_search(&policydb->p_types, rulestr);
3626*4882a593Smuzhiyun 		if (!typedatum)
3627*4882a593Smuzhiyun 			goto out;
3628*4882a593Smuzhiyun 		tmprule->au_ctxt.type = typedatum->value;
3629*4882a593Smuzhiyun 		break;
3630*4882a593Smuzhiyun 	case AUDIT_SUBJ_SEN:
3631*4882a593Smuzhiyun 	case AUDIT_SUBJ_CLR:
3632*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_LOW:
3633*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_HIGH:
3634*4882a593Smuzhiyun 		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3635*4882a593Smuzhiyun 				     GFP_ATOMIC);
3636*4882a593Smuzhiyun 		if (rc)
3637*4882a593Smuzhiyun 			goto out;
3638*4882a593Smuzhiyun 		break;
3639*4882a593Smuzhiyun 	}
3640*4882a593Smuzhiyun 	rc = 0;
3641*4882a593Smuzhiyun out:
3642*4882a593Smuzhiyun 	rcu_read_unlock();
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 	if (rc) {
3645*4882a593Smuzhiyun 		selinux_audit_rule_free(tmprule);
3646*4882a593Smuzhiyun 		tmprule = NULL;
3647*4882a593Smuzhiyun 	}
3648*4882a593Smuzhiyun 
3649*4882a593Smuzhiyun 	*rule = tmprule;
3650*4882a593Smuzhiyun 
3651*4882a593Smuzhiyun 	return rc;
3652*4882a593Smuzhiyun }
3653*4882a593Smuzhiyun 
3654*4882a593Smuzhiyun /* Check to see if the rule contains any selinux fields */
selinux_audit_rule_known(struct audit_krule * rule)3655*4882a593Smuzhiyun int selinux_audit_rule_known(struct audit_krule *rule)
3656*4882a593Smuzhiyun {
3657*4882a593Smuzhiyun 	int i;
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 	for (i = 0; i < rule->field_count; i++) {
3660*4882a593Smuzhiyun 		struct audit_field *f = &rule->fields[i];
3661*4882a593Smuzhiyun 		switch (f->type) {
3662*4882a593Smuzhiyun 		case AUDIT_SUBJ_USER:
3663*4882a593Smuzhiyun 		case AUDIT_SUBJ_ROLE:
3664*4882a593Smuzhiyun 		case AUDIT_SUBJ_TYPE:
3665*4882a593Smuzhiyun 		case AUDIT_SUBJ_SEN:
3666*4882a593Smuzhiyun 		case AUDIT_SUBJ_CLR:
3667*4882a593Smuzhiyun 		case AUDIT_OBJ_USER:
3668*4882a593Smuzhiyun 		case AUDIT_OBJ_ROLE:
3669*4882a593Smuzhiyun 		case AUDIT_OBJ_TYPE:
3670*4882a593Smuzhiyun 		case AUDIT_OBJ_LEV_LOW:
3671*4882a593Smuzhiyun 		case AUDIT_OBJ_LEV_HIGH:
3672*4882a593Smuzhiyun 			return 1;
3673*4882a593Smuzhiyun 		}
3674*4882a593Smuzhiyun 	}
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	return 0;
3677*4882a593Smuzhiyun }
3678*4882a593Smuzhiyun 
selinux_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)3679*4882a593Smuzhiyun int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3680*4882a593Smuzhiyun {
3681*4882a593Smuzhiyun 	struct selinux_state *state = &selinux_state;
3682*4882a593Smuzhiyun 	struct selinux_policy *policy;
3683*4882a593Smuzhiyun 	struct context *ctxt;
3684*4882a593Smuzhiyun 	struct mls_level *level;
3685*4882a593Smuzhiyun 	struct selinux_audit_rule *rule = vrule;
3686*4882a593Smuzhiyun 	int match = 0;
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun 	if (unlikely(!rule)) {
3689*4882a593Smuzhiyun 		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3690*4882a593Smuzhiyun 		return -ENOENT;
3691*4882a593Smuzhiyun 	}
3692*4882a593Smuzhiyun 
3693*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3694*4882a593Smuzhiyun 		return 0;
3695*4882a593Smuzhiyun 
3696*4882a593Smuzhiyun 	rcu_read_lock();
3697*4882a593Smuzhiyun 
3698*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3699*4882a593Smuzhiyun 
3700*4882a593Smuzhiyun 	if (rule->au_seqno < policy->latest_granting) {
3701*4882a593Smuzhiyun 		match = -ESTALE;
3702*4882a593Smuzhiyun 		goto out;
3703*4882a593Smuzhiyun 	}
3704*4882a593Smuzhiyun 
3705*4882a593Smuzhiyun 	ctxt = sidtab_search(policy->sidtab, sid);
3706*4882a593Smuzhiyun 	if (unlikely(!ctxt)) {
3707*4882a593Smuzhiyun 		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
3708*4882a593Smuzhiyun 			  sid);
3709*4882a593Smuzhiyun 		match = -ENOENT;
3710*4882a593Smuzhiyun 		goto out;
3711*4882a593Smuzhiyun 	}
3712*4882a593Smuzhiyun 
3713*4882a593Smuzhiyun 	/* a field/op pair that is not caught here will simply fall through
3714*4882a593Smuzhiyun 	   without a match */
3715*4882a593Smuzhiyun 	switch (field) {
3716*4882a593Smuzhiyun 	case AUDIT_SUBJ_USER:
3717*4882a593Smuzhiyun 	case AUDIT_OBJ_USER:
3718*4882a593Smuzhiyun 		switch (op) {
3719*4882a593Smuzhiyun 		case Audit_equal:
3720*4882a593Smuzhiyun 			match = (ctxt->user == rule->au_ctxt.user);
3721*4882a593Smuzhiyun 			break;
3722*4882a593Smuzhiyun 		case Audit_not_equal:
3723*4882a593Smuzhiyun 			match = (ctxt->user != rule->au_ctxt.user);
3724*4882a593Smuzhiyun 			break;
3725*4882a593Smuzhiyun 		}
3726*4882a593Smuzhiyun 		break;
3727*4882a593Smuzhiyun 	case AUDIT_SUBJ_ROLE:
3728*4882a593Smuzhiyun 	case AUDIT_OBJ_ROLE:
3729*4882a593Smuzhiyun 		switch (op) {
3730*4882a593Smuzhiyun 		case Audit_equal:
3731*4882a593Smuzhiyun 			match = (ctxt->role == rule->au_ctxt.role);
3732*4882a593Smuzhiyun 			break;
3733*4882a593Smuzhiyun 		case Audit_not_equal:
3734*4882a593Smuzhiyun 			match = (ctxt->role != rule->au_ctxt.role);
3735*4882a593Smuzhiyun 			break;
3736*4882a593Smuzhiyun 		}
3737*4882a593Smuzhiyun 		break;
3738*4882a593Smuzhiyun 	case AUDIT_SUBJ_TYPE:
3739*4882a593Smuzhiyun 	case AUDIT_OBJ_TYPE:
3740*4882a593Smuzhiyun 		switch (op) {
3741*4882a593Smuzhiyun 		case Audit_equal:
3742*4882a593Smuzhiyun 			match = (ctxt->type == rule->au_ctxt.type);
3743*4882a593Smuzhiyun 			break;
3744*4882a593Smuzhiyun 		case Audit_not_equal:
3745*4882a593Smuzhiyun 			match = (ctxt->type != rule->au_ctxt.type);
3746*4882a593Smuzhiyun 			break;
3747*4882a593Smuzhiyun 		}
3748*4882a593Smuzhiyun 		break;
3749*4882a593Smuzhiyun 	case AUDIT_SUBJ_SEN:
3750*4882a593Smuzhiyun 	case AUDIT_SUBJ_CLR:
3751*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_LOW:
3752*4882a593Smuzhiyun 	case AUDIT_OBJ_LEV_HIGH:
3753*4882a593Smuzhiyun 		level = ((field == AUDIT_SUBJ_SEN ||
3754*4882a593Smuzhiyun 			  field == AUDIT_OBJ_LEV_LOW) ?
3755*4882a593Smuzhiyun 			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3756*4882a593Smuzhiyun 		switch (op) {
3757*4882a593Smuzhiyun 		case Audit_equal:
3758*4882a593Smuzhiyun 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3759*4882a593Smuzhiyun 					     level);
3760*4882a593Smuzhiyun 			break;
3761*4882a593Smuzhiyun 		case Audit_not_equal:
3762*4882a593Smuzhiyun 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3763*4882a593Smuzhiyun 					      level);
3764*4882a593Smuzhiyun 			break;
3765*4882a593Smuzhiyun 		case Audit_lt:
3766*4882a593Smuzhiyun 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3767*4882a593Smuzhiyun 					       level) &&
3768*4882a593Smuzhiyun 				 !mls_level_eq(&rule->au_ctxt.range.level[0],
3769*4882a593Smuzhiyun 					       level));
3770*4882a593Smuzhiyun 			break;
3771*4882a593Smuzhiyun 		case Audit_le:
3772*4882a593Smuzhiyun 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3773*4882a593Smuzhiyun 					      level);
3774*4882a593Smuzhiyun 			break;
3775*4882a593Smuzhiyun 		case Audit_gt:
3776*4882a593Smuzhiyun 			match = (mls_level_dom(level,
3777*4882a593Smuzhiyun 					      &rule->au_ctxt.range.level[0]) &&
3778*4882a593Smuzhiyun 				 !mls_level_eq(level,
3779*4882a593Smuzhiyun 					       &rule->au_ctxt.range.level[0]));
3780*4882a593Smuzhiyun 			break;
3781*4882a593Smuzhiyun 		case Audit_ge:
3782*4882a593Smuzhiyun 			match = mls_level_dom(level,
3783*4882a593Smuzhiyun 					      &rule->au_ctxt.range.level[0]);
3784*4882a593Smuzhiyun 			break;
3785*4882a593Smuzhiyun 		}
3786*4882a593Smuzhiyun 	}
3787*4882a593Smuzhiyun 
3788*4882a593Smuzhiyun out:
3789*4882a593Smuzhiyun 	rcu_read_unlock();
3790*4882a593Smuzhiyun 	return match;
3791*4882a593Smuzhiyun }
3792*4882a593Smuzhiyun 
3793*4882a593Smuzhiyun static int (*aurule_callback)(void) = audit_update_lsm_rules;
3794*4882a593Smuzhiyun 
aurule_avc_callback(u32 event)3795*4882a593Smuzhiyun static int aurule_avc_callback(u32 event)
3796*4882a593Smuzhiyun {
3797*4882a593Smuzhiyun 	int err = 0;
3798*4882a593Smuzhiyun 
3799*4882a593Smuzhiyun 	if (event == AVC_CALLBACK_RESET && aurule_callback)
3800*4882a593Smuzhiyun 		err = aurule_callback();
3801*4882a593Smuzhiyun 	return err;
3802*4882a593Smuzhiyun }
3803*4882a593Smuzhiyun 
aurule_init(void)3804*4882a593Smuzhiyun static int __init aurule_init(void)
3805*4882a593Smuzhiyun {
3806*4882a593Smuzhiyun 	int err;
3807*4882a593Smuzhiyun 
3808*4882a593Smuzhiyun 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3809*4882a593Smuzhiyun 	if (err)
3810*4882a593Smuzhiyun 		panic("avc_add_callback() failed, error %d\n", err);
3811*4882a593Smuzhiyun 
3812*4882a593Smuzhiyun 	return err;
3813*4882a593Smuzhiyun }
3814*4882a593Smuzhiyun __initcall(aurule_init);
3815*4882a593Smuzhiyun 
3816*4882a593Smuzhiyun #ifdef CONFIG_NETLABEL
3817*4882a593Smuzhiyun /**
3818*4882a593Smuzhiyun  * security_netlbl_cache_add - Add an entry to the NetLabel cache
3819*4882a593Smuzhiyun  * @secattr: the NetLabel packet security attributes
3820*4882a593Smuzhiyun  * @sid: the SELinux SID
3821*4882a593Smuzhiyun  *
3822*4882a593Smuzhiyun  * Description:
3823*4882a593Smuzhiyun  * Attempt to cache the context in @ctx, which was derived from the packet in
3824*4882a593Smuzhiyun  * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
3825*4882a593Smuzhiyun  * already been initialized.
3826*4882a593Smuzhiyun  *
3827*4882a593Smuzhiyun  */
security_netlbl_cache_add(struct netlbl_lsm_secattr * secattr,u32 sid)3828*4882a593Smuzhiyun static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
3829*4882a593Smuzhiyun 				      u32 sid)
3830*4882a593Smuzhiyun {
3831*4882a593Smuzhiyun 	u32 *sid_cache;
3832*4882a593Smuzhiyun 
3833*4882a593Smuzhiyun 	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
3834*4882a593Smuzhiyun 	if (sid_cache == NULL)
3835*4882a593Smuzhiyun 		return;
3836*4882a593Smuzhiyun 	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
3837*4882a593Smuzhiyun 	if (secattr->cache == NULL) {
3838*4882a593Smuzhiyun 		kfree(sid_cache);
3839*4882a593Smuzhiyun 		return;
3840*4882a593Smuzhiyun 	}
3841*4882a593Smuzhiyun 
3842*4882a593Smuzhiyun 	*sid_cache = sid;
3843*4882a593Smuzhiyun 	secattr->cache->free = kfree;
3844*4882a593Smuzhiyun 	secattr->cache->data = sid_cache;
3845*4882a593Smuzhiyun 	secattr->flags |= NETLBL_SECATTR_CACHE;
3846*4882a593Smuzhiyun }
3847*4882a593Smuzhiyun 
3848*4882a593Smuzhiyun /**
3849*4882a593Smuzhiyun  * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
3850*4882a593Smuzhiyun  * @secattr: the NetLabel packet security attributes
3851*4882a593Smuzhiyun  * @sid: the SELinux SID
3852*4882a593Smuzhiyun  *
3853*4882a593Smuzhiyun  * Description:
3854*4882a593Smuzhiyun  * Convert the given NetLabel security attributes in @secattr into a
3855*4882a593Smuzhiyun  * SELinux SID.  If the @secattr field does not contain a full SELinux
3856*4882a593Smuzhiyun  * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
3857*4882a593Smuzhiyun  * 'cache' field of @secattr is set and the CACHE flag is set; this is to
3858*4882a593Smuzhiyun  * allow the @secattr to be used by NetLabel to cache the secattr to SID
3859*4882a593Smuzhiyun  * conversion for future lookups.  Returns zero on success, negative values on
3860*4882a593Smuzhiyun  * failure.
3861*4882a593Smuzhiyun  *
3862*4882a593Smuzhiyun  */
security_netlbl_secattr_to_sid(struct selinux_state * state,struct netlbl_lsm_secattr * secattr,u32 * sid)3863*4882a593Smuzhiyun int security_netlbl_secattr_to_sid(struct selinux_state *state,
3864*4882a593Smuzhiyun 				   struct netlbl_lsm_secattr *secattr,
3865*4882a593Smuzhiyun 				   u32 *sid)
3866*4882a593Smuzhiyun {
3867*4882a593Smuzhiyun 	struct selinux_policy *policy;
3868*4882a593Smuzhiyun 	struct policydb *policydb;
3869*4882a593Smuzhiyun 	struct sidtab *sidtab;
3870*4882a593Smuzhiyun 	int rc;
3871*4882a593Smuzhiyun 	struct context *ctx;
3872*4882a593Smuzhiyun 	struct context ctx_new;
3873*4882a593Smuzhiyun 
3874*4882a593Smuzhiyun 	if (!selinux_initialized(state)) {
3875*4882a593Smuzhiyun 		*sid = SECSID_NULL;
3876*4882a593Smuzhiyun 		return 0;
3877*4882a593Smuzhiyun 	}
3878*4882a593Smuzhiyun 
3879*4882a593Smuzhiyun retry:
3880*4882a593Smuzhiyun 	rc = 0;
3881*4882a593Smuzhiyun 	rcu_read_lock();
3882*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3883*4882a593Smuzhiyun 	policydb = &policy->policydb;
3884*4882a593Smuzhiyun 	sidtab = policy->sidtab;
3885*4882a593Smuzhiyun 
3886*4882a593Smuzhiyun 	if (secattr->flags & NETLBL_SECATTR_CACHE)
3887*4882a593Smuzhiyun 		*sid = *(u32 *)secattr->cache->data;
3888*4882a593Smuzhiyun 	else if (secattr->flags & NETLBL_SECATTR_SECID)
3889*4882a593Smuzhiyun 		*sid = secattr->attr.secid;
3890*4882a593Smuzhiyun 	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
3891*4882a593Smuzhiyun 		rc = -EIDRM;
3892*4882a593Smuzhiyun 		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
3893*4882a593Smuzhiyun 		if (ctx == NULL)
3894*4882a593Smuzhiyun 			goto out;
3895*4882a593Smuzhiyun 
3896*4882a593Smuzhiyun 		context_init(&ctx_new);
3897*4882a593Smuzhiyun 		ctx_new.user = ctx->user;
3898*4882a593Smuzhiyun 		ctx_new.role = ctx->role;
3899*4882a593Smuzhiyun 		ctx_new.type = ctx->type;
3900*4882a593Smuzhiyun 		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3901*4882a593Smuzhiyun 		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3902*4882a593Smuzhiyun 			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
3903*4882a593Smuzhiyun 			if (rc)
3904*4882a593Smuzhiyun 				goto out;
3905*4882a593Smuzhiyun 		}
3906*4882a593Smuzhiyun 		rc = -EIDRM;
3907*4882a593Smuzhiyun 		if (!mls_context_isvalid(policydb, &ctx_new)) {
3908*4882a593Smuzhiyun 			ebitmap_destroy(&ctx_new.range.level[0].cat);
3909*4882a593Smuzhiyun 			goto out;
3910*4882a593Smuzhiyun 		}
3911*4882a593Smuzhiyun 
3912*4882a593Smuzhiyun 		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
3913*4882a593Smuzhiyun 		ebitmap_destroy(&ctx_new.range.level[0].cat);
3914*4882a593Smuzhiyun 		if (rc == -ESTALE) {
3915*4882a593Smuzhiyun 			rcu_read_unlock();
3916*4882a593Smuzhiyun 			goto retry;
3917*4882a593Smuzhiyun 		}
3918*4882a593Smuzhiyun 		if (rc)
3919*4882a593Smuzhiyun 			goto out;
3920*4882a593Smuzhiyun 
3921*4882a593Smuzhiyun 		security_netlbl_cache_add(secattr, *sid);
3922*4882a593Smuzhiyun 	} else
3923*4882a593Smuzhiyun 		*sid = SECSID_NULL;
3924*4882a593Smuzhiyun 
3925*4882a593Smuzhiyun out:
3926*4882a593Smuzhiyun 	rcu_read_unlock();
3927*4882a593Smuzhiyun 	return rc;
3928*4882a593Smuzhiyun }
3929*4882a593Smuzhiyun 
3930*4882a593Smuzhiyun /**
3931*4882a593Smuzhiyun  * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
3932*4882a593Smuzhiyun  * @sid: the SELinux SID
3933*4882a593Smuzhiyun  * @secattr: the NetLabel packet security attributes
3934*4882a593Smuzhiyun  *
3935*4882a593Smuzhiyun  * Description:
3936*4882a593Smuzhiyun  * Convert the given SELinux SID in @sid into a NetLabel security attribute.
3937*4882a593Smuzhiyun  * Returns zero on success, negative values on failure.
3938*4882a593Smuzhiyun  *
3939*4882a593Smuzhiyun  */
security_netlbl_sid_to_secattr(struct selinux_state * state,u32 sid,struct netlbl_lsm_secattr * secattr)3940*4882a593Smuzhiyun int security_netlbl_sid_to_secattr(struct selinux_state *state,
3941*4882a593Smuzhiyun 				   u32 sid, struct netlbl_lsm_secattr *secattr)
3942*4882a593Smuzhiyun {
3943*4882a593Smuzhiyun 	struct selinux_policy *policy;
3944*4882a593Smuzhiyun 	struct policydb *policydb;
3945*4882a593Smuzhiyun 	int rc;
3946*4882a593Smuzhiyun 	struct context *ctx;
3947*4882a593Smuzhiyun 
3948*4882a593Smuzhiyun 	if (!selinux_initialized(state))
3949*4882a593Smuzhiyun 		return 0;
3950*4882a593Smuzhiyun 
3951*4882a593Smuzhiyun 	rcu_read_lock();
3952*4882a593Smuzhiyun 	policy = rcu_dereference(state->policy);
3953*4882a593Smuzhiyun 	policydb = &policy->policydb;
3954*4882a593Smuzhiyun 
3955*4882a593Smuzhiyun 	rc = -ENOENT;
3956*4882a593Smuzhiyun 	ctx = sidtab_search(policy->sidtab, sid);
3957*4882a593Smuzhiyun 	if (ctx == NULL)
3958*4882a593Smuzhiyun 		goto out;
3959*4882a593Smuzhiyun 
3960*4882a593Smuzhiyun 	rc = -ENOMEM;
3961*4882a593Smuzhiyun 	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
3962*4882a593Smuzhiyun 				  GFP_ATOMIC);
3963*4882a593Smuzhiyun 	if (secattr->domain == NULL)
3964*4882a593Smuzhiyun 		goto out;
3965*4882a593Smuzhiyun 
3966*4882a593Smuzhiyun 	secattr->attr.secid = sid;
3967*4882a593Smuzhiyun 	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3968*4882a593Smuzhiyun 	mls_export_netlbl_lvl(policydb, ctx, secattr);
3969*4882a593Smuzhiyun 	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
3970*4882a593Smuzhiyun out:
3971*4882a593Smuzhiyun 	rcu_read_unlock();
3972*4882a593Smuzhiyun 	return rc;
3973*4882a593Smuzhiyun }
3974*4882a593Smuzhiyun #endif /* CONFIG_NETLABEL */
3975*4882a593Smuzhiyun 
3976*4882a593Smuzhiyun /**
3977*4882a593Smuzhiyun  * security_read_policy - read the policy.
3978*4882a593Smuzhiyun  * @data: binary policy data
3979*4882a593Smuzhiyun  * @len: length of data in bytes
3980*4882a593Smuzhiyun  *
3981*4882a593Smuzhiyun  */
security_read_policy(struct selinux_state * state,void ** data,size_t * len)3982*4882a593Smuzhiyun int security_read_policy(struct selinux_state *state,
3983*4882a593Smuzhiyun 			 void **data, size_t *len)
3984*4882a593Smuzhiyun {
3985*4882a593Smuzhiyun 	struct selinux_policy *policy;
3986*4882a593Smuzhiyun 	int rc;
3987*4882a593Smuzhiyun 	struct policy_file fp;
3988*4882a593Smuzhiyun 
3989*4882a593Smuzhiyun 	policy = rcu_dereference_protected(
3990*4882a593Smuzhiyun 			state->policy, lockdep_is_held(&state->policy_mutex));
3991*4882a593Smuzhiyun 	if (!policy)
3992*4882a593Smuzhiyun 		return -EINVAL;
3993*4882a593Smuzhiyun 
3994*4882a593Smuzhiyun 	*len = policy->policydb.len;
3995*4882a593Smuzhiyun 	*data = vmalloc_user(*len);
3996*4882a593Smuzhiyun 	if (!*data)
3997*4882a593Smuzhiyun 		return -ENOMEM;
3998*4882a593Smuzhiyun 
3999*4882a593Smuzhiyun 	fp.data = *data;
4000*4882a593Smuzhiyun 	fp.len = *len;
4001*4882a593Smuzhiyun 
4002*4882a593Smuzhiyun 	rc = policydb_write(&policy->policydb, &fp);
4003*4882a593Smuzhiyun 	if (rc)
4004*4882a593Smuzhiyun 		return rc;
4005*4882a593Smuzhiyun 
4006*4882a593Smuzhiyun 	*len = (unsigned long)fp.data - (unsigned long)*data;
4007*4882a593Smuzhiyun 	return 0;
4008*4882a593Smuzhiyun 
4009*4882a593Smuzhiyun }
4010