xref: /OK3568_Linux_fs/kernel/security/apparmor/label.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AppArmor security module
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This file contains AppArmor label definitions
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright 2017 Canonical Ltd.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/audit.h>
11*4882a593Smuzhiyun #include <linux/seq_file.h>
12*4882a593Smuzhiyun #include <linux/sort.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "include/apparmor.h"
15*4882a593Smuzhiyun #include "include/cred.h"
16*4882a593Smuzhiyun #include "include/label.h"
17*4882a593Smuzhiyun #include "include/policy.h"
18*4882a593Smuzhiyun #include "include/secid.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun  * the aa_label represents the set of profiles confining an object
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Labels maintain a reference count to the set of pointers they reference
25*4882a593Smuzhiyun  * Labels are ref counted by
26*4882a593Smuzhiyun  *   tasks and object via the security field/security context off the field
27*4882a593Smuzhiyun  *   code - will take a ref count on a label if it needs the label
28*4882a593Smuzhiyun  *          beyond what is possible with an rcu_read_lock.
29*4882a593Smuzhiyun  *   profiles - each profile is a label
30*4882a593Smuzhiyun  *   secids - a pinned secid will keep a refcount of the label it is
31*4882a593Smuzhiyun  *          referencing
32*4882a593Smuzhiyun  *   objects - inode, files, sockets, ...
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * Labels are not ref counted by the label set, so they maybe removed and
35*4882a593Smuzhiyun  * freed when no longer in use.
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define PROXY_POISON 97
40*4882a593Smuzhiyun #define LABEL_POISON 100
41*4882a593Smuzhiyun 
free_proxy(struct aa_proxy * proxy)42*4882a593Smuzhiyun static void free_proxy(struct aa_proxy *proxy)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	if (proxy) {
45*4882a593Smuzhiyun 		/* p->label will not updated any more as p is dead */
46*4882a593Smuzhiyun 		aa_put_label(rcu_dereference_protected(proxy->label, true));
47*4882a593Smuzhiyun 		memset(proxy, 0, sizeof(*proxy));
48*4882a593Smuzhiyun 		RCU_INIT_POINTER(proxy->label, (struct aa_label *)PROXY_POISON);
49*4882a593Smuzhiyun 		kfree(proxy);
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
aa_proxy_kref(struct kref * kref)53*4882a593Smuzhiyun void aa_proxy_kref(struct kref *kref)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	struct aa_proxy *proxy = container_of(kref, struct aa_proxy, count);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	free_proxy(proxy);
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
aa_alloc_proxy(struct aa_label * label,gfp_t gfp)60*4882a593Smuzhiyun struct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct aa_proxy *new;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	new = kzalloc(sizeof(struct aa_proxy), gfp);
65*4882a593Smuzhiyun 	if (new) {
66*4882a593Smuzhiyun 		kref_init(&new->count);
67*4882a593Smuzhiyun 		rcu_assign_pointer(new->label, aa_get_label(label));
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 	return new;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* requires profile list write lock held */
__aa_proxy_redirect(struct aa_label * orig,struct aa_label * new)73*4882a593Smuzhiyun void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct aa_label *tmp;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	AA_BUG(!orig);
78*4882a593Smuzhiyun 	AA_BUG(!new);
79*4882a593Smuzhiyun 	lockdep_assert_held_write(&labels_set(orig)->lock);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	tmp = rcu_dereference_protected(orig->proxy->label,
82*4882a593Smuzhiyun 					&labels_ns(orig)->lock);
83*4882a593Smuzhiyun 	rcu_assign_pointer(orig->proxy->label, aa_get_label(new));
84*4882a593Smuzhiyun 	orig->flags |= FLAG_STALE;
85*4882a593Smuzhiyun 	aa_put_label(tmp);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
__proxy_share(struct aa_label * old,struct aa_label * new)88*4882a593Smuzhiyun static void __proxy_share(struct aa_label *old, struct aa_label *new)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct aa_proxy *proxy = new->proxy;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	new->proxy = aa_get_proxy(old->proxy);
93*4882a593Smuzhiyun 	__aa_proxy_redirect(old, new);
94*4882a593Smuzhiyun 	aa_put_proxy(proxy);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /**
99*4882a593Smuzhiyun  * ns_cmp - compare ns for label set ordering
100*4882a593Smuzhiyun  * @a: ns to compare (NOT NULL)
101*4882a593Smuzhiyun  * @b: ns to compare (NOT NULL)
102*4882a593Smuzhiyun  *
103*4882a593Smuzhiyun  * Returns: <0 if a < b
104*4882a593Smuzhiyun  *          ==0 if a == b
105*4882a593Smuzhiyun  *          >0  if a > b
106*4882a593Smuzhiyun  */
ns_cmp(struct aa_ns * a,struct aa_ns * b)107*4882a593Smuzhiyun static int ns_cmp(struct aa_ns *a, struct aa_ns *b)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	int res;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	AA_BUG(!a);
112*4882a593Smuzhiyun 	AA_BUG(!b);
113*4882a593Smuzhiyun 	AA_BUG(!a->base.hname);
114*4882a593Smuzhiyun 	AA_BUG(!b->base.hname);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (a == b)
117*4882a593Smuzhiyun 		return 0;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	res = a->level - b->level;
120*4882a593Smuzhiyun 	if (res)
121*4882a593Smuzhiyun 		return res;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return strcmp(a->base.hname, b->base.hname);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun /**
127*4882a593Smuzhiyun  * profile_cmp - profile comparison for set ordering
128*4882a593Smuzhiyun  * @a: profile to compare (NOT NULL)
129*4882a593Smuzhiyun  * @b: profile to compare (NOT NULL)
130*4882a593Smuzhiyun  *
131*4882a593Smuzhiyun  * Returns: <0  if a < b
132*4882a593Smuzhiyun  *          ==0 if a == b
133*4882a593Smuzhiyun  *          >0  if a > b
134*4882a593Smuzhiyun  */
profile_cmp(struct aa_profile * a,struct aa_profile * b)135*4882a593Smuzhiyun static int profile_cmp(struct aa_profile *a, struct aa_profile *b)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	int res;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	AA_BUG(!a);
140*4882a593Smuzhiyun 	AA_BUG(!b);
141*4882a593Smuzhiyun 	AA_BUG(!a->ns);
142*4882a593Smuzhiyun 	AA_BUG(!b->ns);
143*4882a593Smuzhiyun 	AA_BUG(!a->base.hname);
144*4882a593Smuzhiyun 	AA_BUG(!b->base.hname);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if (a == b || a->base.hname == b->base.hname)
147*4882a593Smuzhiyun 		return 0;
148*4882a593Smuzhiyun 	res = ns_cmp(a->ns, b->ns);
149*4882a593Smuzhiyun 	if (res)
150*4882a593Smuzhiyun 		return res;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return strcmp(a->base.hname, b->base.hname);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /**
156*4882a593Smuzhiyun  * vec_cmp - label comparison for set ordering
157*4882a593Smuzhiyun  * @a: label to compare (NOT NULL)
158*4882a593Smuzhiyun  * @vec: vector of profiles to compare (NOT NULL)
159*4882a593Smuzhiyun  * @n: length of @vec
160*4882a593Smuzhiyun  *
161*4882a593Smuzhiyun  * Returns: <0  if a < vec
162*4882a593Smuzhiyun  *          ==0 if a == vec
163*4882a593Smuzhiyun  *          >0  if a > vec
164*4882a593Smuzhiyun  */
vec_cmp(struct aa_profile ** a,int an,struct aa_profile ** b,int bn)165*4882a593Smuzhiyun static int vec_cmp(struct aa_profile **a, int an, struct aa_profile **b, int bn)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	int i;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	AA_BUG(!a);
170*4882a593Smuzhiyun 	AA_BUG(!*a);
171*4882a593Smuzhiyun 	AA_BUG(!b);
172*4882a593Smuzhiyun 	AA_BUG(!*b);
173*4882a593Smuzhiyun 	AA_BUG(an <= 0);
174*4882a593Smuzhiyun 	AA_BUG(bn <= 0);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	for (i = 0; i < an && i < bn; i++) {
177*4882a593Smuzhiyun 		int res = profile_cmp(a[i], b[i]);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		if (res != 0)
180*4882a593Smuzhiyun 			return res;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return an - bn;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
vec_is_stale(struct aa_profile ** vec,int n)186*4882a593Smuzhiyun static bool vec_is_stale(struct aa_profile **vec, int n)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	int i;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	AA_BUG(!vec);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	for (i = 0; i < n; i++) {
193*4882a593Smuzhiyun 		if (profile_is_stale(vec[i]))
194*4882a593Smuzhiyun 			return true;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return false;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
vec_unconfined(struct aa_profile ** vec,int n)200*4882a593Smuzhiyun static bool vec_unconfined(struct aa_profile **vec, int n)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	int i;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	AA_BUG(!vec);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	for (i = 0; i < n; i++) {
207*4882a593Smuzhiyun 		if (!profile_unconfined(vec[i]))
208*4882a593Smuzhiyun 			return false;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	return true;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
sort_cmp(const void * a,const void * b)214*4882a593Smuzhiyun static int sort_cmp(const void *a, const void *b)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	return profile_cmp(*(struct aa_profile **)a, *(struct aa_profile **)b);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun  * assumes vec is sorted
221*4882a593Smuzhiyun  * Assumes @vec has null terminator at vec[n], and will null terminate
222*4882a593Smuzhiyun  * vec[n - dups]
223*4882a593Smuzhiyun  */
unique(struct aa_profile ** vec,int n)224*4882a593Smuzhiyun static inline int unique(struct aa_profile **vec, int n)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int i, pos, dups = 0;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	AA_BUG(n < 1);
229*4882a593Smuzhiyun 	AA_BUG(!vec);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	pos = 0;
232*4882a593Smuzhiyun 	for (i = 1; i < n; i++) {
233*4882a593Smuzhiyun 		int res = profile_cmp(vec[pos], vec[i]);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 		AA_BUG(res > 0, "vec not sorted");
236*4882a593Smuzhiyun 		if (res == 0) {
237*4882a593Smuzhiyun 			/* drop duplicate */
238*4882a593Smuzhiyun 			aa_put_profile(vec[i]);
239*4882a593Smuzhiyun 			dups++;
240*4882a593Smuzhiyun 			continue;
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 		pos++;
243*4882a593Smuzhiyun 		if (dups)
244*4882a593Smuzhiyun 			vec[pos] = vec[i];
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	AA_BUG(dups < 0);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return dups;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /**
253*4882a593Smuzhiyun  * aa_vec_unique - canonical sort and unique a list of profiles
254*4882a593Smuzhiyun  * @n: number of refcounted profiles in the list (@n > 0)
255*4882a593Smuzhiyun  * @vec: list of profiles to sort and merge
256*4882a593Smuzhiyun  *
257*4882a593Smuzhiyun  * Returns: the number of duplicates eliminated == references put
258*4882a593Smuzhiyun  *
259*4882a593Smuzhiyun  * If @flags & VEC_FLAG_TERMINATE @vec has null terminator at vec[n], and will
260*4882a593Smuzhiyun  * null terminate vec[n - dups]
261*4882a593Smuzhiyun  */
aa_vec_unique(struct aa_profile ** vec,int n,int flags)262*4882a593Smuzhiyun int aa_vec_unique(struct aa_profile **vec, int n, int flags)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	int i, dups = 0;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	AA_BUG(n < 1);
267*4882a593Smuzhiyun 	AA_BUG(!vec);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	/* vecs are usually small and inorder, have a fallback for larger */
270*4882a593Smuzhiyun 	if (n > 8) {
271*4882a593Smuzhiyun 		sort(vec, n, sizeof(struct aa_profile *), sort_cmp, NULL);
272*4882a593Smuzhiyun 		dups = unique(vec, n);
273*4882a593Smuzhiyun 		goto out;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	/* insertion sort + unique in one */
277*4882a593Smuzhiyun 	for (i = 1; i < n; i++) {
278*4882a593Smuzhiyun 		struct aa_profile *tmp = vec[i];
279*4882a593Smuzhiyun 		int pos, j;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 		for (pos = i - 1 - dups; pos >= 0; pos--) {
282*4882a593Smuzhiyun 			int res = profile_cmp(vec[pos], tmp);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 			if (res == 0) {
285*4882a593Smuzhiyun 				/* drop duplicate entry */
286*4882a593Smuzhiyun 				aa_put_profile(tmp);
287*4882a593Smuzhiyun 				dups++;
288*4882a593Smuzhiyun 				goto continue_outer;
289*4882a593Smuzhiyun 			} else if (res < 0)
290*4882a593Smuzhiyun 				break;
291*4882a593Smuzhiyun 		}
292*4882a593Smuzhiyun 		/* pos is at entry < tmp, or index -1. Set to insert pos */
293*4882a593Smuzhiyun 		pos++;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		for (j = i - dups; j > pos; j--)
296*4882a593Smuzhiyun 			vec[j] = vec[j - 1];
297*4882a593Smuzhiyun 		vec[pos] = tmp;
298*4882a593Smuzhiyun continue_outer:
299*4882a593Smuzhiyun 		;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	AA_BUG(dups < 0);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun out:
305*4882a593Smuzhiyun 	if (flags & VEC_FLAG_TERMINATE)
306*4882a593Smuzhiyun 		vec[n - dups] = NULL;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return dups;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 
aa_label_destroy(struct aa_label * label)312*4882a593Smuzhiyun void aa_label_destroy(struct aa_label *label)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	AA_BUG(!label);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	if (!label_isprofile(label)) {
317*4882a593Smuzhiyun 		struct aa_profile *profile;
318*4882a593Smuzhiyun 		struct label_it i;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 		aa_put_str(label->hname);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		label_for_each(i, label, profile) {
323*4882a593Smuzhiyun 			aa_put_profile(profile);
324*4882a593Smuzhiyun 			label->vec[i.i] = (struct aa_profile *)
325*4882a593Smuzhiyun 					   (LABEL_POISON + (long) i.i);
326*4882a593Smuzhiyun 		}
327*4882a593Smuzhiyun 	}
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (label->proxy) {
330*4882a593Smuzhiyun 		if (rcu_dereference_protected(label->proxy->label, true) == label)
331*4882a593Smuzhiyun 			rcu_assign_pointer(label->proxy->label, NULL);
332*4882a593Smuzhiyun 		aa_put_proxy(label->proxy);
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	aa_free_secid(label->secid);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	label->proxy = (struct aa_proxy *) PROXY_POISON + 1;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
aa_label_free(struct aa_label * label)339*4882a593Smuzhiyun void aa_label_free(struct aa_label *label)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	if (!label)
342*4882a593Smuzhiyun 		return;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	aa_label_destroy(label);
345*4882a593Smuzhiyun 	kfree(label);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
label_free_switch(struct aa_label * label)348*4882a593Smuzhiyun static void label_free_switch(struct aa_label *label)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	if (label->flags & FLAG_NS_COUNT)
351*4882a593Smuzhiyun 		aa_free_ns(labels_ns(label));
352*4882a593Smuzhiyun 	else if (label_isprofile(label))
353*4882a593Smuzhiyun 		aa_free_profile(labels_profile(label));
354*4882a593Smuzhiyun 	else
355*4882a593Smuzhiyun 		aa_label_free(label);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
label_free_rcu(struct rcu_head * head)358*4882a593Smuzhiyun static void label_free_rcu(struct rcu_head *head)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	struct aa_label *label = container_of(head, struct aa_label, rcu);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (label->flags & FLAG_IN_TREE)
363*4882a593Smuzhiyun 		(void) aa_label_remove(label);
364*4882a593Smuzhiyun 	label_free_switch(label);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
aa_label_kref(struct kref * kref)367*4882a593Smuzhiyun void aa_label_kref(struct kref *kref)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	struct aa_label *label = container_of(kref, struct aa_label, count);
370*4882a593Smuzhiyun 	struct aa_ns *ns = labels_ns(label);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (!ns) {
373*4882a593Smuzhiyun 		/* never live, no rcu callback needed, just using the fn */
374*4882a593Smuzhiyun 		label_free_switch(label);
375*4882a593Smuzhiyun 		return;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 	/* TODO: update labels_profile macro so it works here */
378*4882a593Smuzhiyun 	AA_BUG(label_isprofile(label) &&
379*4882a593Smuzhiyun 	       on_list_rcu(&label->vec[0]->base.profiles));
380*4882a593Smuzhiyun 	AA_BUG(label_isprofile(label) &&
381*4882a593Smuzhiyun 	       on_list_rcu(&label->vec[0]->base.list));
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	/* TODO: if compound label and not stale add to reclaim cache */
384*4882a593Smuzhiyun 	call_rcu(&label->rcu, label_free_rcu);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
label_free_or_put_new(struct aa_label * label,struct aa_label * new)387*4882a593Smuzhiyun static void label_free_or_put_new(struct aa_label *label, struct aa_label *new)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	if (label != new)
390*4882a593Smuzhiyun 		/* need to free directly to break circular ref with proxy */
391*4882a593Smuzhiyun 		aa_label_free(new);
392*4882a593Smuzhiyun 	else
393*4882a593Smuzhiyun 		aa_put_label(new);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
aa_label_init(struct aa_label * label,int size,gfp_t gfp)396*4882a593Smuzhiyun bool aa_label_init(struct aa_label *label, int size, gfp_t gfp)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	AA_BUG(!label);
399*4882a593Smuzhiyun 	AA_BUG(size < 1);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (aa_alloc_secid(label, gfp) < 0)
402*4882a593Smuzhiyun 		return false;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	label->size = size;			/* doesn't include null */
405*4882a593Smuzhiyun 	label->vec[size] = NULL;		/* null terminate */
406*4882a593Smuzhiyun 	kref_init(&label->count);
407*4882a593Smuzhiyun 	RB_CLEAR_NODE(&label->node);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return true;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun /**
413*4882a593Smuzhiyun  * aa_label_alloc - allocate a label with a profile vector of @size length
414*4882a593Smuzhiyun  * @size: size of profile vector in the label
415*4882a593Smuzhiyun  * @proxy: proxy to use OR null if to allocate a new one
416*4882a593Smuzhiyun  * @gfp: memory allocation type
417*4882a593Smuzhiyun  *
418*4882a593Smuzhiyun  * Returns: new label
419*4882a593Smuzhiyun  *     else NULL if failed
420*4882a593Smuzhiyun  */
aa_label_alloc(int size,struct aa_proxy * proxy,gfp_t gfp)421*4882a593Smuzhiyun struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun 	struct aa_label *new;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	AA_BUG(size < 1);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/*  + 1 for null terminator entry on vec */
428*4882a593Smuzhiyun 	new = kzalloc(sizeof(*new) + sizeof(struct aa_profile *) * (size + 1),
429*4882a593Smuzhiyun 			gfp);
430*4882a593Smuzhiyun 	AA_DEBUG("%s (%p)\n", __func__, new);
431*4882a593Smuzhiyun 	if (!new)
432*4882a593Smuzhiyun 		goto fail;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (!aa_label_init(new, size, gfp))
435*4882a593Smuzhiyun 		goto fail;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	if (!proxy) {
438*4882a593Smuzhiyun 		proxy = aa_alloc_proxy(new, gfp);
439*4882a593Smuzhiyun 		if (!proxy)
440*4882a593Smuzhiyun 			goto fail;
441*4882a593Smuzhiyun 	} else
442*4882a593Smuzhiyun 		aa_get_proxy(proxy);
443*4882a593Smuzhiyun 	/* just set new's proxy, don't redirect proxy here if it was passed in*/
444*4882a593Smuzhiyun 	new->proxy = proxy;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	return new;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun fail:
449*4882a593Smuzhiyun 	kfree(new);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return NULL;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun /**
456*4882a593Smuzhiyun  * label_cmp - label comparison for set ordering
457*4882a593Smuzhiyun  * @a: label to compare (NOT NULL)
458*4882a593Smuzhiyun  * @b: label to compare (NOT NULL)
459*4882a593Smuzhiyun  *
460*4882a593Smuzhiyun  * Returns: <0  if a < b
461*4882a593Smuzhiyun  *          ==0 if a == b
462*4882a593Smuzhiyun  *          >0  if a > b
463*4882a593Smuzhiyun  */
label_cmp(struct aa_label * a,struct aa_label * b)464*4882a593Smuzhiyun static int label_cmp(struct aa_label *a, struct aa_label *b)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun 	AA_BUG(!b);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (a == b)
469*4882a593Smuzhiyun 		return 0;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	return vec_cmp(a->vec, a->size, b->vec, b->size);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun /* helper fn for label_for_each_confined */
aa_label_next_confined(struct aa_label * label,int i)475*4882a593Smuzhiyun int aa_label_next_confined(struct aa_label *label, int i)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	AA_BUG(!label);
478*4882a593Smuzhiyun 	AA_BUG(i < 0);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	for (; i < label->size; i++) {
481*4882a593Smuzhiyun 		if (!profile_unconfined(label->vec[i]))
482*4882a593Smuzhiyun 			return i;
483*4882a593Smuzhiyun 	}
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	return i;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun /**
489*4882a593Smuzhiyun  * aa_label_next_not_in_set - return the next profile of @sub not in @set
490*4882a593Smuzhiyun  * @I: label iterator
491*4882a593Smuzhiyun  * @set: label to test against
492*4882a593Smuzhiyun  * @sub: label to if is subset of @set
493*4882a593Smuzhiyun  *
494*4882a593Smuzhiyun  * Returns: profile in @sub that is not in @set, with iterator set pos after
495*4882a593Smuzhiyun  *     else NULL if @sub is a subset of @set
496*4882a593Smuzhiyun  */
__aa_label_next_not_in_set(struct label_it * I,struct aa_label * set,struct aa_label * sub)497*4882a593Smuzhiyun struct aa_profile *__aa_label_next_not_in_set(struct label_it *I,
498*4882a593Smuzhiyun 					      struct aa_label *set,
499*4882a593Smuzhiyun 					      struct aa_label *sub)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	AA_BUG(!set);
502*4882a593Smuzhiyun 	AA_BUG(!I);
503*4882a593Smuzhiyun 	AA_BUG(I->i < 0);
504*4882a593Smuzhiyun 	AA_BUG(I->i > set->size);
505*4882a593Smuzhiyun 	AA_BUG(!sub);
506*4882a593Smuzhiyun 	AA_BUG(I->j < 0);
507*4882a593Smuzhiyun 	AA_BUG(I->j > sub->size);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	while (I->j < sub->size && I->i < set->size) {
510*4882a593Smuzhiyun 		int res = profile_cmp(sub->vec[I->j], set->vec[I->i]);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 		if (res == 0) {
513*4882a593Smuzhiyun 			(I->j)++;
514*4882a593Smuzhiyun 			(I->i)++;
515*4882a593Smuzhiyun 		} else if (res > 0)
516*4882a593Smuzhiyun 			(I->i)++;
517*4882a593Smuzhiyun 		else
518*4882a593Smuzhiyun 			return sub->vec[(I->j)++];
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (I->j < sub->size)
522*4882a593Smuzhiyun 		return sub->vec[(I->j)++];
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return NULL;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun /**
528*4882a593Smuzhiyun  * aa_label_is_subset - test if @sub is a subset of @set
529*4882a593Smuzhiyun  * @set: label to test against
530*4882a593Smuzhiyun  * @sub: label to test if is subset of @set
531*4882a593Smuzhiyun  *
532*4882a593Smuzhiyun  * Returns: true if @sub is subset of @set
533*4882a593Smuzhiyun  *     else false
534*4882a593Smuzhiyun  */
aa_label_is_subset(struct aa_label * set,struct aa_label * sub)535*4882a593Smuzhiyun bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	struct label_it i = { };
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	AA_BUG(!set);
540*4882a593Smuzhiyun 	AA_BUG(!sub);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (sub == set)
543*4882a593Smuzhiyun 		return true;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	return __aa_label_next_not_in_set(&i, set, sub) == NULL;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun /**
549*4882a593Smuzhiyun  * aa_label_is_unconfined_subset - test if @sub is a subset of @set
550*4882a593Smuzhiyun  * @set: label to test against
551*4882a593Smuzhiyun  * @sub: label to test if is subset of @set
552*4882a593Smuzhiyun  *
553*4882a593Smuzhiyun  * This checks for subset but taking into account unconfined. IF
554*4882a593Smuzhiyun  * @sub contains an unconfined profile that does not have a matching
555*4882a593Smuzhiyun  * unconfined in @set then this will not cause the test to fail.
556*4882a593Smuzhiyun  * Conversely we don't care about an unconfined in @set that is not in
557*4882a593Smuzhiyun  * @sub
558*4882a593Smuzhiyun  *
559*4882a593Smuzhiyun  * Returns: true if @sub is special_subset of @set
560*4882a593Smuzhiyun  *     else false
561*4882a593Smuzhiyun  */
aa_label_is_unconfined_subset(struct aa_label * set,struct aa_label * sub)562*4882a593Smuzhiyun bool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun 	struct label_it i = { };
565*4882a593Smuzhiyun 	struct aa_profile *p;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	AA_BUG(!set);
568*4882a593Smuzhiyun 	AA_BUG(!sub);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	if (sub == set)
571*4882a593Smuzhiyun 		return true;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	do {
574*4882a593Smuzhiyun 		p = __aa_label_next_not_in_set(&i, set, sub);
575*4882a593Smuzhiyun 		if (p && !profile_unconfined(p))
576*4882a593Smuzhiyun 			break;
577*4882a593Smuzhiyun 	} while (p);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	return p == NULL;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun /**
584*4882a593Smuzhiyun  * __label_remove - remove @label from the label set
585*4882a593Smuzhiyun  * @l: label to remove
586*4882a593Smuzhiyun  * @new: label to redirect to
587*4882a593Smuzhiyun  *
588*4882a593Smuzhiyun  * Requires: labels_set(@label)->lock write_lock
589*4882a593Smuzhiyun  * Returns:  true if the label was in the tree and removed
590*4882a593Smuzhiyun  */
__label_remove(struct aa_label * label,struct aa_label * new)591*4882a593Smuzhiyun static bool __label_remove(struct aa_label *label, struct aa_label *new)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun 	struct aa_labelset *ls = labels_set(label);
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	AA_BUG(!ls);
596*4882a593Smuzhiyun 	AA_BUG(!label);
597*4882a593Smuzhiyun 	lockdep_assert_held_write(&ls->lock);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (new)
600*4882a593Smuzhiyun 		__aa_proxy_redirect(label, new);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	if (!label_is_stale(label))
603*4882a593Smuzhiyun 		__label_make_stale(label);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	if (label->flags & FLAG_IN_TREE) {
606*4882a593Smuzhiyun 		rb_erase(&label->node, &ls->root);
607*4882a593Smuzhiyun 		label->flags &= ~FLAG_IN_TREE;
608*4882a593Smuzhiyun 		return true;
609*4882a593Smuzhiyun 	}
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	return false;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun /**
615*4882a593Smuzhiyun  * __label_replace - replace @old with @new in label set
616*4882a593Smuzhiyun  * @old: label to remove from label set
617*4882a593Smuzhiyun  * @new: label to replace @old with
618*4882a593Smuzhiyun  *
619*4882a593Smuzhiyun  * Requires: labels_set(@old)->lock write_lock
620*4882a593Smuzhiyun  *           valid ref count be held on @new
621*4882a593Smuzhiyun  * Returns: true if @old was in set and replaced by @new
622*4882a593Smuzhiyun  *
623*4882a593Smuzhiyun  * Note: current implementation requires label set be order in such a way
624*4882a593Smuzhiyun  *       that @new directly replaces @old position in the set (ie.
625*4882a593Smuzhiyun  *       using pointer comparison of the label address would not work)
626*4882a593Smuzhiyun  */
__label_replace(struct aa_label * old,struct aa_label * new)627*4882a593Smuzhiyun static bool __label_replace(struct aa_label *old, struct aa_label *new)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	struct aa_labelset *ls = labels_set(old);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	AA_BUG(!ls);
632*4882a593Smuzhiyun 	AA_BUG(!old);
633*4882a593Smuzhiyun 	AA_BUG(!new);
634*4882a593Smuzhiyun 	lockdep_assert_held_write(&ls->lock);
635*4882a593Smuzhiyun 	AA_BUG(new->flags & FLAG_IN_TREE);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	if (!label_is_stale(old))
638*4882a593Smuzhiyun 		__label_make_stale(old);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (old->flags & FLAG_IN_TREE) {
641*4882a593Smuzhiyun 		rb_replace_node(&old->node, &new->node, &ls->root);
642*4882a593Smuzhiyun 		old->flags &= ~FLAG_IN_TREE;
643*4882a593Smuzhiyun 		new->flags |= FLAG_IN_TREE;
644*4882a593Smuzhiyun 		return true;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	return false;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun /**
651*4882a593Smuzhiyun  * __label_insert - attempt to insert @l into a label set
652*4882a593Smuzhiyun  * @ls: set of labels to insert @l into (NOT NULL)
653*4882a593Smuzhiyun  * @label: new label to insert (NOT NULL)
654*4882a593Smuzhiyun  * @replace: whether insertion should replace existing entry that is not stale
655*4882a593Smuzhiyun  *
656*4882a593Smuzhiyun  * Requires: @ls->lock
657*4882a593Smuzhiyun  *           caller to hold a valid ref on l
658*4882a593Smuzhiyun  *           if @replace is true l has a preallocated proxy associated
659*4882a593Smuzhiyun  * Returns: @l if successful in inserting @l - with additional refcount
660*4882a593Smuzhiyun  *          else ref counted equivalent label that is already in the set,
661*4882a593Smuzhiyun  *          the else condition only happens if @replace is false
662*4882a593Smuzhiyun  */
__label_insert(struct aa_labelset * ls,struct aa_label * label,bool replace)663*4882a593Smuzhiyun static struct aa_label *__label_insert(struct aa_labelset *ls,
664*4882a593Smuzhiyun 				       struct aa_label *label, bool replace)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	struct rb_node **new, *parent = NULL;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	AA_BUG(!ls);
669*4882a593Smuzhiyun 	AA_BUG(!label);
670*4882a593Smuzhiyun 	AA_BUG(labels_set(label) != ls);
671*4882a593Smuzhiyun 	lockdep_assert_held_write(&ls->lock);
672*4882a593Smuzhiyun 	AA_BUG(label->flags & FLAG_IN_TREE);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/* Figure out where to put new node */
675*4882a593Smuzhiyun 	new = &ls->root.rb_node;
676*4882a593Smuzhiyun 	while (*new) {
677*4882a593Smuzhiyun 		struct aa_label *this = rb_entry(*new, struct aa_label, node);
678*4882a593Smuzhiyun 		int result = label_cmp(label, this);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 		parent = *new;
681*4882a593Smuzhiyun 		if (result == 0) {
682*4882a593Smuzhiyun 			/* !__aa_get_label means queued for destruction,
683*4882a593Smuzhiyun 			 * so replace in place, however the label has
684*4882a593Smuzhiyun 			 * died before the replacement so do not share
685*4882a593Smuzhiyun 			 * the proxy
686*4882a593Smuzhiyun 			 */
687*4882a593Smuzhiyun 			if (!replace && !label_is_stale(this)) {
688*4882a593Smuzhiyun 				if (__aa_get_label(this))
689*4882a593Smuzhiyun 					return this;
690*4882a593Smuzhiyun 			} else
691*4882a593Smuzhiyun 				__proxy_share(this, label);
692*4882a593Smuzhiyun 			AA_BUG(!__label_replace(this, label));
693*4882a593Smuzhiyun 			return aa_get_label(label);
694*4882a593Smuzhiyun 		} else if (result < 0)
695*4882a593Smuzhiyun 			new = &((*new)->rb_left);
696*4882a593Smuzhiyun 		else /* (result > 0) */
697*4882a593Smuzhiyun 			new = &((*new)->rb_right);
698*4882a593Smuzhiyun 	}
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	/* Add new node and rebalance tree. */
701*4882a593Smuzhiyun 	rb_link_node(&label->node, parent, new);
702*4882a593Smuzhiyun 	rb_insert_color(&label->node, &ls->root);
703*4882a593Smuzhiyun 	label->flags |= FLAG_IN_TREE;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	return aa_get_label(label);
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun /**
709*4882a593Smuzhiyun  * __vec_find - find label that matches @vec in label set
710*4882a593Smuzhiyun  * @vec: vec of profiles to find matching label for (NOT NULL)
711*4882a593Smuzhiyun  * @n: length of @vec
712*4882a593Smuzhiyun  *
713*4882a593Smuzhiyun  * Requires: @vec_labelset(vec) lock held
714*4882a593Smuzhiyun  *           caller to hold a valid ref on l
715*4882a593Smuzhiyun  *
716*4882a593Smuzhiyun  * Returns: ref counted @label if matching label is in tree
717*4882a593Smuzhiyun  *          ref counted label that is equiv to @l in tree
718*4882a593Smuzhiyun  *     else NULL if @vec equiv is not in tree
719*4882a593Smuzhiyun  */
__vec_find(struct aa_profile ** vec,int n)720*4882a593Smuzhiyun static struct aa_label *__vec_find(struct aa_profile **vec, int n)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	struct rb_node *node;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	AA_BUG(!vec);
725*4882a593Smuzhiyun 	AA_BUG(!*vec);
726*4882a593Smuzhiyun 	AA_BUG(n <= 0);
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	node = vec_labelset(vec, n)->root.rb_node;
729*4882a593Smuzhiyun 	while (node) {
730*4882a593Smuzhiyun 		struct aa_label *this = rb_entry(node, struct aa_label, node);
731*4882a593Smuzhiyun 		int result = vec_cmp(this->vec, this->size, vec, n);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		if (result > 0)
734*4882a593Smuzhiyun 			node = node->rb_left;
735*4882a593Smuzhiyun 		else if (result < 0)
736*4882a593Smuzhiyun 			node = node->rb_right;
737*4882a593Smuzhiyun 		else
738*4882a593Smuzhiyun 			return __aa_get_label(this);
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	return NULL;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun /**
745*4882a593Smuzhiyun  * __label_find - find label @label in label set
746*4882a593Smuzhiyun  * @label: label to find (NOT NULL)
747*4882a593Smuzhiyun  *
748*4882a593Smuzhiyun  * Requires: labels_set(@label)->lock held
749*4882a593Smuzhiyun  *           caller to hold a valid ref on l
750*4882a593Smuzhiyun  *
751*4882a593Smuzhiyun  * Returns: ref counted @label if @label is in tree OR
752*4882a593Smuzhiyun  *          ref counted label that is equiv to @label in tree
753*4882a593Smuzhiyun  *     else NULL if @label or equiv is not in tree
754*4882a593Smuzhiyun  */
__label_find(struct aa_label * label)755*4882a593Smuzhiyun static struct aa_label *__label_find(struct aa_label *label)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	AA_BUG(!label);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	return __vec_find(label->vec, label->size);
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun /**
764*4882a593Smuzhiyun  * aa_label_remove - remove a label from the labelset
765*4882a593Smuzhiyun  * @label: label to remove
766*4882a593Smuzhiyun  *
767*4882a593Smuzhiyun  * Returns: true if @label was removed from the tree
768*4882a593Smuzhiyun  *     else @label was not in tree so it could not be removed
769*4882a593Smuzhiyun  */
aa_label_remove(struct aa_label * label)770*4882a593Smuzhiyun bool aa_label_remove(struct aa_label *label)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	struct aa_labelset *ls = labels_set(label);
773*4882a593Smuzhiyun 	unsigned long flags;
774*4882a593Smuzhiyun 	bool res;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	AA_BUG(!ls);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
779*4882a593Smuzhiyun 	res = __label_remove(label, ns_unconfined(labels_ns(label)));
780*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	return res;
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun /**
786*4882a593Smuzhiyun  * aa_label_replace - replace a label @old with a new version @new
787*4882a593Smuzhiyun  * @old: label to replace
788*4882a593Smuzhiyun  * @new: label replacing @old
789*4882a593Smuzhiyun  *
790*4882a593Smuzhiyun  * Returns: true if @old was in tree and replaced
791*4882a593Smuzhiyun  *     else @old was not in tree, and @new was not inserted
792*4882a593Smuzhiyun  */
aa_label_replace(struct aa_label * old,struct aa_label * new)793*4882a593Smuzhiyun bool aa_label_replace(struct aa_label *old, struct aa_label *new)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun 	unsigned long flags;
796*4882a593Smuzhiyun 	bool res;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	if (name_is_shared(old, new) && labels_ns(old) == labels_ns(new)) {
799*4882a593Smuzhiyun 		write_lock_irqsave(&labels_set(old)->lock, flags);
800*4882a593Smuzhiyun 		if (old->proxy != new->proxy)
801*4882a593Smuzhiyun 			__proxy_share(old, new);
802*4882a593Smuzhiyun 		else
803*4882a593Smuzhiyun 			__aa_proxy_redirect(old, new);
804*4882a593Smuzhiyun 		res = __label_replace(old, new);
805*4882a593Smuzhiyun 		write_unlock_irqrestore(&labels_set(old)->lock, flags);
806*4882a593Smuzhiyun 	} else {
807*4882a593Smuzhiyun 		struct aa_label *l;
808*4882a593Smuzhiyun 		struct aa_labelset *ls = labels_set(old);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 		write_lock_irqsave(&ls->lock, flags);
811*4882a593Smuzhiyun 		res = __label_remove(old, new);
812*4882a593Smuzhiyun 		if (labels_ns(old) != labels_ns(new)) {
813*4882a593Smuzhiyun 			write_unlock_irqrestore(&ls->lock, flags);
814*4882a593Smuzhiyun 			ls = labels_set(new);
815*4882a593Smuzhiyun 			write_lock_irqsave(&ls->lock, flags);
816*4882a593Smuzhiyun 		}
817*4882a593Smuzhiyun 		l = __label_insert(ls, new, true);
818*4882a593Smuzhiyun 		res = (l == new);
819*4882a593Smuzhiyun 		write_unlock_irqrestore(&ls->lock, flags);
820*4882a593Smuzhiyun 		aa_put_label(l);
821*4882a593Smuzhiyun 	}
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	return res;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun /**
827*4882a593Smuzhiyun  * vec_find - find label @l in label set
828*4882a593Smuzhiyun  * @vec: array of profiles to find equiv label for (NOT NULL)
829*4882a593Smuzhiyun  * @n: length of @vec
830*4882a593Smuzhiyun  *
831*4882a593Smuzhiyun  * Returns: refcounted label if @vec equiv is in tree
832*4882a593Smuzhiyun  *     else NULL if @vec equiv is not in tree
833*4882a593Smuzhiyun  */
vec_find(struct aa_profile ** vec,int n)834*4882a593Smuzhiyun static struct aa_label *vec_find(struct aa_profile **vec, int n)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	struct aa_labelset *ls;
837*4882a593Smuzhiyun 	struct aa_label *label;
838*4882a593Smuzhiyun 	unsigned long flags;
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	AA_BUG(!vec);
841*4882a593Smuzhiyun 	AA_BUG(!*vec);
842*4882a593Smuzhiyun 	AA_BUG(n <= 0);
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	ls = vec_labelset(vec, n);
845*4882a593Smuzhiyun 	read_lock_irqsave(&ls->lock, flags);
846*4882a593Smuzhiyun 	label = __vec_find(vec, n);
847*4882a593Smuzhiyun 	read_unlock_irqrestore(&ls->lock, flags);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	return label;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun /* requires sort and merge done first */
vec_create_and_insert_label(struct aa_profile ** vec,int len,gfp_t gfp)853*4882a593Smuzhiyun static struct aa_label *vec_create_and_insert_label(struct aa_profile **vec,
854*4882a593Smuzhiyun 						    int len, gfp_t gfp)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun 	struct aa_label *label = NULL;
857*4882a593Smuzhiyun 	struct aa_labelset *ls;
858*4882a593Smuzhiyun 	unsigned long flags;
859*4882a593Smuzhiyun 	struct aa_label *new;
860*4882a593Smuzhiyun 	int i;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	AA_BUG(!vec);
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	if (len == 1)
865*4882a593Smuzhiyun 		return aa_get_label(&vec[0]->label);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	ls = labels_set(&vec[len - 1]->label);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	/* TODO: enable when read side is lockless
870*4882a593Smuzhiyun 	 * check if label exists before taking locks
871*4882a593Smuzhiyun 	 */
872*4882a593Smuzhiyun 	new = aa_label_alloc(len, NULL, gfp);
873*4882a593Smuzhiyun 	if (!new)
874*4882a593Smuzhiyun 		return NULL;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
877*4882a593Smuzhiyun 		new->vec[i] = aa_get_profile(vec[i]);
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
880*4882a593Smuzhiyun 	label = __label_insert(ls, new, false);
881*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
882*4882a593Smuzhiyun 	label_free_or_put_new(label, new);
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	return label;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
aa_vec_find_or_create_label(struct aa_profile ** vec,int len,gfp_t gfp)887*4882a593Smuzhiyun struct aa_label *aa_vec_find_or_create_label(struct aa_profile **vec, int len,
888*4882a593Smuzhiyun 					     gfp_t gfp)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	struct aa_label *label = vec_find(vec, len);
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	if (label)
893*4882a593Smuzhiyun 		return label;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	return vec_create_and_insert_label(vec, len, gfp);
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun /**
899*4882a593Smuzhiyun  * aa_label_find - find label @label in label set
900*4882a593Smuzhiyun  * @label: label to find (NOT NULL)
901*4882a593Smuzhiyun  *
902*4882a593Smuzhiyun  * Requires: caller to hold a valid ref on l
903*4882a593Smuzhiyun  *
904*4882a593Smuzhiyun  * Returns: refcounted @label if @label is in tree
905*4882a593Smuzhiyun  *          refcounted label that is equiv to @label in tree
906*4882a593Smuzhiyun  *     else NULL if @label or equiv is not in tree
907*4882a593Smuzhiyun  */
aa_label_find(struct aa_label * label)908*4882a593Smuzhiyun struct aa_label *aa_label_find(struct aa_label *label)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun 	AA_BUG(!label);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	return vec_find(label->vec, label->size);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun /**
917*4882a593Smuzhiyun  * aa_label_insert - insert label @label into @ls or return existing label
918*4882a593Smuzhiyun  * @ls - labelset to insert @label into
919*4882a593Smuzhiyun  * @label - label to insert
920*4882a593Smuzhiyun  *
921*4882a593Smuzhiyun  * Requires: caller to hold a valid ref on @label
922*4882a593Smuzhiyun  *
923*4882a593Smuzhiyun  * Returns: ref counted @label if successful in inserting @label
924*4882a593Smuzhiyun  *     else ref counted equivalent label that is already in the set
925*4882a593Smuzhiyun  */
aa_label_insert(struct aa_labelset * ls,struct aa_label * label)926*4882a593Smuzhiyun struct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *label)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun 	struct aa_label *l;
929*4882a593Smuzhiyun 	unsigned long flags;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	AA_BUG(!ls);
932*4882a593Smuzhiyun 	AA_BUG(!label);
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	/* check if label exists before taking lock */
935*4882a593Smuzhiyun 	if (!label_is_stale(label)) {
936*4882a593Smuzhiyun 		read_lock_irqsave(&ls->lock, flags);
937*4882a593Smuzhiyun 		l = __label_find(label);
938*4882a593Smuzhiyun 		read_unlock_irqrestore(&ls->lock, flags);
939*4882a593Smuzhiyun 		if (l)
940*4882a593Smuzhiyun 			return l;
941*4882a593Smuzhiyun 	}
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
944*4882a593Smuzhiyun 	l = __label_insert(ls, label, false);
945*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	return l;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun /**
952*4882a593Smuzhiyun  * aa_label_next_in_merge - find the next profile when merging @a and @b
953*4882a593Smuzhiyun  * @I: label iterator
954*4882a593Smuzhiyun  * @a: label to merge
955*4882a593Smuzhiyun  * @b: label to merge
956*4882a593Smuzhiyun  *
957*4882a593Smuzhiyun  * Returns: next profile
958*4882a593Smuzhiyun  *     else null if no more profiles
959*4882a593Smuzhiyun  */
aa_label_next_in_merge(struct label_it * I,struct aa_label * a,struct aa_label * b)960*4882a593Smuzhiyun struct aa_profile *aa_label_next_in_merge(struct label_it *I,
961*4882a593Smuzhiyun 					  struct aa_label *a,
962*4882a593Smuzhiyun 					  struct aa_label *b)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun 	AA_BUG(!a);
965*4882a593Smuzhiyun 	AA_BUG(!b);
966*4882a593Smuzhiyun 	AA_BUG(!I);
967*4882a593Smuzhiyun 	AA_BUG(I->i < 0);
968*4882a593Smuzhiyun 	AA_BUG(I->i > a->size);
969*4882a593Smuzhiyun 	AA_BUG(I->j < 0);
970*4882a593Smuzhiyun 	AA_BUG(I->j > b->size);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	if (I->i < a->size) {
973*4882a593Smuzhiyun 		if (I->j < b->size) {
974*4882a593Smuzhiyun 			int res = profile_cmp(a->vec[I->i], b->vec[I->j]);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 			if (res > 0)
977*4882a593Smuzhiyun 				return b->vec[(I->j)++];
978*4882a593Smuzhiyun 			if (res == 0)
979*4882a593Smuzhiyun 				(I->j)++;
980*4882a593Smuzhiyun 		}
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 		return a->vec[(I->i)++];
983*4882a593Smuzhiyun 	}
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	if (I->j < b->size)
986*4882a593Smuzhiyun 		return b->vec[(I->j)++];
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	return NULL;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun /**
992*4882a593Smuzhiyun  * label_merge_cmp - cmp of @a merging with @b against @z for set ordering
993*4882a593Smuzhiyun  * @a: label to merge then compare (NOT NULL)
994*4882a593Smuzhiyun  * @b: label to merge then compare (NOT NULL)
995*4882a593Smuzhiyun  * @z: label to compare merge against (NOT NULL)
996*4882a593Smuzhiyun  *
997*4882a593Smuzhiyun  * Assumes: using the most recent versions of @a, @b, and @z
998*4882a593Smuzhiyun  *
999*4882a593Smuzhiyun  * Returns: <0  if a < b
1000*4882a593Smuzhiyun  *          ==0 if a == b
1001*4882a593Smuzhiyun  *          >0  if a > b
1002*4882a593Smuzhiyun  */
label_merge_cmp(struct aa_label * a,struct aa_label * b,struct aa_label * z)1003*4882a593Smuzhiyun static int label_merge_cmp(struct aa_label *a, struct aa_label *b,
1004*4882a593Smuzhiyun 			   struct aa_label *z)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun 	struct aa_profile *p = NULL;
1007*4882a593Smuzhiyun 	struct label_it i = { };
1008*4882a593Smuzhiyun 	int k;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	AA_BUG(!a);
1011*4882a593Smuzhiyun 	AA_BUG(!b);
1012*4882a593Smuzhiyun 	AA_BUG(!z);
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	for (k = 0;
1015*4882a593Smuzhiyun 	     k < z->size && (p = aa_label_next_in_merge(&i, a, b));
1016*4882a593Smuzhiyun 	     k++) {
1017*4882a593Smuzhiyun 		int res = profile_cmp(p, z->vec[k]);
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 		if (res != 0)
1020*4882a593Smuzhiyun 			return res;
1021*4882a593Smuzhiyun 	}
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	if (p)
1024*4882a593Smuzhiyun 		return 1;
1025*4882a593Smuzhiyun 	else if (k < z->size)
1026*4882a593Smuzhiyun 		return -1;
1027*4882a593Smuzhiyun 	return 0;
1028*4882a593Smuzhiyun }
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun /**
1031*4882a593Smuzhiyun  * label_merge_insert - create a new label by merging @a and @b
1032*4882a593Smuzhiyun  * @new: preallocated label to merge into (NOT NULL)
1033*4882a593Smuzhiyun  * @a: label to merge with @b  (NOT NULL)
1034*4882a593Smuzhiyun  * @b: label to merge with @a  (NOT NULL)
1035*4882a593Smuzhiyun  *
1036*4882a593Smuzhiyun  * Requires: preallocated proxy
1037*4882a593Smuzhiyun  *
1038*4882a593Smuzhiyun  * Returns: ref counted label either @new if merge is unique
1039*4882a593Smuzhiyun  *          @a if @b is a subset of @a
1040*4882a593Smuzhiyun  *          @b if @a is a subset of @b
1041*4882a593Smuzhiyun  *
1042*4882a593Smuzhiyun  * NOTE: will not use @new if the merge results in @new == @a or @b
1043*4882a593Smuzhiyun  *
1044*4882a593Smuzhiyun  *       Must be used within labelset write lock to avoid racing with
1045*4882a593Smuzhiyun  *       setting labels stale.
1046*4882a593Smuzhiyun  */
label_merge_insert(struct aa_label * new,struct aa_label * a,struct aa_label * b)1047*4882a593Smuzhiyun static struct aa_label *label_merge_insert(struct aa_label *new,
1048*4882a593Smuzhiyun 					   struct aa_label *a,
1049*4882a593Smuzhiyun 					   struct aa_label *b)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun 	struct aa_label *label;
1052*4882a593Smuzhiyun 	struct aa_labelset *ls;
1053*4882a593Smuzhiyun 	struct aa_profile *next;
1054*4882a593Smuzhiyun 	struct label_it i;
1055*4882a593Smuzhiyun 	unsigned long flags;
1056*4882a593Smuzhiyun 	int k = 0, invcount = 0;
1057*4882a593Smuzhiyun 	bool stale = false;
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	AA_BUG(!a);
1060*4882a593Smuzhiyun 	AA_BUG(a->size < 0);
1061*4882a593Smuzhiyun 	AA_BUG(!b);
1062*4882a593Smuzhiyun 	AA_BUG(b->size < 0);
1063*4882a593Smuzhiyun 	AA_BUG(!new);
1064*4882a593Smuzhiyun 	AA_BUG(new->size < a->size + b->size);
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	label_for_each_in_merge(i, a, b, next) {
1067*4882a593Smuzhiyun 		AA_BUG(!next);
1068*4882a593Smuzhiyun 		if (profile_is_stale(next)) {
1069*4882a593Smuzhiyun 			new->vec[k] = aa_get_newest_profile(next);
1070*4882a593Smuzhiyun 			AA_BUG(!new->vec[k]->label.proxy);
1071*4882a593Smuzhiyun 			AA_BUG(!new->vec[k]->label.proxy->label);
1072*4882a593Smuzhiyun 			if (next->label.proxy != new->vec[k]->label.proxy)
1073*4882a593Smuzhiyun 				invcount++;
1074*4882a593Smuzhiyun 			k++;
1075*4882a593Smuzhiyun 			stale = true;
1076*4882a593Smuzhiyun 		} else
1077*4882a593Smuzhiyun 			new->vec[k++] = aa_get_profile(next);
1078*4882a593Smuzhiyun 	}
1079*4882a593Smuzhiyun 	/* set to actual size which is <= allocated len */
1080*4882a593Smuzhiyun 	new->size = k;
1081*4882a593Smuzhiyun 	new->vec[k] = NULL;
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (invcount) {
1084*4882a593Smuzhiyun 		new->size -= aa_vec_unique(&new->vec[0], new->size,
1085*4882a593Smuzhiyun 					   VEC_FLAG_TERMINATE);
1086*4882a593Smuzhiyun 		/* TODO: deal with reference labels */
1087*4882a593Smuzhiyun 		if (new->size == 1) {
1088*4882a593Smuzhiyun 			label = aa_get_label(&new->vec[0]->label);
1089*4882a593Smuzhiyun 			return label;
1090*4882a593Smuzhiyun 		}
1091*4882a593Smuzhiyun 	} else if (!stale) {
1092*4882a593Smuzhiyun 		/*
1093*4882a593Smuzhiyun 		 * merge could be same as a || b, note: it is not possible
1094*4882a593Smuzhiyun 		 * for new->size == a->size == b->size unless a == b
1095*4882a593Smuzhiyun 		 */
1096*4882a593Smuzhiyun 		if (k == a->size)
1097*4882a593Smuzhiyun 			return aa_get_label(a);
1098*4882a593Smuzhiyun 		else if (k == b->size)
1099*4882a593Smuzhiyun 			return aa_get_label(b);
1100*4882a593Smuzhiyun 	}
1101*4882a593Smuzhiyun 	if (vec_unconfined(new->vec, new->size))
1102*4882a593Smuzhiyun 		new->flags |= FLAG_UNCONFINED;
1103*4882a593Smuzhiyun 	ls = labels_set(new);
1104*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
1105*4882a593Smuzhiyun 	label = __label_insert(labels_set(new), new, false);
1106*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	return label;
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun /**
1112*4882a593Smuzhiyun  * labelset_of_merge - find which labelset a merged label should be inserted
1113*4882a593Smuzhiyun  * @a: label to merge and insert
1114*4882a593Smuzhiyun  * @b: label to merge and insert
1115*4882a593Smuzhiyun  *
1116*4882a593Smuzhiyun  * Returns: labelset that the merged label should be inserted into
1117*4882a593Smuzhiyun  */
labelset_of_merge(struct aa_label * a,struct aa_label * b)1118*4882a593Smuzhiyun static struct aa_labelset *labelset_of_merge(struct aa_label *a,
1119*4882a593Smuzhiyun 					     struct aa_label *b)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun 	struct aa_ns *nsa = labels_ns(a);
1122*4882a593Smuzhiyun 	struct aa_ns *nsb = labels_ns(b);
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	if (ns_cmp(nsa, nsb) <= 0)
1125*4882a593Smuzhiyun 		return &nsa->labels;
1126*4882a593Smuzhiyun 	return &nsb->labels;
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun /**
1130*4882a593Smuzhiyun  * __label_find_merge - find label that is equiv to merge of @a and @b
1131*4882a593Smuzhiyun  * @ls: set of labels to search (NOT NULL)
1132*4882a593Smuzhiyun  * @a: label to merge with @b  (NOT NULL)
1133*4882a593Smuzhiyun  * @b: label to merge with @a  (NOT NULL)
1134*4882a593Smuzhiyun  *
1135*4882a593Smuzhiyun  * Requires: ls->lock read_lock held
1136*4882a593Smuzhiyun  *
1137*4882a593Smuzhiyun  * Returns: ref counted label that is equiv to merge of @a and @b
1138*4882a593Smuzhiyun  *     else NULL if merge of @a and @b is not in set
1139*4882a593Smuzhiyun  */
__label_find_merge(struct aa_labelset * ls,struct aa_label * a,struct aa_label * b)1140*4882a593Smuzhiyun static struct aa_label *__label_find_merge(struct aa_labelset *ls,
1141*4882a593Smuzhiyun 					   struct aa_label *a,
1142*4882a593Smuzhiyun 					   struct aa_label *b)
1143*4882a593Smuzhiyun {
1144*4882a593Smuzhiyun 	struct rb_node *node;
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	AA_BUG(!ls);
1147*4882a593Smuzhiyun 	AA_BUG(!a);
1148*4882a593Smuzhiyun 	AA_BUG(!b);
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	if (a == b)
1151*4882a593Smuzhiyun 		return __label_find(a);
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	node  = ls->root.rb_node;
1154*4882a593Smuzhiyun 	while (node) {
1155*4882a593Smuzhiyun 		struct aa_label *this = container_of(node, struct aa_label,
1156*4882a593Smuzhiyun 						     node);
1157*4882a593Smuzhiyun 		int result = label_merge_cmp(a, b, this);
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 		if (result < 0)
1160*4882a593Smuzhiyun 			node = node->rb_left;
1161*4882a593Smuzhiyun 		else if (result > 0)
1162*4882a593Smuzhiyun 			node = node->rb_right;
1163*4882a593Smuzhiyun 		else
1164*4882a593Smuzhiyun 			return __aa_get_label(this);
1165*4882a593Smuzhiyun 	}
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	return NULL;
1168*4882a593Smuzhiyun }
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun /**
1172*4882a593Smuzhiyun  * aa_label_find_merge - find label that is equiv to merge of @a and @b
1173*4882a593Smuzhiyun  * @a: label to merge with @b  (NOT NULL)
1174*4882a593Smuzhiyun  * @b: label to merge with @a  (NOT NULL)
1175*4882a593Smuzhiyun  *
1176*4882a593Smuzhiyun  * Requires: labels be fully constructed with a valid ns
1177*4882a593Smuzhiyun  *
1178*4882a593Smuzhiyun  * Returns: ref counted label that is equiv to merge of @a and @b
1179*4882a593Smuzhiyun  *     else NULL if merge of @a and @b is not in set
1180*4882a593Smuzhiyun  */
aa_label_find_merge(struct aa_label * a,struct aa_label * b)1181*4882a593Smuzhiyun struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun 	struct aa_labelset *ls;
1184*4882a593Smuzhiyun 	struct aa_label *label, *ar = NULL, *br = NULL;
1185*4882a593Smuzhiyun 	unsigned long flags;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	AA_BUG(!a);
1188*4882a593Smuzhiyun 	AA_BUG(!b);
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 	if (label_is_stale(a))
1191*4882a593Smuzhiyun 		a = ar = aa_get_newest_label(a);
1192*4882a593Smuzhiyun 	if (label_is_stale(b))
1193*4882a593Smuzhiyun 		b = br = aa_get_newest_label(b);
1194*4882a593Smuzhiyun 	ls = labelset_of_merge(a, b);
1195*4882a593Smuzhiyun 	read_lock_irqsave(&ls->lock, flags);
1196*4882a593Smuzhiyun 	label = __label_find_merge(ls, a, b);
1197*4882a593Smuzhiyun 	read_unlock_irqrestore(&ls->lock, flags);
1198*4882a593Smuzhiyun 	aa_put_label(ar);
1199*4882a593Smuzhiyun 	aa_put_label(br);
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	return label;
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun /**
1205*4882a593Smuzhiyun  * aa_label_merge - attempt to insert new merged label of @a and @b
1206*4882a593Smuzhiyun  * @ls: set of labels to insert label into (NOT NULL)
1207*4882a593Smuzhiyun  * @a: label to merge with @b  (NOT NULL)
1208*4882a593Smuzhiyun  * @b: label to merge with @a  (NOT NULL)
1209*4882a593Smuzhiyun  * @gfp: memory allocation type
1210*4882a593Smuzhiyun  *
1211*4882a593Smuzhiyun  * Requires: caller to hold valid refs on @a and @b
1212*4882a593Smuzhiyun  *           labels be fully constructed with a valid ns
1213*4882a593Smuzhiyun  *
1214*4882a593Smuzhiyun  * Returns: ref counted new label if successful in inserting merge of a & b
1215*4882a593Smuzhiyun  *     else ref counted equivalent label that is already in the set.
1216*4882a593Smuzhiyun  *     else NULL if could not create label (-ENOMEM)
1217*4882a593Smuzhiyun  */
aa_label_merge(struct aa_label * a,struct aa_label * b,gfp_t gfp)1218*4882a593Smuzhiyun struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b,
1219*4882a593Smuzhiyun 				gfp_t gfp)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun 	struct aa_label *label = NULL;
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	AA_BUG(!a);
1224*4882a593Smuzhiyun 	AA_BUG(!b);
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	if (a == b)
1227*4882a593Smuzhiyun 		return aa_get_newest_label(a);
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	/* TODO: enable when read side is lockless
1230*4882a593Smuzhiyun 	 * check if label exists before taking locks
1231*4882a593Smuzhiyun 	if (!label_is_stale(a) && !label_is_stale(b))
1232*4882a593Smuzhiyun 		label = aa_label_find_merge(a, b);
1233*4882a593Smuzhiyun 	*/
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	if (!label) {
1236*4882a593Smuzhiyun 		struct aa_label *new;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 		a = aa_get_newest_label(a);
1239*4882a593Smuzhiyun 		b = aa_get_newest_label(b);
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 		/* could use label_merge_len(a, b), but requires double
1242*4882a593Smuzhiyun 		 * comparison for small savings
1243*4882a593Smuzhiyun 		 */
1244*4882a593Smuzhiyun 		new = aa_label_alloc(a->size + b->size, NULL, gfp);
1245*4882a593Smuzhiyun 		if (!new)
1246*4882a593Smuzhiyun 			goto out;
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun 		label = label_merge_insert(new, a, b);
1249*4882a593Smuzhiyun 		label_free_or_put_new(label, new);
1250*4882a593Smuzhiyun out:
1251*4882a593Smuzhiyun 		aa_put_label(a);
1252*4882a593Smuzhiyun 		aa_put_label(b);
1253*4882a593Smuzhiyun 	}
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	return label;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun 
label_is_visible(struct aa_profile * profile,struct aa_label * label)1258*4882a593Smuzhiyun static inline bool label_is_visible(struct aa_profile *profile,
1259*4882a593Smuzhiyun 				    struct aa_label *label)
1260*4882a593Smuzhiyun {
1261*4882a593Smuzhiyun 	return aa_ns_visible(profile->ns, labels_ns(label), true);
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun /* match a profile and its associated ns component if needed
1265*4882a593Smuzhiyun  * Assumes visibility test has already been done.
1266*4882a593Smuzhiyun  * If a subns profile is not to be matched should be prescreened with
1267*4882a593Smuzhiyun  * visibility test.
1268*4882a593Smuzhiyun  */
match_component(struct aa_profile * profile,struct aa_profile * tp,unsigned int state)1269*4882a593Smuzhiyun static inline unsigned int match_component(struct aa_profile *profile,
1270*4882a593Smuzhiyun 					   struct aa_profile *tp,
1271*4882a593Smuzhiyun 					   unsigned int state)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun 	const char *ns_name;
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	if (profile->ns == tp->ns)
1276*4882a593Smuzhiyun 		return aa_dfa_match(profile->policy.dfa, state, tp->base.hname);
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	/* try matching with namespace name and then profile */
1279*4882a593Smuzhiyun 	ns_name = aa_ns_name(profile->ns, tp->ns, true);
1280*4882a593Smuzhiyun 	state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1);
1281*4882a593Smuzhiyun 	state = aa_dfa_match(profile->policy.dfa, state, ns_name);
1282*4882a593Smuzhiyun 	state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1);
1283*4882a593Smuzhiyun 	return aa_dfa_match(profile->policy.dfa, state, tp->base.hname);
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun /**
1287*4882a593Smuzhiyun  * label_compound_match - find perms for full compound label
1288*4882a593Smuzhiyun  * @profile: profile to find perms for
1289*4882a593Smuzhiyun  * @label: label to check access permissions for
1290*4882a593Smuzhiyun  * @start: state to start match in
1291*4882a593Smuzhiyun  * @subns: whether to do permission checks on components in a subns
1292*4882a593Smuzhiyun  * @request: permissions to request
1293*4882a593Smuzhiyun  * @perms: perms struct to set
1294*4882a593Smuzhiyun  *
1295*4882a593Smuzhiyun  * Returns: 0 on success else ERROR
1296*4882a593Smuzhiyun  *
1297*4882a593Smuzhiyun  * For the label A//&B//&C this does the perm match for A//&B//&C
1298*4882a593Smuzhiyun  * @perms should be preinitialized with allperms OR a previous permission
1299*4882a593Smuzhiyun  *        check to be stacked.
1300*4882a593Smuzhiyun  */
label_compound_match(struct aa_profile * profile,struct aa_label * label,unsigned int state,bool subns,u32 request,struct aa_perms * perms)1301*4882a593Smuzhiyun static int label_compound_match(struct aa_profile *profile,
1302*4882a593Smuzhiyun 				struct aa_label *label,
1303*4882a593Smuzhiyun 				unsigned int state, bool subns, u32 request,
1304*4882a593Smuzhiyun 				struct aa_perms *perms)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun 	struct aa_profile *tp;
1307*4882a593Smuzhiyun 	struct label_it i;
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	/* find first subcomponent that is visible */
1310*4882a593Smuzhiyun 	label_for_each(i, label, tp) {
1311*4882a593Smuzhiyun 		if (!aa_ns_visible(profile->ns, tp->ns, subns))
1312*4882a593Smuzhiyun 			continue;
1313*4882a593Smuzhiyun 		state = match_component(profile, tp, state);
1314*4882a593Smuzhiyun 		if (!state)
1315*4882a593Smuzhiyun 			goto fail;
1316*4882a593Smuzhiyun 		goto next;
1317*4882a593Smuzhiyun 	}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	/* no component visible */
1320*4882a593Smuzhiyun 	*perms = allperms;
1321*4882a593Smuzhiyun 	return 0;
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun next:
1324*4882a593Smuzhiyun 	label_for_each_cont(i, label, tp) {
1325*4882a593Smuzhiyun 		if (!aa_ns_visible(profile->ns, tp->ns, subns))
1326*4882a593Smuzhiyun 			continue;
1327*4882a593Smuzhiyun 		state = aa_dfa_match(profile->policy.dfa, state, "//&");
1328*4882a593Smuzhiyun 		state = match_component(profile, tp, state);
1329*4882a593Smuzhiyun 		if (!state)
1330*4882a593Smuzhiyun 			goto fail;
1331*4882a593Smuzhiyun 	}
1332*4882a593Smuzhiyun 	aa_compute_perms(profile->policy.dfa, state, perms);
1333*4882a593Smuzhiyun 	aa_apply_modes_to_perms(profile, perms);
1334*4882a593Smuzhiyun 	if ((perms->allow & request) != request)
1335*4882a593Smuzhiyun 		return -EACCES;
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	return 0;
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun fail:
1340*4882a593Smuzhiyun 	*perms = nullperms;
1341*4882a593Smuzhiyun 	return state;
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun /**
1345*4882a593Smuzhiyun  * label_components_match - find perms for all subcomponents of a label
1346*4882a593Smuzhiyun  * @profile: profile to find perms for
1347*4882a593Smuzhiyun  * @label: label to check access permissions for
1348*4882a593Smuzhiyun  * @start: state to start match in
1349*4882a593Smuzhiyun  * @subns: whether to do permission checks on components in a subns
1350*4882a593Smuzhiyun  * @request: permissions to request
1351*4882a593Smuzhiyun  * @perms: an initialized perms struct to add accumulation to
1352*4882a593Smuzhiyun  *
1353*4882a593Smuzhiyun  * Returns: 0 on success else ERROR
1354*4882a593Smuzhiyun  *
1355*4882a593Smuzhiyun  * For the label A//&B//&C this does the perm match for each of A and B and C
1356*4882a593Smuzhiyun  * @perms should be preinitialized with allperms OR a previous permission
1357*4882a593Smuzhiyun  *        check to be stacked.
1358*4882a593Smuzhiyun  */
label_components_match(struct aa_profile * profile,struct aa_label * label,unsigned int start,bool subns,u32 request,struct aa_perms * perms)1359*4882a593Smuzhiyun static int label_components_match(struct aa_profile *profile,
1360*4882a593Smuzhiyun 				  struct aa_label *label, unsigned int start,
1361*4882a593Smuzhiyun 				  bool subns, u32 request,
1362*4882a593Smuzhiyun 				  struct aa_perms *perms)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun 	struct aa_profile *tp;
1365*4882a593Smuzhiyun 	struct label_it i;
1366*4882a593Smuzhiyun 	struct aa_perms tmp;
1367*4882a593Smuzhiyun 	unsigned int state = 0;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	/* find first subcomponent to test */
1370*4882a593Smuzhiyun 	label_for_each(i, label, tp) {
1371*4882a593Smuzhiyun 		if (!aa_ns_visible(profile->ns, tp->ns, subns))
1372*4882a593Smuzhiyun 			continue;
1373*4882a593Smuzhiyun 		state = match_component(profile, tp, start);
1374*4882a593Smuzhiyun 		if (!state)
1375*4882a593Smuzhiyun 			goto fail;
1376*4882a593Smuzhiyun 		goto next;
1377*4882a593Smuzhiyun 	}
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	/* no subcomponents visible - no change in perms */
1380*4882a593Smuzhiyun 	return 0;
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun next:
1383*4882a593Smuzhiyun 	aa_compute_perms(profile->policy.dfa, state, &tmp);
1384*4882a593Smuzhiyun 	aa_apply_modes_to_perms(profile, &tmp);
1385*4882a593Smuzhiyun 	aa_perms_accum(perms, &tmp);
1386*4882a593Smuzhiyun 	label_for_each_cont(i, label, tp) {
1387*4882a593Smuzhiyun 		if (!aa_ns_visible(profile->ns, tp->ns, subns))
1388*4882a593Smuzhiyun 			continue;
1389*4882a593Smuzhiyun 		state = match_component(profile, tp, start);
1390*4882a593Smuzhiyun 		if (!state)
1391*4882a593Smuzhiyun 			goto fail;
1392*4882a593Smuzhiyun 		aa_compute_perms(profile->policy.dfa, state, &tmp);
1393*4882a593Smuzhiyun 		aa_apply_modes_to_perms(profile, &tmp);
1394*4882a593Smuzhiyun 		aa_perms_accum(perms, &tmp);
1395*4882a593Smuzhiyun 	}
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	if ((perms->allow & request) != request)
1398*4882a593Smuzhiyun 		return -EACCES;
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	return 0;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun fail:
1403*4882a593Smuzhiyun 	*perms = nullperms;
1404*4882a593Smuzhiyun 	return -EACCES;
1405*4882a593Smuzhiyun }
1406*4882a593Smuzhiyun 
1407*4882a593Smuzhiyun /**
1408*4882a593Smuzhiyun  * aa_label_match - do a multi-component label match
1409*4882a593Smuzhiyun  * @profile: profile to match against (NOT NULL)
1410*4882a593Smuzhiyun  * @label: label to match (NOT NULL)
1411*4882a593Smuzhiyun  * @state: state to start in
1412*4882a593Smuzhiyun  * @subns: whether to match subns components
1413*4882a593Smuzhiyun  * @request: permission request
1414*4882a593Smuzhiyun  * @perms: Returns computed perms (NOT NULL)
1415*4882a593Smuzhiyun  *
1416*4882a593Smuzhiyun  * Returns: the state the match finished in, may be the none matching state
1417*4882a593Smuzhiyun  */
aa_label_match(struct aa_profile * profile,struct aa_label * label,unsigned int state,bool subns,u32 request,struct aa_perms * perms)1418*4882a593Smuzhiyun int aa_label_match(struct aa_profile *profile, struct aa_label *label,
1419*4882a593Smuzhiyun 		   unsigned int state, bool subns, u32 request,
1420*4882a593Smuzhiyun 		   struct aa_perms *perms)
1421*4882a593Smuzhiyun {
1422*4882a593Smuzhiyun 	int error = label_compound_match(profile, label, state, subns, request,
1423*4882a593Smuzhiyun 					 perms);
1424*4882a593Smuzhiyun 	if (!error)
1425*4882a593Smuzhiyun 		return error;
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	*perms = allperms;
1428*4882a593Smuzhiyun 	return label_components_match(profile, label, state, subns, request,
1429*4882a593Smuzhiyun 				      perms);
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun /**
1434*4882a593Smuzhiyun  * aa_update_label_name - update a label to have a stored name
1435*4882a593Smuzhiyun  * @ns: ns being viewed from (NOT NULL)
1436*4882a593Smuzhiyun  * @label: label to update (NOT NULL)
1437*4882a593Smuzhiyun  * @gfp: type of memory allocation
1438*4882a593Smuzhiyun  *
1439*4882a593Smuzhiyun  * Requires: labels_set(label) not locked in caller
1440*4882a593Smuzhiyun  *
1441*4882a593Smuzhiyun  * note: only updates the label name if it does not have a name already
1442*4882a593Smuzhiyun  *       and if it is in the labelset
1443*4882a593Smuzhiyun  */
aa_update_label_name(struct aa_ns * ns,struct aa_label * label,gfp_t gfp)1444*4882a593Smuzhiyun bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
1445*4882a593Smuzhiyun {
1446*4882a593Smuzhiyun 	struct aa_labelset *ls;
1447*4882a593Smuzhiyun 	unsigned long flags;
1448*4882a593Smuzhiyun 	char __counted *name;
1449*4882a593Smuzhiyun 	bool res = false;
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 	AA_BUG(!ns);
1452*4882a593Smuzhiyun 	AA_BUG(!label);
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	if (label->hname || labels_ns(label) != ns)
1455*4882a593Smuzhiyun 		return res;
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun 	if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0)
1458*4882a593Smuzhiyun 		return res;
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	ls = labels_set(label);
1461*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
1462*4882a593Smuzhiyun 	if (!label->hname && label->flags & FLAG_IN_TREE) {
1463*4882a593Smuzhiyun 		label->hname = name;
1464*4882a593Smuzhiyun 		res = true;
1465*4882a593Smuzhiyun 	} else
1466*4882a593Smuzhiyun 		aa_put_str(name);
1467*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	return res;
1470*4882a593Smuzhiyun }
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun /*
1473*4882a593Smuzhiyun  * cached label name is present and visible
1474*4882a593Smuzhiyun  * @label->hname only exists if label is namespace hierachical
1475*4882a593Smuzhiyun  */
use_label_hname(struct aa_ns * ns,struct aa_label * label,int flags)1476*4882a593Smuzhiyun static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
1477*4882a593Smuzhiyun 				   int flags)
1478*4882a593Smuzhiyun {
1479*4882a593Smuzhiyun 	if (label->hname && (!ns || labels_ns(label) == ns) &&
1480*4882a593Smuzhiyun 	    !(flags & ~FLAG_SHOW_MODE))
1481*4882a593Smuzhiyun 		return true;
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	return false;
1484*4882a593Smuzhiyun }
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun /* helper macro for snprint routines */
1487*4882a593Smuzhiyun #define update_for_len(total, len, size, str)	\
1488*4882a593Smuzhiyun do {					\
1489*4882a593Smuzhiyun 	size_t ulen = len;		\
1490*4882a593Smuzhiyun 					\
1491*4882a593Smuzhiyun 	AA_BUG(len < 0);		\
1492*4882a593Smuzhiyun 	total += ulen;			\
1493*4882a593Smuzhiyun 	ulen = min(ulen, size);		\
1494*4882a593Smuzhiyun 	size -= ulen;			\
1495*4882a593Smuzhiyun 	str += ulen;			\
1496*4882a593Smuzhiyun } while (0)
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun /**
1499*4882a593Smuzhiyun  * aa_profile_snxprint - print a profile name to a buffer
1500*4882a593Smuzhiyun  * @str: buffer to write to. (MAY BE NULL if @size == 0)
1501*4882a593Smuzhiyun  * @size: size of buffer
1502*4882a593Smuzhiyun  * @view: namespace profile is being viewed from
1503*4882a593Smuzhiyun  * @profile: profile to view (NOT NULL)
1504*4882a593Smuzhiyun  * @flags: whether to include the mode string
1505*4882a593Smuzhiyun  * @prev_ns: last ns printed when used in compound print
1506*4882a593Smuzhiyun  *
1507*4882a593Smuzhiyun  * Returns: size of name written or would be written if larger than
1508*4882a593Smuzhiyun  *          available buffer
1509*4882a593Smuzhiyun  *
1510*4882a593Smuzhiyun  * Note: will not print anything if the profile is not visible
1511*4882a593Smuzhiyun  */
aa_profile_snxprint(char * str,size_t size,struct aa_ns * view,struct aa_profile * profile,int flags,struct aa_ns ** prev_ns)1512*4882a593Smuzhiyun static int aa_profile_snxprint(char *str, size_t size, struct aa_ns *view,
1513*4882a593Smuzhiyun 			       struct aa_profile *profile, int flags,
1514*4882a593Smuzhiyun 			       struct aa_ns **prev_ns)
1515*4882a593Smuzhiyun {
1516*4882a593Smuzhiyun 	const char *ns_name = NULL;
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	AA_BUG(!str && size != 0);
1519*4882a593Smuzhiyun 	AA_BUG(!profile);
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	if (!view)
1522*4882a593Smuzhiyun 		view = profiles_ns(profile);
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	if (view != profile->ns &&
1525*4882a593Smuzhiyun 	    (!prev_ns || (*prev_ns != profile->ns))) {
1526*4882a593Smuzhiyun 		if (prev_ns)
1527*4882a593Smuzhiyun 			*prev_ns = profile->ns;
1528*4882a593Smuzhiyun 		ns_name = aa_ns_name(view, profile->ns,
1529*4882a593Smuzhiyun 				     flags & FLAG_VIEW_SUBNS);
1530*4882a593Smuzhiyun 		if (ns_name == aa_hidden_ns_name) {
1531*4882a593Smuzhiyun 			if (flags & FLAG_HIDDEN_UNCONFINED)
1532*4882a593Smuzhiyun 				return snprintf(str, size, "%s", "unconfined");
1533*4882a593Smuzhiyun 			return snprintf(str, size, "%s", ns_name);
1534*4882a593Smuzhiyun 		}
1535*4882a593Smuzhiyun 	}
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	if ((flags & FLAG_SHOW_MODE) && profile != profile->ns->unconfined) {
1538*4882a593Smuzhiyun 		const char *modestr = aa_profile_mode_names[profile->mode];
1539*4882a593Smuzhiyun 
1540*4882a593Smuzhiyun 		if (ns_name)
1541*4882a593Smuzhiyun 			return snprintf(str, size, ":%s:%s (%s)", ns_name,
1542*4882a593Smuzhiyun 					profile->base.hname, modestr);
1543*4882a593Smuzhiyun 		return snprintf(str, size, "%s (%s)", profile->base.hname,
1544*4882a593Smuzhiyun 				modestr);
1545*4882a593Smuzhiyun 	}
1546*4882a593Smuzhiyun 
1547*4882a593Smuzhiyun 	if (ns_name)
1548*4882a593Smuzhiyun 		return snprintf(str, size, ":%s:%s", ns_name,
1549*4882a593Smuzhiyun 				profile->base.hname);
1550*4882a593Smuzhiyun 	return snprintf(str, size, "%s", profile->base.hname);
1551*4882a593Smuzhiyun }
1552*4882a593Smuzhiyun 
label_modename(struct aa_ns * ns,struct aa_label * label,int flags)1553*4882a593Smuzhiyun static const char *label_modename(struct aa_ns *ns, struct aa_label *label,
1554*4882a593Smuzhiyun 				  int flags)
1555*4882a593Smuzhiyun {
1556*4882a593Smuzhiyun 	struct aa_profile *profile;
1557*4882a593Smuzhiyun 	struct label_it i;
1558*4882a593Smuzhiyun 	int mode = -1, count = 0;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	label_for_each(i, label, profile) {
1561*4882a593Smuzhiyun 		if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
1562*4882a593Smuzhiyun 			count++;
1563*4882a593Smuzhiyun 			if (profile == profile->ns->unconfined)
1564*4882a593Smuzhiyun 				/* special case unconfined so stacks with
1565*4882a593Smuzhiyun 				 * unconfined don't report as mixed. ie.
1566*4882a593Smuzhiyun 				 * profile_foo//&:ns1:unconfined (mixed)
1567*4882a593Smuzhiyun 				 */
1568*4882a593Smuzhiyun 				continue;
1569*4882a593Smuzhiyun 			if (mode == -1)
1570*4882a593Smuzhiyun 				mode = profile->mode;
1571*4882a593Smuzhiyun 			else if (mode != profile->mode)
1572*4882a593Smuzhiyun 				return "mixed";
1573*4882a593Smuzhiyun 		}
1574*4882a593Smuzhiyun 	}
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun 	if (count == 0)
1577*4882a593Smuzhiyun 		return "-";
1578*4882a593Smuzhiyun 	if (mode == -1)
1579*4882a593Smuzhiyun 		/* everything was unconfined */
1580*4882a593Smuzhiyun 		mode = APPARMOR_UNCONFINED;
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	return aa_profile_mode_names[mode];
1583*4882a593Smuzhiyun }
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun /* if any visible label is not unconfined the display_mode returns true */
display_mode(struct aa_ns * ns,struct aa_label * label,int flags)1586*4882a593Smuzhiyun static inline bool display_mode(struct aa_ns *ns, struct aa_label *label,
1587*4882a593Smuzhiyun 				int flags)
1588*4882a593Smuzhiyun {
1589*4882a593Smuzhiyun 	if ((flags & FLAG_SHOW_MODE)) {
1590*4882a593Smuzhiyun 		struct aa_profile *profile;
1591*4882a593Smuzhiyun 		struct label_it i;
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 		label_for_each(i, label, profile) {
1594*4882a593Smuzhiyun 			if (aa_ns_visible(ns, profile->ns,
1595*4882a593Smuzhiyun 					  flags & FLAG_VIEW_SUBNS) &&
1596*4882a593Smuzhiyun 			    profile != profile->ns->unconfined)
1597*4882a593Smuzhiyun 				return true;
1598*4882a593Smuzhiyun 		}
1599*4882a593Smuzhiyun 		/* only ns->unconfined in set of profiles in ns */
1600*4882a593Smuzhiyun 		return false;
1601*4882a593Smuzhiyun 	}
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun 	return false;
1604*4882a593Smuzhiyun }
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun /**
1607*4882a593Smuzhiyun  * aa_label_snxprint - print a label name to a string buffer
1608*4882a593Smuzhiyun  * @str: buffer to write to. (MAY BE NULL if @size == 0)
1609*4882a593Smuzhiyun  * @size: size of buffer
1610*4882a593Smuzhiyun  * @ns: namespace profile is being viewed from
1611*4882a593Smuzhiyun  * @label: label to view (NOT NULL)
1612*4882a593Smuzhiyun  * @flags: whether to include the mode string
1613*4882a593Smuzhiyun  *
1614*4882a593Smuzhiyun  * Returns: size of name written or would be written if larger than
1615*4882a593Smuzhiyun  *          available buffer
1616*4882a593Smuzhiyun  *
1617*4882a593Smuzhiyun  * Note: labels do not have to be strictly hierarchical to the ns as
1618*4882a593Smuzhiyun  *       objects may be shared across different namespaces and thus
1619*4882a593Smuzhiyun  *       pickup labeling from each ns.  If a particular part of the
1620*4882a593Smuzhiyun  *       label is not visible it will just be excluded.  And if none
1621*4882a593Smuzhiyun  *       of the label is visible "---" will be used.
1622*4882a593Smuzhiyun  */
aa_label_snxprint(char * str,size_t size,struct aa_ns * ns,struct aa_label * label,int flags)1623*4882a593Smuzhiyun int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
1624*4882a593Smuzhiyun 		      struct aa_label *label, int flags)
1625*4882a593Smuzhiyun {
1626*4882a593Smuzhiyun 	struct aa_profile *profile;
1627*4882a593Smuzhiyun 	struct aa_ns *prev_ns = NULL;
1628*4882a593Smuzhiyun 	struct label_it i;
1629*4882a593Smuzhiyun 	int count = 0, total = 0;
1630*4882a593Smuzhiyun 	ssize_t len;
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	AA_BUG(!str && size != 0);
1633*4882a593Smuzhiyun 	AA_BUG(!label);
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) {
1636*4882a593Smuzhiyun 		ns = root_ns;
1637*4882a593Smuzhiyun 		len = snprintf(str, size, "_");
1638*4882a593Smuzhiyun 		update_for_len(total, len, size, str);
1639*4882a593Smuzhiyun 	} else if (!ns) {
1640*4882a593Smuzhiyun 		ns = labels_ns(label);
1641*4882a593Smuzhiyun 	}
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 	label_for_each(i, label, profile) {
1644*4882a593Smuzhiyun 		if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
1645*4882a593Smuzhiyun 			if (count > 0) {
1646*4882a593Smuzhiyun 				len = snprintf(str, size, "//&");
1647*4882a593Smuzhiyun 				update_for_len(total, len, size, str);
1648*4882a593Smuzhiyun 			}
1649*4882a593Smuzhiyun 			len = aa_profile_snxprint(str, size, ns, profile,
1650*4882a593Smuzhiyun 						  flags & FLAG_VIEW_SUBNS,
1651*4882a593Smuzhiyun 						  &prev_ns);
1652*4882a593Smuzhiyun 			update_for_len(total, len, size, str);
1653*4882a593Smuzhiyun 			count++;
1654*4882a593Smuzhiyun 		}
1655*4882a593Smuzhiyun 	}
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	if (count == 0) {
1658*4882a593Smuzhiyun 		if (flags & FLAG_HIDDEN_UNCONFINED)
1659*4882a593Smuzhiyun 			return snprintf(str, size, "%s", "unconfined");
1660*4882a593Smuzhiyun 		return snprintf(str, size, "%s", aa_hidden_ns_name);
1661*4882a593Smuzhiyun 	}
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	/* count == 1 && ... is for backwards compat where the mode
1664*4882a593Smuzhiyun 	 * is not displayed for 'unconfined' in the current ns
1665*4882a593Smuzhiyun 	 */
1666*4882a593Smuzhiyun 	if (display_mode(ns, label, flags)) {
1667*4882a593Smuzhiyun 		len = snprintf(str, size, " (%s)",
1668*4882a593Smuzhiyun 			       label_modename(ns, label, flags));
1669*4882a593Smuzhiyun 		update_for_len(total, len, size, str);
1670*4882a593Smuzhiyun 	}
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	return total;
1673*4882a593Smuzhiyun }
1674*4882a593Smuzhiyun #undef update_for_len
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun /**
1677*4882a593Smuzhiyun  * aa_label_asxprint - allocate a string buffer and print label into it
1678*4882a593Smuzhiyun  * @strp: Returns - the allocated buffer with the label name. (NOT NULL)
1679*4882a593Smuzhiyun  * @ns: namespace profile is being viewed from
1680*4882a593Smuzhiyun  * @label: label to view (NOT NULL)
1681*4882a593Smuzhiyun  * @flags: flags controlling what label info is printed
1682*4882a593Smuzhiyun  * @gfp: kernel memory allocation type
1683*4882a593Smuzhiyun  *
1684*4882a593Smuzhiyun  * Returns: size of name written or would be written if larger than
1685*4882a593Smuzhiyun  *          available buffer
1686*4882a593Smuzhiyun  */
aa_label_asxprint(char ** strp,struct aa_ns * ns,struct aa_label * label,int flags,gfp_t gfp)1687*4882a593Smuzhiyun int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
1688*4882a593Smuzhiyun 		      int flags, gfp_t gfp)
1689*4882a593Smuzhiyun {
1690*4882a593Smuzhiyun 	int size;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	AA_BUG(!strp);
1693*4882a593Smuzhiyun 	AA_BUG(!label);
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 	size = aa_label_snxprint(NULL, 0, ns, label, flags);
1696*4882a593Smuzhiyun 	if (size < 0)
1697*4882a593Smuzhiyun 		return size;
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun 	*strp = kmalloc(size + 1, gfp);
1700*4882a593Smuzhiyun 	if (!*strp)
1701*4882a593Smuzhiyun 		return -ENOMEM;
1702*4882a593Smuzhiyun 	return aa_label_snxprint(*strp, size + 1, ns, label, flags);
1703*4882a593Smuzhiyun }
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun /**
1706*4882a593Smuzhiyun  * aa_label_acntsxprint - allocate a __counted string buffer and print label
1707*4882a593Smuzhiyun  * @strp: buffer to write to.
1708*4882a593Smuzhiyun  * @ns: namespace profile is being viewed from
1709*4882a593Smuzhiyun  * @label: label to view (NOT NULL)
1710*4882a593Smuzhiyun  * @flags: flags controlling what label info is printed
1711*4882a593Smuzhiyun  * @gfp: kernel memory allocation type
1712*4882a593Smuzhiyun  *
1713*4882a593Smuzhiyun  * Returns: size of name written or would be written if larger than
1714*4882a593Smuzhiyun  *          available buffer
1715*4882a593Smuzhiyun  */
aa_label_acntsxprint(char __counted ** strp,struct aa_ns * ns,struct aa_label * label,int flags,gfp_t gfp)1716*4882a593Smuzhiyun int aa_label_acntsxprint(char __counted **strp, struct aa_ns *ns,
1717*4882a593Smuzhiyun 			 struct aa_label *label, int flags, gfp_t gfp)
1718*4882a593Smuzhiyun {
1719*4882a593Smuzhiyun 	int size;
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun 	AA_BUG(!strp);
1722*4882a593Smuzhiyun 	AA_BUG(!label);
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	size = aa_label_snxprint(NULL, 0, ns, label, flags);
1725*4882a593Smuzhiyun 	if (size < 0)
1726*4882a593Smuzhiyun 		return size;
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 	*strp = aa_str_alloc(size + 1, gfp);
1729*4882a593Smuzhiyun 	if (!*strp)
1730*4882a593Smuzhiyun 		return -ENOMEM;
1731*4882a593Smuzhiyun 	return aa_label_snxprint(*strp, size + 1, ns, label, flags);
1732*4882a593Smuzhiyun }
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 
aa_label_xaudit(struct audit_buffer * ab,struct aa_ns * ns,struct aa_label * label,int flags,gfp_t gfp)1735*4882a593Smuzhiyun void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
1736*4882a593Smuzhiyun 		     struct aa_label *label, int flags, gfp_t gfp)
1737*4882a593Smuzhiyun {
1738*4882a593Smuzhiyun 	const char *str;
1739*4882a593Smuzhiyun 	char *name = NULL;
1740*4882a593Smuzhiyun 	int len;
1741*4882a593Smuzhiyun 
1742*4882a593Smuzhiyun 	AA_BUG(!ab);
1743*4882a593Smuzhiyun 	AA_BUG(!label);
1744*4882a593Smuzhiyun 
1745*4882a593Smuzhiyun 	if (!use_label_hname(ns, label, flags) ||
1746*4882a593Smuzhiyun 	    display_mode(ns, label, flags)) {
1747*4882a593Smuzhiyun 		len  = aa_label_asxprint(&name, ns, label, flags, gfp);
1748*4882a593Smuzhiyun 		if (len < 0) {
1749*4882a593Smuzhiyun 			AA_DEBUG("label print error");
1750*4882a593Smuzhiyun 			return;
1751*4882a593Smuzhiyun 		}
1752*4882a593Smuzhiyun 		str = name;
1753*4882a593Smuzhiyun 	} else {
1754*4882a593Smuzhiyun 		str = (char *) label->hname;
1755*4882a593Smuzhiyun 		len = strlen(str);
1756*4882a593Smuzhiyun 	}
1757*4882a593Smuzhiyun 	if (audit_string_contains_control(str, len))
1758*4882a593Smuzhiyun 		audit_log_n_hex(ab, str, len);
1759*4882a593Smuzhiyun 	else
1760*4882a593Smuzhiyun 		audit_log_n_string(ab, str, len);
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 	kfree(name);
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun 
aa_label_seq_xprint(struct seq_file * f,struct aa_ns * ns,struct aa_label * label,int flags,gfp_t gfp)1765*4882a593Smuzhiyun void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
1766*4882a593Smuzhiyun 			 struct aa_label *label, int flags, gfp_t gfp)
1767*4882a593Smuzhiyun {
1768*4882a593Smuzhiyun 	AA_BUG(!f);
1769*4882a593Smuzhiyun 	AA_BUG(!label);
1770*4882a593Smuzhiyun 
1771*4882a593Smuzhiyun 	if (!use_label_hname(ns, label, flags)) {
1772*4882a593Smuzhiyun 		char *str;
1773*4882a593Smuzhiyun 		int len;
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 		len = aa_label_asxprint(&str, ns, label, flags, gfp);
1776*4882a593Smuzhiyun 		if (len < 0) {
1777*4882a593Smuzhiyun 			AA_DEBUG("label print error");
1778*4882a593Smuzhiyun 			return;
1779*4882a593Smuzhiyun 		}
1780*4882a593Smuzhiyun 		seq_puts(f, str);
1781*4882a593Smuzhiyun 		kfree(str);
1782*4882a593Smuzhiyun 	} else if (display_mode(ns, label, flags))
1783*4882a593Smuzhiyun 		seq_printf(f, "%s (%s)", label->hname,
1784*4882a593Smuzhiyun 			   label_modename(ns, label, flags));
1785*4882a593Smuzhiyun 	else
1786*4882a593Smuzhiyun 		seq_puts(f, label->hname);
1787*4882a593Smuzhiyun }
1788*4882a593Smuzhiyun 
aa_label_xprintk(struct aa_ns * ns,struct aa_label * label,int flags,gfp_t gfp)1789*4882a593Smuzhiyun void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
1790*4882a593Smuzhiyun 		      gfp_t gfp)
1791*4882a593Smuzhiyun {
1792*4882a593Smuzhiyun 	AA_BUG(!label);
1793*4882a593Smuzhiyun 
1794*4882a593Smuzhiyun 	if (!use_label_hname(ns, label, flags)) {
1795*4882a593Smuzhiyun 		char *str;
1796*4882a593Smuzhiyun 		int len;
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 		len = aa_label_asxprint(&str, ns, label, flags, gfp);
1799*4882a593Smuzhiyun 		if (len < 0) {
1800*4882a593Smuzhiyun 			AA_DEBUG("label print error");
1801*4882a593Smuzhiyun 			return;
1802*4882a593Smuzhiyun 		}
1803*4882a593Smuzhiyun 		pr_info("%s", str);
1804*4882a593Smuzhiyun 		kfree(str);
1805*4882a593Smuzhiyun 	} else if (display_mode(ns, label, flags))
1806*4882a593Smuzhiyun 		pr_info("%s (%s)", label->hname,
1807*4882a593Smuzhiyun 		       label_modename(ns, label, flags));
1808*4882a593Smuzhiyun 	else
1809*4882a593Smuzhiyun 		pr_info("%s", label->hname);
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun 
aa_label_audit(struct audit_buffer * ab,struct aa_label * label,gfp_t gfp)1812*4882a593Smuzhiyun void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp)
1813*4882a593Smuzhiyun {
1814*4882a593Smuzhiyun 	struct aa_ns *ns = aa_get_current_ns();
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun 	aa_label_xaudit(ab, ns, label, FLAG_VIEW_SUBNS, gfp);
1817*4882a593Smuzhiyun 	aa_put_ns(ns);
1818*4882a593Smuzhiyun }
1819*4882a593Smuzhiyun 
aa_label_seq_print(struct seq_file * f,struct aa_label * label,gfp_t gfp)1820*4882a593Smuzhiyun void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun 	struct aa_ns *ns = aa_get_current_ns();
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 	aa_label_seq_xprint(f, ns, label, FLAG_VIEW_SUBNS, gfp);
1825*4882a593Smuzhiyun 	aa_put_ns(ns);
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun 
aa_label_printk(struct aa_label * label,gfp_t gfp)1828*4882a593Smuzhiyun void aa_label_printk(struct aa_label *label, gfp_t gfp)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun 	struct aa_ns *ns = aa_get_current_ns();
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 	aa_label_xprintk(ns, label, FLAG_VIEW_SUBNS, gfp);
1833*4882a593Smuzhiyun 	aa_put_ns(ns);
1834*4882a593Smuzhiyun }
1835*4882a593Smuzhiyun 
label_count_strn_entries(const char * str,size_t n)1836*4882a593Smuzhiyun static int label_count_strn_entries(const char *str, size_t n)
1837*4882a593Smuzhiyun {
1838*4882a593Smuzhiyun 	const char *end = str + n;
1839*4882a593Smuzhiyun 	const char *split;
1840*4882a593Smuzhiyun 	int count = 1;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	AA_BUG(!str);
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	for (split = aa_label_strn_split(str, end - str);
1845*4882a593Smuzhiyun 	     split;
1846*4882a593Smuzhiyun 	     split = aa_label_strn_split(str, end - str)) {
1847*4882a593Smuzhiyun 		count++;
1848*4882a593Smuzhiyun 		str = split + 3;
1849*4882a593Smuzhiyun 	}
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun 	return count;
1852*4882a593Smuzhiyun }
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun /*
1855*4882a593Smuzhiyun  * ensure stacks with components like
1856*4882a593Smuzhiyun  *   :ns:A//&B
1857*4882a593Smuzhiyun  * have :ns: applied to both 'A' and 'B' by making the lookup relative
1858*4882a593Smuzhiyun  * to the base if the lookup specifies an ns, else making the stacked lookup
1859*4882a593Smuzhiyun  * relative to the last embedded ns in the string.
1860*4882a593Smuzhiyun  */
fqlookupn_profile(struct aa_label * base,struct aa_label * currentbase,const char * str,size_t n)1861*4882a593Smuzhiyun static struct aa_profile *fqlookupn_profile(struct aa_label *base,
1862*4882a593Smuzhiyun 					    struct aa_label *currentbase,
1863*4882a593Smuzhiyun 					    const char *str, size_t n)
1864*4882a593Smuzhiyun {
1865*4882a593Smuzhiyun 	const char *first = skipn_spaces(str, n);
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	if (first && *first == ':')
1868*4882a593Smuzhiyun 		return aa_fqlookupn_profile(base, str, n);
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	return aa_fqlookupn_profile(currentbase, str, n);
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun 
1873*4882a593Smuzhiyun /**
1874*4882a593Smuzhiyun  * aa_label_strn_parse - parse, validate and convert a text string to a label
1875*4882a593Smuzhiyun  * @base: base label to use for lookups (NOT NULL)
1876*4882a593Smuzhiyun  * @str: null terminated text string (NOT NULL)
1877*4882a593Smuzhiyun  * @n: length of str to parse, will stop at \0 if encountered before n
1878*4882a593Smuzhiyun  * @gfp: allocation type
1879*4882a593Smuzhiyun  * @create: true if should create compound labels if they don't exist
1880*4882a593Smuzhiyun  * @force_stack: true if should stack even if no leading &
1881*4882a593Smuzhiyun  *
1882*4882a593Smuzhiyun  * Returns: the matching refcounted label if present
1883*4882a593Smuzhiyun  *     else ERRPTR
1884*4882a593Smuzhiyun  */
aa_label_strn_parse(struct aa_label * base,const char * str,size_t n,gfp_t gfp,bool create,bool force_stack)1885*4882a593Smuzhiyun struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
1886*4882a593Smuzhiyun 				     size_t n, gfp_t gfp, bool create,
1887*4882a593Smuzhiyun 				     bool force_stack)
1888*4882a593Smuzhiyun {
1889*4882a593Smuzhiyun 	DEFINE_VEC(profile, vec);
1890*4882a593Smuzhiyun 	struct aa_label *label, *currbase = base;
1891*4882a593Smuzhiyun 	int i, len, stack = 0, error;
1892*4882a593Smuzhiyun 	const char *end = str + n;
1893*4882a593Smuzhiyun 	const char *split;
1894*4882a593Smuzhiyun 
1895*4882a593Smuzhiyun 	AA_BUG(!base);
1896*4882a593Smuzhiyun 	AA_BUG(!str);
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	str = skipn_spaces(str, n);
1899*4882a593Smuzhiyun 	if (str == NULL || (AA_DEBUG_LABEL && *str == '_' &&
1900*4882a593Smuzhiyun 			    base != &root_ns->unconfined->label))
1901*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun 	len = label_count_strn_entries(str, end - str);
1904*4882a593Smuzhiyun 	if (*str == '&' || force_stack) {
1905*4882a593Smuzhiyun 		/* stack on top of base */
1906*4882a593Smuzhiyun 		stack = base->size;
1907*4882a593Smuzhiyun 		len += stack;
1908*4882a593Smuzhiyun 		if (*str == '&')
1909*4882a593Smuzhiyun 			str++;
1910*4882a593Smuzhiyun 	}
1911*4882a593Smuzhiyun 
1912*4882a593Smuzhiyun 	error = vec_setup(profile, vec, len, gfp);
1913*4882a593Smuzhiyun 	if (error)
1914*4882a593Smuzhiyun 		return ERR_PTR(error);
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	for (i = 0; i < stack; i++)
1917*4882a593Smuzhiyun 		vec[i] = aa_get_profile(base->vec[i]);
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun 	for (split = aa_label_strn_split(str, end - str), i = stack;
1920*4882a593Smuzhiyun 	     split && i < len; i++) {
1921*4882a593Smuzhiyun 		vec[i] = fqlookupn_profile(base, currbase, str, split - str);
1922*4882a593Smuzhiyun 		if (!vec[i])
1923*4882a593Smuzhiyun 			goto fail;
1924*4882a593Smuzhiyun 		/*
1925*4882a593Smuzhiyun 		 * if component specified a new ns it becomes the new base
1926*4882a593Smuzhiyun 		 * so that subsequent lookups are relative to it
1927*4882a593Smuzhiyun 		 */
1928*4882a593Smuzhiyun 		if (vec[i]->ns != labels_ns(currbase))
1929*4882a593Smuzhiyun 			currbase = &vec[i]->label;
1930*4882a593Smuzhiyun 		str = split + 3;
1931*4882a593Smuzhiyun 		split = aa_label_strn_split(str, end - str);
1932*4882a593Smuzhiyun 	}
1933*4882a593Smuzhiyun 	/* last element doesn't have a split */
1934*4882a593Smuzhiyun 	if (i < len) {
1935*4882a593Smuzhiyun 		vec[i] = fqlookupn_profile(base, currbase, str, end - str);
1936*4882a593Smuzhiyun 		if (!vec[i])
1937*4882a593Smuzhiyun 			goto fail;
1938*4882a593Smuzhiyun 	}
1939*4882a593Smuzhiyun 	if (len == 1)
1940*4882a593Smuzhiyun 		/* no need to free vec as len < LOCAL_VEC_ENTRIES */
1941*4882a593Smuzhiyun 		return &vec[0]->label;
1942*4882a593Smuzhiyun 
1943*4882a593Smuzhiyun 	len -= aa_vec_unique(vec, len, VEC_FLAG_TERMINATE);
1944*4882a593Smuzhiyun 	/* TODO: deal with reference labels */
1945*4882a593Smuzhiyun 	if (len == 1) {
1946*4882a593Smuzhiyun 		label = aa_get_label(&vec[0]->label);
1947*4882a593Smuzhiyun 		goto out;
1948*4882a593Smuzhiyun 	}
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	if (create)
1951*4882a593Smuzhiyun 		label = aa_vec_find_or_create_label(vec, len, gfp);
1952*4882a593Smuzhiyun 	else
1953*4882a593Smuzhiyun 		label = vec_find(vec, len);
1954*4882a593Smuzhiyun 	if (!label)
1955*4882a593Smuzhiyun 		goto fail;
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun out:
1958*4882a593Smuzhiyun 	/* use adjusted len from after vec_unique, not original */
1959*4882a593Smuzhiyun 	vec_cleanup(profile, vec, len);
1960*4882a593Smuzhiyun 	return label;
1961*4882a593Smuzhiyun 
1962*4882a593Smuzhiyun fail:
1963*4882a593Smuzhiyun 	label = ERR_PTR(-ENOENT);
1964*4882a593Smuzhiyun 	goto out;
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun 
aa_label_parse(struct aa_label * base,const char * str,gfp_t gfp,bool create,bool force_stack)1967*4882a593Smuzhiyun struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
1968*4882a593Smuzhiyun 				gfp_t gfp, bool create, bool force_stack)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun 	return aa_label_strn_parse(base, str, strlen(str), gfp, create,
1971*4882a593Smuzhiyun 				   force_stack);
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun /**
1975*4882a593Smuzhiyun  * aa_labelset_destroy - remove all labels from the label set
1976*4882a593Smuzhiyun  * @ls: label set to cleanup (NOT NULL)
1977*4882a593Smuzhiyun  *
1978*4882a593Smuzhiyun  * Labels that are removed from the set may still exist beyond the set
1979*4882a593Smuzhiyun  * being destroyed depending on their reference counting
1980*4882a593Smuzhiyun  */
aa_labelset_destroy(struct aa_labelset * ls)1981*4882a593Smuzhiyun void aa_labelset_destroy(struct aa_labelset *ls)
1982*4882a593Smuzhiyun {
1983*4882a593Smuzhiyun 	struct rb_node *node;
1984*4882a593Smuzhiyun 	unsigned long flags;
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 	AA_BUG(!ls);
1987*4882a593Smuzhiyun 
1988*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
1989*4882a593Smuzhiyun 	for (node = rb_first(&ls->root); node; node = rb_first(&ls->root)) {
1990*4882a593Smuzhiyun 		struct aa_label *this = rb_entry(node, struct aa_label, node);
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 		if (labels_ns(this) != root_ns)
1993*4882a593Smuzhiyun 			__label_remove(this,
1994*4882a593Smuzhiyun 				       ns_unconfined(labels_ns(this)->parent));
1995*4882a593Smuzhiyun 		else
1996*4882a593Smuzhiyun 			__label_remove(this, NULL);
1997*4882a593Smuzhiyun 	}
1998*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
1999*4882a593Smuzhiyun }
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun /*
2002*4882a593Smuzhiyun  * @ls: labelset to init (NOT NULL)
2003*4882a593Smuzhiyun  */
aa_labelset_init(struct aa_labelset * ls)2004*4882a593Smuzhiyun void aa_labelset_init(struct aa_labelset *ls)
2005*4882a593Smuzhiyun {
2006*4882a593Smuzhiyun 	AA_BUG(!ls);
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	rwlock_init(&ls->lock);
2009*4882a593Smuzhiyun 	ls->root = RB_ROOT;
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun 
labelset_next_stale(struct aa_labelset * ls)2012*4882a593Smuzhiyun static struct aa_label *labelset_next_stale(struct aa_labelset *ls)
2013*4882a593Smuzhiyun {
2014*4882a593Smuzhiyun 	struct aa_label *label;
2015*4882a593Smuzhiyun 	struct rb_node *node;
2016*4882a593Smuzhiyun 	unsigned long flags;
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 	AA_BUG(!ls);
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	read_lock_irqsave(&ls->lock, flags);
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	__labelset_for_each(ls, node) {
2023*4882a593Smuzhiyun 		label = rb_entry(node, struct aa_label, node);
2024*4882a593Smuzhiyun 		if ((label_is_stale(label) ||
2025*4882a593Smuzhiyun 		     vec_is_stale(label->vec, label->size)) &&
2026*4882a593Smuzhiyun 		    __aa_get_label(label))
2027*4882a593Smuzhiyun 			goto out;
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 	}
2030*4882a593Smuzhiyun 	label = NULL;
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun out:
2033*4882a593Smuzhiyun 	read_unlock_irqrestore(&ls->lock, flags);
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 	return label;
2036*4882a593Smuzhiyun }
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun /**
2039*4882a593Smuzhiyun  * __label_update - insert updated version of @label into labelset
2040*4882a593Smuzhiyun  * @label - the label to update/replace
2041*4882a593Smuzhiyun  *
2042*4882a593Smuzhiyun  * Returns: new label that is up to date
2043*4882a593Smuzhiyun  *     else NULL on failure
2044*4882a593Smuzhiyun  *
2045*4882a593Smuzhiyun  * Requires: @ns lock be held
2046*4882a593Smuzhiyun  *
2047*4882a593Smuzhiyun  * Note: worst case is the stale @label does not get updated and has
2048*4882a593Smuzhiyun  *       to be updated at a later time.
2049*4882a593Smuzhiyun  */
__label_update(struct aa_label * label)2050*4882a593Smuzhiyun static struct aa_label *__label_update(struct aa_label *label)
2051*4882a593Smuzhiyun {
2052*4882a593Smuzhiyun 	struct aa_label *new, *tmp;
2053*4882a593Smuzhiyun 	struct aa_labelset *ls;
2054*4882a593Smuzhiyun 	unsigned long flags;
2055*4882a593Smuzhiyun 	int i, invcount = 0;
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun 	AA_BUG(!label);
2058*4882a593Smuzhiyun 	AA_BUG(!mutex_is_locked(&labels_ns(label)->lock));
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun 	new = aa_label_alloc(label->size, label->proxy, GFP_KERNEL);
2061*4882a593Smuzhiyun 	if (!new)
2062*4882a593Smuzhiyun 		return NULL;
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 	/*
2065*4882a593Smuzhiyun 	 * while holding the ns_lock will stop profile replacement, removal,
2066*4882a593Smuzhiyun 	 * and label updates, label merging and removal can be occurring
2067*4882a593Smuzhiyun 	 */
2068*4882a593Smuzhiyun 	ls = labels_set(label);
2069*4882a593Smuzhiyun 	write_lock_irqsave(&ls->lock, flags);
2070*4882a593Smuzhiyun 	for (i = 0; i < label->size; i++) {
2071*4882a593Smuzhiyun 		AA_BUG(!label->vec[i]);
2072*4882a593Smuzhiyun 		new->vec[i] = aa_get_newest_profile(label->vec[i]);
2073*4882a593Smuzhiyun 		AA_BUG(!new->vec[i]);
2074*4882a593Smuzhiyun 		AA_BUG(!new->vec[i]->label.proxy);
2075*4882a593Smuzhiyun 		AA_BUG(!new->vec[i]->label.proxy->label);
2076*4882a593Smuzhiyun 		if (new->vec[i]->label.proxy != label->vec[i]->label.proxy)
2077*4882a593Smuzhiyun 			invcount++;
2078*4882a593Smuzhiyun 	}
2079*4882a593Smuzhiyun 
2080*4882a593Smuzhiyun 	/* updated stale label by being removed/renamed from labelset */
2081*4882a593Smuzhiyun 	if (invcount) {
2082*4882a593Smuzhiyun 		new->size -= aa_vec_unique(&new->vec[0], new->size,
2083*4882a593Smuzhiyun 					   VEC_FLAG_TERMINATE);
2084*4882a593Smuzhiyun 		/* TODO: deal with reference labels */
2085*4882a593Smuzhiyun 		if (new->size == 1) {
2086*4882a593Smuzhiyun 			tmp = aa_get_label(&new->vec[0]->label);
2087*4882a593Smuzhiyun 			AA_BUG(tmp == label);
2088*4882a593Smuzhiyun 			goto remove;
2089*4882a593Smuzhiyun 		}
2090*4882a593Smuzhiyun 		if (labels_set(label) != labels_set(new)) {
2091*4882a593Smuzhiyun 			write_unlock_irqrestore(&ls->lock, flags);
2092*4882a593Smuzhiyun 			tmp = aa_label_insert(labels_set(new), new);
2093*4882a593Smuzhiyun 			write_lock_irqsave(&ls->lock, flags);
2094*4882a593Smuzhiyun 			goto remove;
2095*4882a593Smuzhiyun 		}
2096*4882a593Smuzhiyun 	} else
2097*4882a593Smuzhiyun 		AA_BUG(labels_ns(label) != labels_ns(new));
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 	tmp = __label_insert(labels_set(label), new, true);
2100*4882a593Smuzhiyun remove:
2101*4882a593Smuzhiyun 	/* ensure label is removed, and redirected correctly */
2102*4882a593Smuzhiyun 	__label_remove(label, tmp);
2103*4882a593Smuzhiyun 	write_unlock_irqrestore(&ls->lock, flags);
2104*4882a593Smuzhiyun 	label_free_or_put_new(tmp, new);
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 	return tmp;
2107*4882a593Smuzhiyun }
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun /**
2110*4882a593Smuzhiyun  * __labelset_update - update labels in @ns
2111*4882a593Smuzhiyun  * @ns: namespace to update labels in  (NOT NULL)
2112*4882a593Smuzhiyun  *
2113*4882a593Smuzhiyun  * Requires: @ns lock be held
2114*4882a593Smuzhiyun  *
2115*4882a593Smuzhiyun  * Walk the labelset ensuring that all labels are up to date and valid
2116*4882a593Smuzhiyun  * Any label that has a stale component is marked stale and replaced and
2117*4882a593Smuzhiyun  * by an updated version.
2118*4882a593Smuzhiyun  *
2119*4882a593Smuzhiyun  * If failures happen due to memory pressures then stale labels will
2120*4882a593Smuzhiyun  * be left in place until the next pass.
2121*4882a593Smuzhiyun  */
__labelset_update(struct aa_ns * ns)2122*4882a593Smuzhiyun static void __labelset_update(struct aa_ns *ns)
2123*4882a593Smuzhiyun {
2124*4882a593Smuzhiyun 	struct aa_label *label;
2125*4882a593Smuzhiyun 
2126*4882a593Smuzhiyun 	AA_BUG(!ns);
2127*4882a593Smuzhiyun 	AA_BUG(!mutex_is_locked(&ns->lock));
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	do {
2130*4882a593Smuzhiyun 		label = labelset_next_stale(&ns->labels);
2131*4882a593Smuzhiyun 		if (label) {
2132*4882a593Smuzhiyun 			struct aa_label *l = __label_update(label);
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 			aa_put_label(l);
2135*4882a593Smuzhiyun 			aa_put_label(label);
2136*4882a593Smuzhiyun 		}
2137*4882a593Smuzhiyun 	} while (label);
2138*4882a593Smuzhiyun }
2139*4882a593Smuzhiyun 
2140*4882a593Smuzhiyun /**
2141*4882a593Smuzhiyun  * __aa_labelset_udate_subtree - update all labels with a stale component
2142*4882a593Smuzhiyun  * @ns: ns to start update at (NOT NULL)
2143*4882a593Smuzhiyun  *
2144*4882a593Smuzhiyun  * Requires: @ns lock be held
2145*4882a593Smuzhiyun  *
2146*4882a593Smuzhiyun  * Invalidates labels based on @p in @ns and any children namespaces.
2147*4882a593Smuzhiyun  */
__aa_labelset_update_subtree(struct aa_ns * ns)2148*4882a593Smuzhiyun void __aa_labelset_update_subtree(struct aa_ns *ns)
2149*4882a593Smuzhiyun {
2150*4882a593Smuzhiyun 	struct aa_ns *child;
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 	AA_BUG(!ns);
2153*4882a593Smuzhiyun 	AA_BUG(!mutex_is_locked(&ns->lock));
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 	__labelset_update(ns);
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	list_for_each_entry(child, &ns->sub_ns, base.list) {
2158*4882a593Smuzhiyun 		mutex_lock_nested(&child->lock, child->level);
2159*4882a593Smuzhiyun 		__aa_labelset_update_subtree(child);
2160*4882a593Smuzhiyun 		mutex_unlock(&child->lock);
2161*4882a593Smuzhiyun 	}
2162*4882a593Smuzhiyun }
2163