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