]>
Commit | Line | Data |
---|---|---|
6bfc18ae JJ |
1 | /* |
2 | * AppArmor security module | |
3 | * | |
4 | * This file contains AppArmor label definitions | |
5 | * | |
6 | * Copyright 2013 Canonical Ltd. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation, version 2 of the | |
11 | * License. | |
12 | */ | |
13 | ||
14 | #include <linux/audit.h> | |
15 | #include <linux/seq_file.h> | |
16 | ||
17 | #include "include/apparmor.h" | |
18 | #include "include/label.h" | |
19 | #include "include/policy.h" | |
20 | #include "include/sid.h" | |
21 | ||
22 | ||
23 | /* | |
24 | * the aa_label represents the set of profiles confining an object | |
25 | * | |
26 | * Labels maintain a reference count to the set of pointers they reference | |
27 | * Labels are ref counted by | |
28 | * tasks and object via the security field/security context off the field | |
29 | * code - will take a ref count on a label if it needs the label | |
30 | * beyond what is possible with an rcu_read_lock. | |
31 | * profiles - each profile is a label | |
32 | * sids - a pinned sid will keep a refcount of the label it is | |
33 | * referencing | |
34 | * objects - inode, files, sockets, ... | |
35 | * | |
36 | * Labels are not ref counted by the label set, so they maybe removed and | |
37 | * freed when no longer in use. | |
38 | * | |
39 | */ | |
40 | ||
41 | static void free_replacedby(struct aa_replacedby *r) | |
42 | { | |
43 | if (r) { | |
44 | /* r->label will not updated any more as r is dead */ | |
45 | aa_put_label(rcu_dereference_protected(r->label, true)); | |
1963692b | 46 | kzfree(r); |
6bfc18ae JJ |
47 | } |
48 | } | |
49 | ||
50 | void aa_free_replacedby_kref(struct kref *kref) | |
51 | { | |
52 | struct aa_replacedby *r = container_of(kref, struct aa_replacedby, | |
53 | count); | |
54 | free_replacedby(r); | |
55 | } | |
56 | ||
8ac21d39 | 57 | struct aa_replacedby *aa_alloc_replacedby(struct aa_label *l) |
6bfc18ae JJ |
58 | { |
59 | struct aa_replacedby *r; | |
60 | ||
8ac21d39 | 61 | r = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL); |
6bfc18ae JJ |
62 | if (r) { |
63 | kref_init(&r->count); | |
64 | rcu_assign_pointer(r->label, aa_get_label(l)); | |
65 | } | |
66 | return r; | |
67 | } | |
68 | ||
69 | /* requires profile list write lock held */ | |
70 | void __aa_update_replacedby(struct aa_label *orig, struct aa_label *new) | |
71 | { | |
72 | struct aa_label *tmp; | |
73 | ||
74 | AA_BUG(!orig); | |
75 | AA_BUG(!new); | |
4d69b183 | 76 | AA_BUG(!mutex_is_locked(&labels_ns(orig)->lock)); |
6bfc18ae JJ |
77 | |
78 | tmp = rcu_dereference_protected(orig->replacedby->label, | |
79 | &labels_ns(orig)->lock); | |
80 | rcu_assign_pointer(orig->replacedby->label, aa_get_label(new)); | |
81 | orig->flags |= FLAG_INVALID; | |
82 | aa_put_label(tmp); | |
83 | } | |
84 | ||
85 | /* helper fn for label_for_each_confined */ | |
86 | int aa_label_next_confined(struct aa_label *l, int i) | |
87 | { | |
88 | AA_BUG(!l); | |
89 | AA_BUG(i < 0); | |
90 | ||
91 | for (; i < l->size; i++) { | |
92 | if (!profile_unconfined(l->ent[i])) | |
93 | return i; | |
94 | } | |
95 | ||
96 | return i; | |
97 | } | |
98 | ||
99 | #if 0 | |
100 | static int label_profile_pos(struct aa_label *l, struct aa_profile *profile) | |
101 | { | |
102 | struct aa_profile *p; | |
103 | struct label_it i; | |
104 | ||
105 | AA_BUG(!profile); | |
106 | AA_BUG(!l); | |
107 | ||
108 | label_for_each(i, l, p) { | |
109 | if (p == profile) | |
110 | return i.i; | |
111 | } | |
112 | ||
113 | return -1; | |
114 | } | |
115 | #endif | |
116 | ||
117 | #if 0 | |
118 | static bool profile_in_label(struct aa_profile *profile, struct aa_label *l) | |
119 | { | |
120 | return label_profile_pos(l, profile) != -1; | |
121 | } | |
122 | #endif | |
123 | ||
124 | static bool label_profiles_unconfined(struct aa_label *label) | |
125 | { | |
126 | struct aa_profile *profile; | |
127 | struct label_it i; | |
128 | ||
129 | AA_BUG(!label); | |
130 | ||
131 | label_for_each(i, label, profile) { | |
132 | if (!profile_unconfined(profile)) | |
133 | return false; | |
134 | } | |
135 | ||
136 | return true; | |
137 | } | |
138 | ||
139 | static int profile_cmp(struct aa_profile *a, struct aa_profile *b); | |
140 | /** | |
141 | * aa_label_next_not_in_set - return the next profile of @sub not in @set | |
142 | * @I: label iterator | |
143 | * @set: label to test against | |
144 | * @sub: label to if is subset of @set | |
145 | * | |
146 | * Returns: profile in @sub that is not in @set, with iterator set pos after | |
147 | * else NULL if @sub is a subset of @set | |
148 | */ | |
d39820a1 JJ |
149 | struct aa_profile * aa_label_next_not_in_set(struct label_it *I, |
150 | struct aa_label *set, | |
151 | struct aa_label *sub) | |
6bfc18ae JJ |
152 | { |
153 | AA_BUG(!set); | |
154 | AA_BUG(!I); | |
155 | AA_BUG(I->i < 0); | |
156 | AA_BUG(I->i > set->size); | |
157 | AA_BUG(!sub); | |
158 | AA_BUG(I->j < 0); | |
159 | AA_BUG(I->j > sub->size); | |
160 | ||
161 | while (I->j < sub->size && I->i < set->size) { | |
162 | int res = profile_cmp(sub->ent[I->j], set->ent[I->i]); | |
163 | if (res == 0) { | |
164 | (I->j)++; | |
165 | (I->i)++; | |
166 | } else if (res > 0) | |
167 | (I->i)++; | |
168 | else | |
169 | return sub->ent[(I->j)++]; | |
170 | } | |
171 | ||
172 | if (I->j < sub->size) | |
173 | return sub->ent[(I->j)++]; | |
174 | ||
175 | return NULL; | |
176 | } | |
177 | ||
178 | /** | |
179 | * aa_label_is_subset - test if @sub is a subset of @set | |
180 | * @set: label to test against | |
181 | * @sub: label to test if is subset of @set | |
182 | * | |
183 | * Returns: true if @sub is subset of @set | |
184 | * else false | |
185 | */ | |
186 | bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub) | |
187 | { | |
188 | struct label_it i = { }; | |
189 | ||
190 | AA_BUG(!set); | |
191 | AA_BUG(!sub); | |
192 | ||
193 | if (sub == set) | |
194 | return true; | |
195 | ||
d39820a1 | 196 | return aa_label_next_not_in_set(&i, set, sub) == NULL; |
6bfc18ae JJ |
197 | } |
198 | ||
199 | void aa_label_destroy(struct aa_label *label) | |
200 | { | |
201 | AA_BUG(!label); | |
202 | ||
203 | if (label_invalid(label)) | |
204 | labelsetstats_dec(labels_set(label), invalid); | |
205 | ||
206 | if (!label_isprofile(label)) { | |
207 | struct aa_profile *profile; | |
208 | struct label_it i; | |
209 | ||
210 | aa_put_str(label->hname); | |
211 | ||
1963692b | 212 | label_for_each(i, label, profile) |
6bfc18ae JJ |
213 | aa_put_profile(profile); |
214 | } | |
1963692b | 215 | |
6bfc18ae JJ |
216 | aa_free_sid(label->sid); |
217 | aa_put_replacedby(label->replacedby); | |
218 | } | |
219 | ||
220 | void aa_label_free(struct aa_label *label) | |
221 | { | |
222 | if (!label) | |
223 | return; | |
224 | ||
225 | aa_label_destroy(label); | |
226 | labelstats_inc(freed); | |
1963692b | 227 | kzfree(label); |
6bfc18ae JJ |
228 | } |
229 | ||
e6ce3c3c | 230 | static void label_free_rcu(struct rcu_head *head) |
6bfc18ae | 231 | { |
e6ce3c3c JJ |
232 | struct aa_label *l = container_of(head, struct aa_label, rcu); |
233 | ||
6bfc18ae JJ |
234 | if (l->flags & FLAG_NS_COUNT) |
235 | aa_free_namespace(labels_ns(l)); | |
236 | else if (label_isprofile(l)) | |
237 | aa_free_profile(labels_profile(l)); | |
238 | else | |
239 | aa_label_free(l); | |
240 | } | |
241 | ||
242 | bool aa_label_remove(struct aa_labelset *ls, struct aa_label *label); | |
243 | void aa_label_kref(struct kref *kref) | |
244 | { | |
245 | struct aa_label *l = container_of(kref, struct aa_label, count); | |
246 | struct aa_namespace *ns = labels_ns(l); | |
247 | ||
248 | if (!ns) { | |
249 | /* never live, no rcu callback needed, just using the fn */ | |
e6ce3c3c | 250 | label_free_rcu(&l->rcu); |
6bfc18ae JJ |
251 | return; |
252 | } | |
253 | ||
e6ce3c3c JJ |
254 | (void) aa_label_remove(&ns->labels, l); |
255 | ||
6bfc18ae JJ |
256 | /* TODO: if compound label and not invalid add to reclaim cache */ |
257 | call_rcu(&l->rcu, label_free_rcu); | |
258 | } | |
259 | ||
260 | bool aa_label_init(struct aa_label *label, int size) | |
261 | { | |
262 | AA_BUG(!label); | |
263 | AA_BUG(size < 1); | |
264 | ||
265 | label->sid = aa_alloc_sid(); | |
266 | if (label->sid == AA_SID_INVALID) | |
267 | return false; | |
268 | ||
269 | label->size = size; /* doesn't include null */ | |
270 | label->ent[size] = NULL; /* null terminate */ | |
271 | kref_init(&label->count); | |
272 | RB_CLEAR_NODE(&label->node); | |
273 | ||
274 | return true; | |
275 | } | |
276 | ||
277 | /** | |
278 | * aa_label_alloc - allocate a label with a profile vector of @size length | |
279 | * @size: size of profile vector in the label | |
280 | * @gfp: memory allocation type | |
281 | * | |
282 | * Returns: new label | |
283 | * else NULL if failed | |
284 | */ | |
f126fd25 | 285 | struct aa_label *aa_label_alloc(int size, gfp_t gfp) |
6bfc18ae JJ |
286 | { |
287 | struct aa_label *label; | |
288 | ||
289 | AA_BUG(size < 1); | |
290 | ||
291 | /* vector: size - 2 (size of array in label struct) + 1 for null */ | |
292 | label = kzalloc(sizeof(*label) + sizeof(struct aa_label *) * (size - 1), | |
293 | gfp); | |
294 | AA_DEBUG("%s (%p)\n", __func__, label); | |
295 | if (!label) | |
296 | goto fail; | |
297 | ||
298 | if (!aa_label_init(label, size)) | |
299 | goto fail; | |
300 | ||
301 | labelstats_inc(allocated); | |
302 | ||
303 | return label; | |
304 | ||
305 | fail: | |
306 | kfree(label); | |
307 | labelstats_inc(failed); | |
308 | ||
309 | return NULL; | |
310 | } | |
311 | ||
67194e9d | 312 | static bool __aa_label_remove(struct aa_labelset *ls, struct aa_label *label) |
6bfc18ae JJ |
313 | { |
314 | AA_BUG(!ls); | |
315 | AA_BUG(!label); | |
316 | AA_BUG(!write_is_locked(&ls->lock)); | |
317 | AA_BUG(labels_set(label) != ls); | |
318 | ||
319 | if (label_invalid(label)) | |
320 | labelstats_dec(invalid_intree); | |
321 | else | |
322 | __label_invalidate(label); | |
323 | ||
324 | if (label->flags & FLAG_IN_TREE) { | |
325 | labelsetstats_dec(ls, intree); | |
326 | rb_erase(&label->node, &ls->root); | |
327 | label->flags &= ~FLAG_IN_TREE; | |
328 | return true; | |
329 | } | |
330 | ||
331 | return false; | |
332 | } | |
333 | ||
334 | /** | |
335 | * aa_label_remove - remove a label from the labelset | |
336 | * @ls: set to remove the label from | |
337 | * @l: label to remove | |
338 | * | |
339 | * Returns: true if @l was removed from the tree | |
340 | * else @l was not in tree so it could not be removed | |
341 | */ | |
342 | bool aa_label_remove(struct aa_labelset *ls, struct aa_label *l) | |
343 | { | |
344 | unsigned long flags; | |
345 | bool res; | |
346 | ||
347 | write_lock_irqsave(&ls->lock, flags); | |
67194e9d | 348 | res = __aa_label_remove(ls, l); |
6bfc18ae JJ |
349 | write_unlock_irqrestore(&ls->lock, flags); |
350 | ||
351 | return res; | |
352 | } | |
353 | ||
709bba29 | 354 | #if 0 |
6bfc18ae JJ |
355 | /* don't use when using ptr comparisons because nodes should never be |
356 | * the same | |
357 | */ | |
358 | static bool __aa_label_replace(struct aa_labelset *ls, struct aa_label *old, | |
359 | struct aa_label *new) | |
360 | { | |
361 | AA_BUG(!ls); | |
362 | AA_BUG(!old); | |
363 | AA_BUG(!new); | |
364 | AA_BUG(!write_is_locked(&ls->lock)); | |
365 | AA_BUG(labels_set(old) != ls); | |
366 | AA_BUG(new->flags & FLAG_IN_TREE); | |
367 | ||
368 | if (label_invalid(old)) | |
369 | labelstats_dec(invalid_intree); | |
370 | else | |
371 | __label_invalidate(old); | |
372 | ||
373 | if (old->flags & FLAG_IN_TREE) { | |
374 | rb_replace_node(&old->node, &new->node, &ls->root); | |
375 | old->flags &= ~FLAG_IN_TREE; | |
376 | new->flags |= FLAG_IN_TREE; | |
377 | return true; | |
378 | } | |
379 | ||
380 | return false; | |
381 | } | |
709bba29 | 382 | #endif |
6bfc18ae JJ |
383 | |
384 | static struct aa_label *__aa_label_insert(struct aa_labelset *ls, | |
709bba29 | 385 | struct aa_label *l); |
6bfc18ae JJ |
386 | |
387 | static struct aa_label *__aa_label_remove_and_insert(struct aa_labelset *ls, | |
388 | struct aa_label *remove, | |
e23c92ae | 389 | struct aa_label *insert) |
6bfc18ae JJ |
390 | { |
391 | AA_BUG(!ls); | |
392 | AA_BUG(!remove); | |
393 | AA_BUG(!insert); | |
394 | AA_BUG(!write_is_locked(&ls->lock)); | |
395 | AA_BUG(labels_set(remove) != ls); | |
396 | AA_BUG(insert->flags & FLAG_IN_TREE); | |
397 | ||
67194e9d | 398 | __aa_label_remove(ls, remove); |
709bba29 | 399 | return __aa_label_insert(ls, insert); |
6bfc18ae JJ |
400 | } |
401 | ||
402 | struct aa_label *aa_label_remove_and_insert(struct aa_labelset *ls, | |
403 | struct aa_label *remove, | |
404 | struct aa_label *insert) | |
405 | { | |
406 | unsigned long flags; | |
407 | struct aa_label *l; | |
408 | ||
409 | write_lock_irqsave(&ls->lock, flags); | |
e23c92ae | 410 | l = aa_get_label(__aa_label_remove_and_insert(ls, remove, insert)); |
6bfc18ae JJ |
411 | write_unlock_irqrestore(&ls->lock, flags); |
412 | ||
413 | return l; | |
414 | } | |
415 | ||
416 | /** | |
417 | * aa_label_replace - replace a label @old with a new version @new | |
4d69b183 | 418 | * @ls: labelset being manipulated |
6bfc18ae JJ |
419 | * @old: label to replace |
420 | * @new: label replacing @old | |
421 | * | |
422 | * Returns: true if @old was in tree and replaced | |
423 | * else @old was not in tree, and @new was not inserted | |
424 | */ | |
4d69b183 JJ |
425 | bool aa_label_replace(struct aa_labelset *ls, struct aa_label *old, |
426 | struct aa_label *new) | |
6bfc18ae | 427 | { |
4d69b183 | 428 | struct aa_label *l; |
6bfc18ae JJ |
429 | unsigned long flags; |
430 | bool res; | |
431 | ||
4d69b183 | 432 | write_lock_irqsave(&ls->lock, flags); |
e23c92ae | 433 | if (!(old->flags & FLAG_IN_TREE)) |
709bba29 | 434 | l = __aa_label_insert(ls, new); |
e23c92ae JJ |
435 | else |
436 | l = __aa_label_remove_and_insert(ls, old, new); | |
4d69b183 JJ |
437 | res = (l == new); |
438 | write_unlock_irqrestore(&ls->lock, flags); | |
6bfc18ae JJ |
439 | |
440 | return res; | |
441 | } | |
442 | ||
443 | static int ns_cmp(struct aa_namespace *a, struct aa_namespace *b) | |
444 | { | |
445 | int res; | |
446 | ||
447 | AA_BUG(!a); | |
448 | AA_BUG(!b); | |
449 | AA_BUG(!a->base.name); | |
450 | AA_BUG(!b->base.name); | |
451 | ||
452 | if (a == b) | |
453 | return 0; | |
454 | ||
455 | res = a->level - b->level; | |
456 | if (res) | |
457 | return res; | |
458 | ||
459 | return strcmp(a->base.name, b->base.name); | |
460 | } | |
461 | ||
462 | /** | |
463 | * profile_cmp - profile comparision for set ordering | |
464 | * @a: profile to compare (NOT NULL) | |
465 | * @b: profile to compare (NOT NULL) | |
466 | * | |
467 | * Returns: <0 if a < b | |
468 | * ==0 if a == b | |
469 | * >0 if a > b | |
470 | */ | |
471 | static int profile_cmp(struct aa_profile *a, struct aa_profile *b) | |
472 | { | |
473 | int res; | |
474 | ||
475 | AA_BUG(!a); | |
476 | AA_BUG(!b); | |
477 | AA_BUG(!a->ns); | |
478 | AA_BUG(!b->ns); | |
479 | AA_BUG(!a->base.hname); | |
480 | AA_BUG(!b->base.hname); | |
481 | ||
482 | if (a == b || a->base.hname == b->base.hname) | |
483 | return 0; | |
484 | res = ns_cmp(a->ns, b->ns); | |
485 | if (res) | |
486 | return res; | |
487 | ||
488 | return strcmp(a->base.hname, b->base.hname); | |
489 | } | |
490 | ||
491 | /** | |
492 | * label_vec_cmp - label comparision for set ordering | |
493 | * @a: label to compare (NOT NULL) | |
494 | * @vec: vector of profiles to compare (NOT NULL) | |
495 | * @n: length of @vec | |
496 | * | |
497 | * Returns: <0 if a < vec | |
498 | * ==0 if a == vec | |
499 | * >0 if a > vec | |
500 | */ | |
501 | static int label_vec_cmp(struct aa_label *a, struct aa_profile **vec, int n) | |
502 | { | |
503 | int i; | |
504 | ||
505 | AA_BUG(!a); | |
506 | AA_BUG(!vec); | |
507 | AA_BUG(!*vec); | |
508 | AA_BUG(n <= 0); | |
509 | ||
510 | for (i = 0; i < a->size && i < n; i++) { | |
511 | int res = profile_cmp(a->ent[i], vec[i]); | |
512 | if (res != 0) | |
513 | return res; | |
514 | } | |
515 | ||
516 | return a->size - n; | |
517 | } | |
518 | ||
519 | /** | |
520 | * label_cmp - label comparision for set ordering | |
521 | * @a: label to compare (NOT NULL) | |
522 | * @b: label to compare (NOT NULL) | |
523 | * | |
524 | * Returns: <0 if a < b | |
525 | * ==0 if a == b | |
526 | * >0 if a > b | |
527 | */ | |
528 | static int label_cmp(struct aa_label *a, struct aa_label *b) | |
529 | { | |
530 | AA_BUG(!b); | |
531 | ||
532 | if (a == b) | |
533 | return 0; | |
534 | ||
535 | return label_vec_cmp(a, b->ent, b->size); | |
536 | } | |
537 | ||
538 | /** | |
539 | * __aa_label_vec_find - find label that matches @vec in label set | |
540 | * @ls: set of labels to search (NOT NULL) | |
541 | * @vec: vec of profiles to find matching label for (NOT NULL) | |
542 | * @n: length of @vec | |
543 | * | |
544 | * Requires: @ls lock held | |
545 | * caller to hold a valid ref on l | |
546 | * | |
e23c92ae | 547 | * Returns: unref counted @label if matching label is in tree |
6bfc18ae JJ |
548 | * else NULL if @vec equiv is not in tree |
549 | */ | |
550 | static struct aa_label *__aa_label_vec_find(struct aa_labelset *ls, | |
551 | struct aa_profile **vec, int n) | |
552 | { | |
553 | struct rb_node *node; | |
554 | ||
555 | AA_BUG(!ls); | |
556 | AA_BUG(!vec); | |
557 | AA_BUG(!*vec); | |
558 | AA_BUG(n <= 0); | |
559 | ||
560 | node = ls->root.rb_node; | |
561 | while (node) { | |
562 | struct aa_label *this = rb_entry(node, struct aa_label, node); | |
563 | int result = label_vec_cmp(this, vec, n); | |
564 | ||
565 | if (result > 0) | |
566 | node = node->rb_left; | |
567 | else if (result < 0) | |
568 | node = node->rb_right; | |
569 | else | |
e23c92ae | 570 | return this; |
6bfc18ae JJ |
571 | } |
572 | ||
573 | return NULL; | |
574 | } | |
575 | ||
576 | /** | |
577 | * __aa_label_find - find label @l in label set | |
578 | * @ls: set of labels to search (NOT NULL) | |
579 | * @l: label to find (NOT NULL) | |
580 | * | |
581 | * Requires: @ls lock held | |
582 | * caller to hold a valid ref on l | |
583 | * | |
e23c92ae JJ |
584 | * Returns: unref counted @l if @l is in tree |
585 | * unref counted label that is equiv to @l in tree | |
6bfc18ae JJ |
586 | * else NULL if @l or equiv is not in tree |
587 | */ | |
588 | static struct aa_label *__aa_label_find(struct aa_labelset *ls, | |
589 | struct aa_label *l) | |
590 | { | |
591 | AA_BUG(!l); | |
592 | ||
593 | return __aa_label_vec_find(ls, l->ent, l->size); | |
594 | } | |
595 | ||
596 | /** | |
597 | * aa_label_vec_find - find label @l in label set | |
598 | * @ls: set of labels to search (NOT NULL) | |
599 | * @vec: array of profiles to find equiv label for (NOT NULL) | |
600 | * @n: length of @vec | |
601 | * | |
602 | * Returns: refcounted label if @vec equiv is in tree | |
603 | * else NULL if @vec equiv is not in tree | |
604 | */ | |
605 | struct aa_label *aa_label_vec_find(struct aa_labelset *ls, | |
606 | struct aa_profile **vec, | |
607 | int n) | |
608 | { | |
609 | struct aa_label *label; | |
610 | unsigned long flags; | |
611 | ||
612 | AA_BUG(!ls); | |
613 | AA_BUG(!vec); | |
614 | AA_BUG(!*vec); | |
615 | AA_BUG(n <= 0); | |
616 | ||
617 | read_lock_irqsave(&ls->lock, flags); | |
e23c92ae | 618 | label = aa_get_label(__aa_label_vec_find(ls, vec, n)); |
6bfc18ae JJ |
619 | labelstats_inc(sread); |
620 | read_unlock_irqrestore(&ls->lock, flags); | |
621 | ||
622 | return label; | |
623 | } | |
624 | ||
625 | /** | |
626 | * aa_label_find - find label @l in label set | |
627 | * @ls: set of labels to search (NOT NULL) | |
628 | * @l: label to find (NOT NULL) | |
629 | * | |
630 | * Requires: caller to hold a valid ref on l | |
631 | * | |
632 | * Returns: refcounted @l if @l is in tree | |
633 | * refcounted label that is equiv to @l in tree | |
634 | * else NULL if @l or equiv is not in tree | |
635 | */ | |
636 | struct aa_label *aa_label_find(struct aa_labelset *ls, struct aa_label *l) | |
637 | { | |
638 | AA_BUG(!l); | |
639 | ||
640 | return aa_label_vec_find(ls, l->ent, l->size); | |
641 | } | |
642 | ||
643 | /** | |
644 | * __aa_label_insert - attempt to insert @l into a label set | |
645 | * @ls: set of labels to insert @l into (NOT NULL) | |
646 | * @l: new label to insert (NOT NULL) | |
709bba29 | 647 | * |
6bfc18ae JJ |
648 | * Requires: @ls->lock |
649 | * caller to hold a valid ref on l | |
93e7aa83 | 650 | * |
e23c92ae JJ |
651 | * Returns: @l if successful in inserting @l |
652 | * else ref counted equivalent label that is already in the set. | |
6bfc18ae JJ |
653 | */ |
654 | static struct aa_label *__aa_label_insert(struct aa_labelset *ls, | |
709bba29 | 655 | struct aa_label *l) |
6bfc18ae JJ |
656 | { |
657 | struct rb_node **new, *parent = NULL; | |
658 | ||
659 | AA_BUG(!ls); | |
660 | AA_BUG(!l); | |
661 | AA_BUG(!write_is_locked(&ls->lock)); | |
662 | AA_BUG(l->flags & FLAG_IN_TREE); | |
663 | ||
664 | /* Figure out where to put new node */ | |
665 | new = &ls->root.rb_node; | |
666 | while (*new) { | |
667 | struct aa_label *this = rb_entry(*new, struct aa_label, node); | |
668 | int result = label_cmp(l, this); | |
669 | ||
670 | parent = *new; | |
671 | if (result == 0) { | |
672 | labelsetstats_inc(ls, existing); | |
709bba29 | 673 | return this; |
6bfc18ae JJ |
674 | } else if (result < 0) |
675 | new = &((*new)->rb_left); | |
676 | else /* (result > 0) */ | |
677 | new = &((*new)->rb_right); | |
678 | } | |
679 | ||
680 | /* Add new node and rebalance tree. */ | |
681 | rb_link_node(&l->node, parent, new); | |
682 | rb_insert_color(&l->node, &ls->root); | |
683 | l->flags |= FLAG_IN_TREE; | |
684 | labelsetstats_inc(ls, insert); | |
685 | labelsetstats_inc(ls, intree); | |
686 | ||
709bba29 | 687 | return l; |
6bfc18ae JJ |
688 | } |
689 | ||
690 | /** | |
691 | * aa_label_insert - insert label @l into @ls or return existing label | |
692 | * @ls - labelset to insert @l into | |
693 | * @l - label to insert | |
694 | * | |
695 | * Requires: caller to hold a valid ref on l | |
696 | * | |
697 | * Returns: ref counted @l if successful in inserting @l | |
698 | * else ref counted equivalent label that is already in the set | |
699 | */ | |
700 | struct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *l) | |
701 | { | |
702 | struct aa_label *label; | |
703 | unsigned long flags; | |
704 | ||
705 | AA_BUG(!ls); | |
706 | AA_BUG(!l); | |
707 | ||
708 | /* check if label exists before taking lock */ | |
709 | if (!label_invalid(l)) { | |
710 | read_lock_irqsave(&ls->lock, flags); | |
e23c92ae | 711 | label = aa_get_label(__aa_label_find(ls, l)); |
6bfc18ae JJ |
712 | read_unlock_irqrestore(&ls->lock, flags); |
713 | labelstats_inc(fread); | |
714 | if (label) | |
715 | return label; | |
716 | } | |
717 | ||
718 | write_lock_irqsave(&ls->lock, flags); | |
709bba29 | 719 | label = aa_get_label(__aa_label_insert(ls, l)); |
6bfc18ae JJ |
720 | write_unlock_irqrestore(&ls->lock, flags); |
721 | ||
722 | return label; | |
723 | } | |
724 | ||
1c7d0095 | 725 | struct aa_label *aa_label_vec_find_or_create(struct aa_labelset *ls, |
6bfc18ae JJ |
726 | struct aa_profile **vec, int len) |
727 | { | |
728 | struct aa_label *label = aa_label_vec_find(ls, vec, len); | |
729 | if (label) | |
730 | return label; | |
731 | ||
732 | return aa_label_vec_merge(vec, len, GFP_KERNEL); | |
733 | } | |
734 | ||
735 | /** | |
736 | * aa_label_next_in_merge - find the next profile when merging @a and @b | |
737 | * @I: label iterator | |
738 | * @a: label to merge | |
739 | * @b: label to merge | |
740 | * | |
741 | * Returns: next profile | |
742 | * else null if no more profiles | |
743 | */ | |
744 | struct aa_profile *aa_label_next_in_merge(struct label_it *I, | |
745 | struct aa_label *a, | |
746 | struct aa_label *b) | |
747 | { | |
748 | AA_BUG(!a); | |
749 | AA_BUG(!b); | |
750 | AA_BUG(!I); | |
751 | AA_BUG(I->i < 0); | |
752 | AA_BUG(I->i > a->size); | |
753 | AA_BUG(I->j < 0); | |
754 | AA_BUG(I->j > b->size); | |
755 | ||
756 | if (I->i < a->size) { | |
757 | if (I->j < b->size) { | |
758 | int res = profile_cmp(a->ent[I->i], b->ent[I->j]); | |
759 | if (res > 0) | |
760 | return b->ent[(I->j)++]; | |
761 | if (res == 0) | |
762 | (I->j)++; | |
763 | } | |
764 | ||
765 | return a->ent[(I->i)++]; | |
766 | } | |
767 | ||
768 | if (I->j < b->size) | |
769 | return b->ent[(I->j)++]; | |
770 | ||
771 | return NULL; | |
772 | } | |
773 | ||
774 | /** | |
775 | * label_merge_cmp - cmp of @a merging with @b against @z for set ordering | |
776 | * @a: label to merge then compare (NOT NULL) | |
777 | * @b: label to merge then compare (NOT NULL) | |
778 | * @z: label to compare merge against (NOT NULL) | |
779 | * | |
780 | * Assumes: using the most recent versions of @a, @b, and @z | |
781 | * | |
782 | * Returns: <0 if a < b | |
783 | * ==0 if a == b | |
784 | * >0 if a > b | |
785 | */ | |
786 | static int label_merge_cmp(struct aa_label *a, struct aa_label *b, | |
787 | struct aa_label *z) | |
788 | { | |
789 | struct aa_profile *p = NULL; | |
790 | struct label_it i = { }; | |
791 | int k; | |
792 | ||
793 | AA_BUG(!a); | |
794 | AA_BUG(!b); | |
795 | AA_BUG(!z); | |
796 | ||
797 | for (k = 0; | |
798 | k < z->size && (p = aa_label_next_in_merge(&i, a, b)); | |
799 | k++) { | |
800 | int res = profile_cmp(p, z->ent[k]); | |
801 | ||
802 | if (res != 0) | |
803 | return res; | |
804 | } | |
805 | ||
806 | if (p) | |
807 | return 1; | |
808 | else if (k < z->size) | |
809 | return -1; | |
810 | return 0; | |
811 | } | |
812 | ||
813 | #if 0 | |
814 | /** | |
815 | * label_merge_len - find the length of the merge of @a and @b | |
816 | * @a: label to merge (NOT NULL) | |
817 | * @b: label to merge (NOT NULL) | |
818 | * | |
819 | * Assumes: using newest versions of labels @a and @b | |
820 | * | |
821 | * Returns: length of a label vector for merge of @a and @b | |
822 | */ | |
823 | static int label_merge_len(struct aa_label *a, struct aa_label *b) | |
824 | { | |
825 | int len = a->size + b->size; | |
826 | int i, j; | |
827 | ||
828 | AA_BUG(!a); | |
829 | AA_BUG(!b); | |
830 | ||
831 | /* find entries in common and remove from count */ | |
832 | for (i = j = 0; i < a->size && j < b->size; ) { | |
833 | int res = profile_cmp(a->ent[i], b->ent[j]); | |
834 | if (res == 0) { | |
835 | len--; | |
836 | i++; | |
837 | j++; | |
838 | } else if (res < 0) | |
839 | i++; | |
840 | else | |
841 | j++; | |
842 | } | |
843 | ||
844 | return len; | |
845 | } | |
846 | #endif | |
847 | ||
848 | /** | |
849 | * aa_sort_and_merge_profiles - canonical sort and merge a list of profiles | |
850 | * @n: number of refcounted profiles in the list (@n > 0) | |
851 | * @ps: list of profiles to sort and merge | |
852 | * | |
853 | * Returns: the number of duplicates eliminated == references put | |
854 | */ | |
855 | static int aa_sort_and_merge_profiles(int n, struct aa_profile **ps) | |
856 | { | |
857 | int i, dups = 0; | |
858 | ||
859 | AA_BUG(n < 1); | |
860 | AA_BUG(!ps); | |
861 | ||
862 | /* label lists are usually small so just use insertion sort */ | |
863 | for (i = 1; i < n; i++) { | |
864 | struct aa_profile *tmp = ps[i]; | |
865 | int pos, j; | |
866 | ||
867 | for (pos = i - 1 - dups; pos >= 0; pos--) { | |
868 | int res = profile_cmp(ps[pos], tmp); | |
869 | if (res == 0) { | |
870 | aa_put_profile(tmp); | |
871 | dups++; | |
872 | goto continue_outer; | |
873 | } else if (res < 0) | |
874 | break; | |
875 | } | |
876 | pos++; | |
877 | ||
878 | for (j = i - dups; j > pos; j--) | |
879 | ps[j] = ps[j - 1]; | |
880 | ps[pos] = tmp; | |
881 | continue_outer: | |
882 | ; /* sigh empty statement required after the label */ | |
883 | } | |
884 | ||
885 | return dups; | |
886 | } | |
887 | ||
888 | /** | |
709bba29 | 889 | * __label_merge - create a new label by merging @a and @b |
6bfc18ae JJ |
890 | * @l: preallocated label to merge into (NOT NULL) |
891 | * @a: label to merge with @b (NOT NULL) | |
892 | * @b: label to merge with @a (NOT NULL) | |
893 | * | |
894 | * Returns: ref counted label either l if merge is unique | |
895 | * a if b is a subset of a | |
896 | * b if a is a subset of b | |
897 | * | |
898 | * NOTE: will not use l if the merge results in l == a or b | |
899 | * | |
900 | * Must be used within labelset write lock to avoid racing with | |
901 | * label invalidation. | |
902 | */ | |
709bba29 JJ |
903 | static struct aa_label *__label_merge(struct aa_label *l, struct aa_label *a, |
904 | struct aa_label *b) | |
6bfc18ae JJ |
905 | { |
906 | struct aa_profile *next; | |
907 | struct label_it i; | |
908 | int k = 0, invcount = 0; | |
909 | ||
910 | AA_BUG(!a); | |
911 | AA_BUG(a->size < 0); | |
912 | AA_BUG(!b); | |
913 | AA_BUG(b->size < 0); | |
914 | AA_BUG(!l); | |
915 | AA_BUG(l->size < a->size + b->size); | |
916 | ||
7e972668 JJ |
917 | if (a == b) |
918 | return aa_get_label(a); | |
919 | ||
6bfc18ae JJ |
920 | label_for_each_in_merge(i, a, b, next) { |
921 | if (PROFILE_INVALID(next)) { | |
922 | l->ent[k] = aa_get_newest_profile(next); | |
923 | if (next->label.replacedby != | |
924 | l->ent[k]->label.replacedby) | |
925 | invcount++; | |
926 | k++; | |
927 | } else | |
928 | l->ent[k++] = aa_get_profile(next); | |
929 | } | |
930 | /* set to actual size which is <= allocated len */ | |
931 | l->size = k; | |
932 | l->ent[k] = NULL; | |
933 | ||
934 | if (invcount) { | |
935 | l->size -= aa_sort_and_merge_profiles(l->size, &l->ent[0]); | |
709bba29 JJ |
936 | if (label_profiles_unconfined(l)) |
937 | l->flags |= FLAG_UNCONFINED; | |
938 | } else { | |
939 | /* merge is same as at least one of the labels */ | |
6bfc18ae JJ |
940 | if (k == a->size) |
941 | return aa_get_label(a); | |
942 | else if (k == b->size) | |
943 | return aa_get_label(b); | |
709bba29 JJ |
944 | |
945 | l->flags |= a->flags & b->flags & FLAG_UNCONFINED; | |
6bfc18ae | 946 | } |
e23c92ae JJ |
947 | |
948 | return aa_get_label(l); | |
6bfc18ae JJ |
949 | } |
950 | ||
951 | /** | |
952 | * labelset_of_merge - find into which labelset a merged label should be inserted | |
953 | * @a: label to merge and insert | |
954 | * @b: label to merge and insert | |
955 | * | |
956 | * Returns: labelset that the merged label should be inserted into | |
957 | */ | |
958 | static struct aa_labelset *labelset_of_merge(struct aa_label *a, struct aa_label *b) | |
959 | { | |
960 | struct aa_namespace *nsa = labels_ns(a); | |
961 | struct aa_namespace *nsb = labels_ns(b); | |
962 | ||
963 | if (ns_cmp(nsa, nsb) <= 0) | |
964 | return &nsa->labels; | |
965 | return &nsb->labels; | |
966 | } | |
967 | ||
968 | /** | |
969 | * __aa_label_find_merge - find label that is equiv to merge of @a and @b | |
970 | * @ls: set of labels to search (NOT NULL) | |
971 | * @a: label to merge with @b (NOT NULL) | |
972 | * @b: label to merge with @a (NOT NULL) | |
973 | * | |
974 | * Requires: read_lock held | |
975 | * | |
e23c92ae | 976 | * Returns: unref counted label that is equiv to merge of @a and @b |
6bfc18ae JJ |
977 | * else NULL if merge of @a and @b is not in set |
978 | */ | |
979 | static struct aa_label *__aa_label_find_merge(struct aa_labelset *ls, | |
980 | struct aa_label *a, | |
981 | struct aa_label *b) | |
982 | { | |
983 | struct rb_node *node; | |
984 | ||
985 | AA_BUG(!ls); | |
986 | AA_BUG(!a); | |
987 | AA_BUG(!b); | |
988 | ||
989 | if (a == b) | |
990 | return __aa_label_find(ls, a); | |
991 | ||
992 | node = ls->root.rb_node; | |
993 | while (node) { | |
994 | struct aa_label *this = container_of(node, struct aa_label, | |
995 | node); | |
996 | int result = label_merge_cmp(a, b, this); | |
997 | ||
998 | if (result < 0) | |
999 | node = node->rb_left; | |
1000 | else if (result > 0) | |
1001 | node = node->rb_right; | |
1002 | else | |
e23c92ae | 1003 | return this; |
6bfc18ae JJ |
1004 | } |
1005 | ||
1006 | return NULL; | |
1007 | } | |
1008 | ||
1009 | ||
1010 | /** | |
1011 | * __aa_label_find_merge - find label that is equiv to merge of @a and @b | |
1012 | * @a: label to merge with @b (NOT NULL) | |
1013 | * @b: label to merge with @a (NOT NULL) | |
1014 | * | |
1015 | * Requires: labels be fully constructed with a valid ns | |
1016 | * | |
1017 | * Returns: ref counted label that is equiv to merge of @a and @b | |
1018 | * else NULL if merge of @a and @b is not in set | |
1019 | */ | |
1020 | struct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b) | |
1021 | { | |
1022 | struct aa_labelset *ls; | |
1023 | struct aa_label *label, *ar = NULL, *br = NULL; | |
1024 | unsigned long flags; | |
1025 | ||
1026 | AA_BUG(!a); | |
1027 | AA_BUG(!b); | |
1028 | ||
1029 | ls = labelset_of_merge(a, b); | |
1030 | read_lock_irqsave(&ls->lock, flags); | |
1031 | if (label_invalid(a)) | |
1032 | a = ar = aa_get_newest_label(a); | |
1033 | if (label_invalid(b)) | |
1034 | b = br = aa_get_newest_label(b); | |
e23c92ae | 1035 | label = aa_get_label(__aa_label_find_merge(ls, a, b)); |
6bfc18ae JJ |
1036 | read_unlock_irqrestore(&ls->lock, flags); |
1037 | aa_put_label(ar); | |
1038 | aa_put_label(br); | |
1039 | labelsetstats_inc(ls, msread); | |
1040 | ||
1041 | return label; | |
1042 | } | |
1043 | ||
1044 | /** | |
1045 | * aa_label_merge - attempt to insert new merged label of @a and @b | |
1046 | * @ls: set of labels to insert label into (NOT NULL) | |
1047 | * @a: label to merge with @b (NOT NULL) | |
1048 | * @b: label to merge with @a (NOT NULL) | |
1049 | * @gfp: memory allocation type | |
1050 | * | |
1051 | * Requires: caller to hold valid refs on @a and @b | |
1052 | * labels be fully constructed with a valid ns | |
1053 | * | |
1054 | * Returns: ref counted new label if successful in inserting merge of a & b | |
1055 | * else ref counted equivalent label that is already in the set. | |
1056 | * else NULL if could not create label (-ENOMEM) | |
1057 | */ | |
1058 | struct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b, | |
1059 | gfp_t gfp) | |
1060 | { | |
1061 | struct aa_label *label = NULL; | |
1062 | struct aa_labelset *ls; | |
1063 | unsigned long flags; | |
1064 | ||
1065 | AA_BUG(!a); | |
1066 | AA_BUG(!b); | |
1067 | ||
1068 | if (a == b) | |
1069 | return aa_get_newest_label(a); | |
1070 | ||
1071 | ls = labelset_of_merge(a, b); | |
1072 | ||
1073 | /* TODO: enable when read side is lockless | |
1074 | * check if label exists before taking locks | |
1075 | if (!label_invalid(a) && !label_invalid(b)) | |
1076 | label = aa_label_find_merge(a, b); | |
1077 | */ | |
1078 | ||
1079 | if (!label) { | |
709bba29 | 1080 | struct aa_label *new, *l; |
6bfc18ae JJ |
1081 | |
1082 | a = aa_get_newest_label(a); | |
1083 | b = aa_get_newest_label(b); | |
1084 | ||
1085 | /* could use label_merge_len(a, b), but requires double | |
1086 | * comparison for small savings | |
1087 | */ | |
f126fd25 | 1088 | new = aa_label_alloc(a->size + b->size, gfp); |
6bfc18ae | 1089 | if (!new) |
03c5aa50 | 1090 | return NULL; |
93e7aa83 | 1091 | |
6bfc18ae | 1092 | write_lock_irqsave(&ls->lock, flags); |
709bba29 JJ |
1093 | l = __label_merge(new, a, b); |
1094 | if (l != new) { | |
7e972668 JJ |
1095 | /* new may not be fully setup so no put_label */ |
1096 | aa_label_free(new); | |
1097 | new = NULL; | |
1098 | } | |
709bba29 JJ |
1099 | if (!(l->flags & FLAG_IN_TREE)) |
1100 | label = aa_get_label(__aa_label_insert(ls, l)); | |
1101 | write_unlock_irqrestore(&ls->lock, flags); | |
6bfc18ae | 1102 | aa_put_label(new); |
709bba29 | 1103 | aa_put_label(l); |
6bfc18ae JJ |
1104 | aa_put_label(a); |
1105 | aa_put_label(b); | |
1106 | } | |
1107 | ||
1108 | return label; | |
1109 | } | |
1110 | ||
1111 | /* requires sort and merge done first */ | |
1112 | struct aa_label *aa_label_vec_merge(struct aa_profile **vec, int len, | |
1113 | gfp_t gfp) | |
1114 | { | |
1115 | struct aa_label *label = NULL; | |
1116 | struct aa_labelset *ls; | |
1117 | unsigned long flags; | |
1118 | struct aa_label *new; | |
1119 | int i; | |
1120 | ||
1121 | AA_BUG(!vec); | |
1122 | ||
1123 | if (len == 1) | |
1124 | return aa_get_label(&vec[0]->label); | |
1125 | ||
1126 | ls = labels_set(&vec[len - 1]->label); | |
1127 | ||
1128 | /* TODO: enable when read side is lockless | |
1129 | * check if label exists before taking locks | |
1130 | */ | |
f126fd25 | 1131 | new = aa_label_alloc(len, gfp); |
6bfc18ae JJ |
1132 | if (!new) |
1133 | return NULL; | |
1134 | ||
8812fb2d | 1135 | write_lock_irqsave(&ls->lock, flags); |
6bfc18ae JJ |
1136 | for (i = 0; i < len; i++) { |
1137 | new->ent[i] = aa_get_profile(vec[i]); | |
709bba29 | 1138 | label = __aa_label_insert(ls, new); |
e23c92ae JJ |
1139 | if (label != new) { |
1140 | aa_get_label(label); | |
1141 | /* not fully constructed don't put */ | |
1142 | aa_label_free(new); | |
1143 | } | |
6bfc18ae JJ |
1144 | } |
1145 | write_unlock_irqrestore(&ls->lock, flags); | |
1146 | ||
1147 | return label; | |
1148 | } | |
1149 | ||
1150 | /** | |
1151 | * aa_update_label_name - update a label to have a stored name | |
1152 | * @ns: ns being viewed from (NOT NULL) | |
1153 | * @label: label to update (NOT NULL) | |
1154 | * @gfp: type of memory allocation | |
1155 | * | |
1156 | * Requires: labels_set(label) not locked in caller | |
1157 | * | |
1158 | * note: only updates the label name if it does not have a name already | |
1159 | * and if it is in the labelset | |
1160 | */ | |
1161 | bool aa_update_label_name(struct aa_namespace *ns, struct aa_label *label, | |
1162 | gfp_t gfp) | |
1163 | { | |
1164 | struct aa_labelset *ls; | |
1165 | unsigned long flags; | |
1166 | char __counted *name; | |
1167 | bool res = false; | |
1168 | ||
1169 | AA_BUG(!ns); | |
1170 | AA_BUG(!label); | |
1171 | ||
1172 | if (label->hname || labels_ns(label) != ns) | |
1173 | return res; | |
1174 | ||
1175 | if (aa_label_acntsprint(&name, ns, label, false, gfp) == -1) | |
1176 | return res; | |
1177 | ||
1178 | ls = labels_set(label); | |
1179 | write_lock_irqsave(&ls->lock, flags); | |
1180 | if (!label->hname && label->flags & FLAG_IN_TREE) { | |
1181 | label->hname = name; | |
1182 | res = true; | |
1183 | } else | |
1184 | aa_put_str(name); | |
1185 | write_unlock_irqrestore(&ls->lock, flags); | |
1186 | ||
1187 | return res; | |
1188 | } | |
1189 | ||
1190 | /* cached label name is present and visible | |
1191 | * @label->hname only exists if label is namespace hierachical */ | |
1192 | static inline bool label_name_visible(struct aa_namespace *ns, | |
1193 | struct aa_label *label) | |
1194 | { | |
1195 | if (label->hname && labels_ns(label) == ns) | |
1196 | return true; | |
1197 | ||
1198 | return false; | |
1199 | } | |
1200 | ||
1201 | /* helper macro for snprint routines */ | |
1202 | #define update_for_len(total, len, size, str) \ | |
1203 | do { \ | |
1204 | AA_BUG(len < 0); \ | |
1205 | total += len; \ | |
1206 | len = min(len, size); \ | |
1207 | size -= len; \ | |
1208 | str += len; \ | |
1209 | } while (0) | |
1210 | ||
1211 | /** | |
1212 | * aa_modename_snprint - print the mode name of a profile or label to a buffer | |
1213 | * @str: buffer to write to (MAY BE NULL if @size == 0) | |
1214 | * @size: size of buffer | |
d0f3986b | 1215 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1216 | * @label: label to print the mode of (NOT NULL) |
1217 | * | |
1218 | * Returns: size of name written or would be written if larger than | |
1219 | * available buffer | |
1220 | * | |
1221 | * Note: will print every mode name visible (mode1)(mode2)(mode3) | |
1222 | * this is likely not what is desired for most interfaces | |
1223 | * use aa_mode_snprint to get the standard mode format | |
1224 | */ | |
1225 | static int aa_modename_snprint(char *str, size_t size, struct aa_namespace *ns, | |
1226 | struct aa_label *label) | |
1227 | { | |
1228 | struct aa_profile *profile; | |
1229 | struct label_it i; | |
1230 | int total = 0; | |
1231 | size_t len; | |
1232 | ||
1233 | label_for_each(i, label, profile) { | |
1234 | const char *modestr; | |
1235 | if (!aa_ns_visible(ns, profile->ns)) | |
1236 | continue; | |
1237 | /* no mode for 'unconfined' */ | |
1238 | if (profile_unconfined(profile) && | |
1239 | profile == profile->ns->unconfined) | |
1240 | break; | |
1241 | modestr = aa_profile_mode_names[profile->mode]; | |
1242 | len = snprintf(str, size, "(%s)", modestr); | |
1243 | update_for_len(total, len, size, str); | |
1244 | } | |
1245 | ||
1246 | return total; | |
1247 | } | |
1248 | ||
1249 | /** | |
1250 | * aa_modechr_snprint - print the mode chr of a profile or labels to a buffer | |
1251 | * @str: buffer to write to (MAY BE NULL if @size == 0) | |
1252 | * @size: size of buffer | |
d0f3986b | 1253 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1254 | * @label: label to print the mode chr of (NOT NULL) |
1255 | * | |
1256 | * Returns: size of mode string written or would be written if larger than | |
1257 | * available buffer | |
1258 | * | |
1259 | * Note: will print the chr of every visible profile (123) | |
1260 | * this is likely not what is desired for most interfaces | |
1261 | * use aa_mode_snprint to get the standard mode format | |
1262 | */ | |
1263 | static int aa_modechr_snprint(char *str, size_t size, struct aa_namespace *ns, | |
1264 | struct aa_label *label) | |
1265 | { | |
1266 | struct aa_profile *profile; | |
1267 | struct label_it i; | |
1268 | int total = 0; | |
1269 | size_t len; | |
1270 | ||
1271 | len = snprintf(str, size, "("); | |
1272 | update_for_len(total, len, size, str); | |
1273 | label_for_each(i, label, profile) { | |
1274 | const char *modestr; | |
1275 | if (!aa_ns_visible(ns, profile->ns)) | |
1276 | continue; | |
1277 | modestr = aa_profile_mode_names[profile->mode]; | |
1278 | /* just the first char of the modestr */ | |
1279 | len = snprintf(str, size, "%c", *modestr); | |
1280 | update_for_len(total, len, size, str); | |
1281 | } | |
1282 | len = snprintf(str, size, ")"); | |
1283 | update_for_len(total, len, size, str); | |
1284 | ||
1285 | return total; | |
1286 | } | |
1287 | ||
1288 | /** | |
1289 | * aa_mode_snprint - print the mode of a profile or label to a buffer | |
1290 | * @str: buffer to write to (MAY BE NULL if @size == 0) | |
1291 | * @size: size of buffer | |
d0f3986b | 1292 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1293 | * @label: label to print the mode of (NOT NULL) |
1294 | * @count: number of label entries to be printed (<= 0 if unknown) | |
1295 | * | |
1296 | * Returns: size of name written or would be written if larger than | |
1297 | * available buffer | |
1298 | * | |
1299 | * Note: dynamically switches between mode name, and mode char format as | |
1300 | * appropriate | |
1301 | * will not print anything if the label is not visible | |
1302 | */ | |
1303 | static int aa_mode_snprint(char *str, size_t size, struct aa_namespace *ns, | |
1304 | struct aa_label *label, int count) | |
1305 | { | |
1306 | struct aa_profile *profile; | |
1307 | struct label_it i; | |
1308 | ||
1309 | if (count <= 0) { | |
1310 | count = 0; | |
1311 | label_for_each(i, label, profile) { | |
1312 | if (aa_ns_visible(ns, profile->ns)) | |
1313 | count++; | |
1314 | } | |
1315 | } | |
1316 | ||
1317 | if (count == 0) | |
1318 | return 0; | |
1319 | ||
1320 | if (count == 1) | |
1321 | return aa_modename_snprint(str, size, ns, label); | |
1322 | ||
1323 | return aa_modechr_snprint(str, size, ns, label); | |
1324 | } | |
1325 | ||
1326 | /** | |
1327 | * aa_snprint_profile - print a profile name to a buffer | |
1328 | * @str: buffer to write to. (MAY BE NULL if @size == 0) | |
1329 | * @size: size of buffer | |
d0f3986b | 1330 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1331 | * @profile: profile to view (NOT NULL) |
1332 | * @mode: whether to include the mode string | |
1333 | * | |
1334 | * Returns: size of name written or would be written if larger than | |
1335 | * available buffer | |
1336 | * | |
1337 | * Note: will not print anything if the profile is not visible | |
1338 | */ | |
1339 | int aa_profile_snprint(char *str, size_t size, struct aa_namespace *ns, | |
1340 | struct aa_profile *profile, bool mode) | |
1341 | { | |
d0f3986b | 1342 | const char *ns_name = aa_ns_name(ns, profile->ns); |
6bfc18ae JJ |
1343 | |
1344 | AA_BUG(!str && size != 0); | |
d0f3986b | 1345 | AA_BUG(!ns); |
6bfc18ae JJ |
1346 | AA_BUG(!profile); |
1347 | ||
1348 | if (!ns_name) | |
1349 | return 0; | |
1350 | ||
1351 | if (mode && profile != profile->ns->unconfined) { | |
1352 | const char *modestr = aa_profile_mode_names[profile->mode]; | |
1353 | if (strlen(ns_name)) | |
1354 | return snprintf(str, size, ":%s://%s (%s)", ns_name, | |
1355 | profile->base.hname, modestr); | |
1356 | return snprintf(str, size, "%s (%s)", profile->base.hname, | |
1357 | modestr); | |
1358 | } | |
1359 | ||
1360 | if (strlen(ns_name)) | |
1361 | return snprintf(str, size, ":%s://%s", ns_name, | |
1362 | profile->base.hname); | |
1363 | return snprintf(str, size, "%s", profile->base.hname); | |
1364 | } | |
1365 | ||
1366 | /** | |
1367 | * aa_label_snprint - print a label name to a string buffer | |
1368 | * @str: buffer to write to. (MAY BE NULL if @size == 0) | |
1369 | * @size: size of buffer | |
d0f3986b | 1370 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1371 | * @label: label to view (NOT NULL) |
1372 | * @mode: whether to include the mode string | |
1373 | * | |
1374 | * Returns: size of name written or would be written if larger than | |
1375 | * available buffer | |
1376 | * | |
1377 | * Note: labels do not have to be strictly hierarchical to the ns as | |
1378 | * objects may be shared across different namespaces and thus | |
1379 | * pickup labeling from each ns. If a particular part of the | |
1380 | * label is not visible it will just be excluded. And if none | |
1381 | * of the label is visible "---" will be used. | |
1382 | */ | |
1383 | int aa_label_snprint(char *str, size_t size, struct aa_namespace *ns, | |
1384 | struct aa_label *label, bool mode) | |
1385 | { | |
1386 | struct aa_profile *profile; | |
1387 | struct label_it i; | |
1388 | int count = 0, total = 0; | |
1389 | size_t len; | |
1390 | ||
1391 | AA_BUG(!str && size != 0); | |
d0f3986b | 1392 | AA_BUG(!ns); |
6bfc18ae JJ |
1393 | AA_BUG(!label); |
1394 | ||
1395 | label_for_each(i, label, profile) { | |
1396 | if (aa_ns_visible(ns, profile->ns)) { | |
1397 | if (count > 0) { | |
1398 | len = snprintf(str, size, "//&"); | |
1399 | update_for_len(total, len, size, str); | |
1400 | } | |
1401 | len = aa_profile_snprint(str, size, ns, profile, false); | |
1402 | update_for_len(total, len, size, str); | |
1403 | count++; | |
1404 | } | |
1405 | } | |
1406 | ||
1407 | if (count == 0) | |
1408 | return snprintf(str, size, aa_hidden_ns_name); | |
1409 | ||
1410 | /* count == 1 && ... is for backwards compat where the mode | |
1411 | * is not displayed for 'unconfined' in the current ns | |
1412 | */ | |
1413 | if (mode && | |
1414 | !(count == 1 && labels_ns(label) == ns && | |
1415 | labels_profile(label) == ns->unconfined)) { | |
1416 | len = snprintf(str, size, " "); | |
1417 | update_for_len(total, len, size, str); | |
1418 | len = aa_mode_snprint(str, size, ns, label, count); | |
1419 | update_for_len(total, len, size, str); | |
1420 | } | |
1421 | ||
1422 | return total; | |
1423 | } | |
1424 | #undef update_for_len | |
1425 | ||
1426 | /** | |
1427 | * aa_label_asprint - allocate a string buffer and print label into it | |
1428 | * @strp: Returns - the allocated buffer with the label name. (NOT NULL) | |
d0f3986b | 1429 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1430 | * @label: label to view (NOT NULL) |
1431 | * @mode: whether to include the mode string | |
1432 | * @gfp: kernel memory allocation type | |
1433 | * | |
1434 | * Returns: size of name written or would be written if larger than | |
1435 | * available buffer | |
1436 | */ | |
1437 | int aa_label_asprint(char **strp, struct aa_namespace *ns, | |
1438 | struct aa_label *label, bool mode, gfp_t gfp) | |
1439 | { | |
1440 | int size; | |
1441 | ||
1442 | AA_BUG(!strp); | |
d0f3986b | 1443 | AA_BUG(!ns); |
6bfc18ae JJ |
1444 | AA_BUG(!label); |
1445 | ||
1446 | size = aa_label_snprint(NULL, 0, ns, label, mode); | |
1447 | if (size < 0) | |
1448 | return size; | |
1449 | ||
1450 | *strp = kmalloc(size + 1, gfp); | |
1451 | if (!*strp) | |
1452 | return -ENOMEM; | |
1453 | return aa_label_snprint(*strp, size + 1, ns, label, mode); | |
1454 | } | |
1455 | ||
1456 | /** | |
1457 | * aa_label_acntsprint - allocate a __counted string buffer and print label | |
1458 | * @strp: buffer to write to. (MAY BE NULL if @size == 0) | |
d0f3986b | 1459 | * @ns: namespace profile is being viewed from (NOT NULL) |
6bfc18ae JJ |
1460 | * @label: label to view (NOT NULL) |
1461 | * @mode: whether to include the mode string | |
1462 | * @gfp: kernel memory allocation type | |
1463 | * | |
1464 | * Returns: size of name written or would be written if larger than | |
1465 | * available buffer | |
1466 | */ | |
1467 | int aa_label_acntsprint(char __counted **strp, struct aa_namespace *ns, | |
1468 | struct aa_label *label, bool mode, gfp_t gfp) | |
1469 | { | |
1470 | int size; | |
1471 | ||
1472 | AA_BUG(!strp); | |
d0f3986b | 1473 | AA_BUG(!ns); |
6bfc18ae JJ |
1474 | AA_BUG(!label); |
1475 | ||
1476 | size = aa_label_snprint(NULL, 0, ns, label, mode); | |
1477 | if (size < 0) | |
1478 | return size; | |
1479 | ||
1480 | *strp = aa_str_alloc(size + 1, gfp); | |
1481 | if (!*strp) | |
1482 | return -ENOMEM; | |
1483 | return aa_label_snprint(*strp, size + 1, ns, label, mode); | |
1484 | } | |
1485 | ||
1486 | ||
1487 | void aa_label_audit(struct audit_buffer *ab, struct aa_namespace *ns, | |
1488 | struct aa_label *label, bool mode, gfp_t gfp) | |
1489 | { | |
1490 | const char *str; | |
1491 | char *name = NULL; | |
1492 | int len; | |
1493 | ||
1494 | AA_BUG(!ab); | |
d0f3986b | 1495 | AA_BUG(!ns); |
6bfc18ae JJ |
1496 | AA_BUG(!label); |
1497 | ||
1498 | if (label_name_visible(ns, label)) { | |
1499 | str = (char *) label->hname; | |
1500 | len = strlen(str); | |
1501 | } else { | |
1502 | labelstats_inc(audit_name_alloc); | |
1503 | len = aa_label_asprint(&name, ns, label, mode, gfp); | |
1504 | if (len == -1) { | |
1505 | labelstats_inc(audit_name_fail); | |
1506 | AA_DEBUG("label print error"); | |
1507 | return; | |
1508 | } | |
1509 | str = name; | |
1510 | } | |
1511 | ||
1512 | if (audit_string_contains_control(str, len)) | |
1513 | audit_log_n_hex(ab, str, len); | |
1514 | else | |
1515 | audit_log_n_string(ab, str, len); | |
1516 | ||
1517 | kfree(name); | |
1518 | } | |
1519 | ||
1520 | void aa_label_seq_print(struct seq_file *f, struct aa_namespace *ns, | |
1521 | struct aa_label *label, bool mode, gfp_t gfp) | |
1522 | { | |
1523 | AA_BUG(!f); | |
d0f3986b | 1524 | AA_BUG(!ns); |
6bfc18ae JJ |
1525 | AA_BUG(!label); |
1526 | ||
1527 | if (!label_name_visible(ns, label)) { | |
1528 | char *str; | |
1529 | int len; | |
1530 | ||
1531 | labelstats_inc(seq_print_name_alloc); | |
1532 | len = aa_label_asprint(&str, ns, label, mode, gfp); | |
1533 | if (len == -1) { | |
1534 | labelstats_inc(seq_print_name_fail); | |
1535 | AA_DEBUG("label print error"); | |
1536 | return; | |
1537 | } | |
1538 | seq_printf(f, "%s", str); | |
1539 | kfree(str); | |
1540 | } else | |
1541 | seq_printf(f, "%s", label->hname); | |
1542 | } | |
1543 | ||
1544 | void aa_label_printk(struct aa_namespace *ns, struct aa_label *label, bool mode, | |
1545 | gfp_t gfp) | |
1546 | { | |
1547 | char *str; | |
1548 | int len; | |
1549 | ||
d0f3986b | 1550 | AA_BUG(!ns); |
6bfc18ae JJ |
1551 | AA_BUG(!label); |
1552 | ||
1553 | if (!label_name_visible(ns, label)) { | |
1554 | labelstats_inc(printk_name_alloc); | |
1555 | len = aa_label_asprint(&str, ns, label, mode, gfp); | |
1556 | if (len == -1) { | |
1557 | labelstats_inc(printk_name_fail); | |
1558 | AA_DEBUG("label print error"); | |
1559 | return; | |
1560 | } | |
1561 | printk("%s", str); | |
1562 | kfree(str); | |
1563 | } else | |
1564 | printk("%s", label->hname); | |
1565 | } | |
1566 | ||
1567 | static int label_count_str_entries(const char *str) | |
1568 | { | |
1569 | const char *split; | |
1570 | int count = 1; | |
1571 | ||
1572 | AA_BUG(!str); | |
1573 | ||
1574 | for (split = strstr(str, "//&"); split; split = strstr(str, "//&")) { | |
1575 | count++; | |
1576 | str = split + 3; | |
1577 | } | |
1578 | ||
1579 | return count; | |
1580 | } | |
1581 | ||
1582 | /** | |
1583 | * aa_label_parse - parse, validate and convert a text string to a label | |
1584 | * @base: base label to use for lookups (NOT NULL) | |
1585 | * @str: null terminated text string (NOT NULL) | |
1586 | * @gfp: allocation type | |
1587 | * @create: true if should create compound labels if they don't exist | |
1588 | * | |
1589 | * Returns: the matching refcounted label if present | |
1590 | * else ERRPTR | |
1591 | */ | |
1592 | struct aa_label *aa_label_parse(struct aa_label *base, char *str, gfp_t gfp, | |
1593 | bool create) | |
1594 | { | |
1595 | DEFINE_PROFILE_VEC(vec, tmp); | |
1596 | struct aa_label *l; | |
1597 | int i, len, error; | |
1598 | char *split; | |
1599 | ||
1600 | AA_BUG(!base); | |
1601 | AA_BUG(!str); | |
1602 | ||
1603 | len = label_count_str_entries(str); | |
1604 | error = aa_setup_profile_vec(vec, tmp, len); | |
1605 | if (error) | |
1606 | return ERR_PTR(error); | |
1607 | ||
1608 | for (split = strstr(str, "//&"), i = 0; split && i < len; i++) { | |
1609 | vec[i] = aa_fqlookupn_profile(base, str, split - str); | |
1610 | if (!vec[i]) | |
1611 | goto fail; | |
1612 | str = split + 3; | |
1613 | split = strstr(str, "//&"); | |
1614 | } | |
1615 | vec[i] = aa_fqlookupn_profile(base, str, strlen(str)); | |
1616 | if (!vec[i]) | |
1617 | goto fail; | |
1618 | if (len == 1) | |
1619 | /* no need to free vec as len < LOCAL_VEC_ENTRIES */ | |
1620 | return &vec[0]->label; | |
1621 | ||
1622 | i = aa_sort_and_merge_profiles(len, vec); | |
1623 | len -= i; | |
1624 | ||
1625 | if (create) | |
1626 | l = aa_label_vec_find_or_create(labels_set(base), vec, len); | |
1627 | else | |
1628 | l = aa_label_vec_find(labels_set(base), vec, len); | |
1629 | if (!l) | |
1630 | l = ERR_PTR(-ENOENT); | |
1631 | ||
1632 | out: | |
1633 | /* use adjusted len from after sort_and_merge, not original */ | |
1634 | aa_cleanup_profile_vec(vec, tmp, len); | |
1635 | return l; | |
1636 | ||
1637 | fail: | |
1638 | l = ERR_PTR(-ENOENT); | |
1639 | goto out; | |
1640 | } | |
1641 | ||
1642 | ||
1643 | /** | |
1644 | * aa_labelset_destroy - remove all labels from the label set | |
1645 | * @ls: label set to cleanup (NOT NULL) | |
1646 | * | |
1647 | * Labels that are removed from the set may still exist beyond the set | |
1648 | * being destroyed depending on their reference counting | |
1649 | */ | |
1650 | void aa_labelset_destroy(struct aa_labelset *ls) | |
1651 | { | |
1652 | struct rb_node *node; | |
1653 | unsigned long flags; | |
1654 | ||
1655 | AA_BUG(!ls); | |
1656 | ||
1657 | write_lock_irqsave(&ls->lock, flags); | |
1658 | for (node = rb_first(&ls->root); node; node = rb_first(&ls->root)) { | |
1659 | struct aa_label *this = rb_entry(node, struct aa_label, node); | |
67194e9d | 1660 | __aa_label_remove(ls, this); |
6bfc18ae JJ |
1661 | } |
1662 | write_unlock_irqrestore(&ls->lock, flags); | |
1663 | } | |
1664 | ||
1665 | /* | |
1666 | * @ls: labelset to init (NOT NULL) | |
1667 | */ | |
1668 | void aa_labelset_init(struct aa_labelset *ls) | |
1669 | { | |
1670 | AA_BUG(!ls); | |
1671 | ||
1672 | rwlock_init(&ls->lock); | |
1673 | ls->root = RB_ROOT; | |
1674 | labelstats_init(&ls); | |
1675 | } | |
1676 | ||
1677 | static struct aa_label *labelset_next_invalid(struct aa_labelset *ls) | |
1678 | { | |
1679 | struct aa_label *label; | |
1680 | struct rb_node *node; | |
1681 | unsigned long flags; | |
1682 | ||
1683 | AA_BUG(!ls); | |
1684 | ||
1685 | read_lock_irqsave(&ls->lock, flags); | |
1686 | ||
1687 | __labelset_for_each(ls, node) { | |
17aa743a JJ |
1688 | struct aa_profile *p; |
1689 | struct label_it i; | |
1690 | ||
6bfc18ae | 1691 | label = rb_entry(node, struct aa_label, node); |
e23c92ae | 1692 | if (label_invalid(label)) |
6bfc18ae JJ |
1693 | goto out; |
1694 | ||
e23c92ae JJ |
1695 | label_for_each(i, label, p) { |
1696 | if (PROFILE_INVALID(p)) | |
1697 | goto out; | |
1698 | } | |
6bfc18ae JJ |
1699 | } |
1700 | label = NULL; | |
1701 | ||
1702 | out: | |
e23c92ae | 1703 | aa_get_label(label); |
6bfc18ae JJ |
1704 | read_unlock_irqrestore(&ls->lock, flags); |
1705 | ||
1706 | return label; | |
1707 | } | |
1708 | ||
1709 | /** | |
1710 | * __label_update - insert updated version of @label into labelset | |
1711 | * @label - the label to update/repace | |
1712 | * | |
1713 | * Returns: new label that is up to date | |
1714 | * else NULL on failure | |
1715 | * | |
1716 | * Requires: @ns lock be held | |
1717 | * | |
1718 | * Note: worst case is the stale @label does not get updated and has | |
1719 | * to be updated at a later time. | |
1720 | */ | |
1721 | static struct aa_label *__label_update(struct aa_label *label) | |
1722 | { | |
1723 | struct aa_label *l, *tmp; | |
1724 | struct aa_labelset *ls; | |
1725 | struct aa_profile *p; | |
1726 | struct label_it i; | |
1727 | unsigned long flags; | |
1728 | int invcount = 0; | |
1729 | ||
1730 | AA_BUG(!label); | |
1731 | AA_BUG(!mutex_is_locked(&labels_ns(label)->lock)); | |
1732 | ||
f126fd25 | 1733 | l = aa_label_alloc(label->size, GFP_KERNEL); |
6bfc18ae JJ |
1734 | if (!l) |
1735 | return NULL; | |
1736 | ||
f126fd25 | 1737 | if (!label->replacedby) { |
8ac21d39 | 1738 | struct aa_replacedby *r = aa_alloc_replacedby(l); |
f126fd25 JJ |
1739 | if (!r) { |
1740 | aa_put_label(l); | |
1741 | return NULL; | |
1742 | } | |
1743 | /* only label update will set replacedby so ns lock is enough */ | |
1744 | label->replacedby = r; | |
1745 | } | |
1746 | ||
6bfc18ae JJ |
1747 | /* while holding the ns_lock will stop profile replacement, removal, |
1748 | * and label updates, label merging and removal can be occuring | |
1749 | */ | |
a4d2e2f9 | 1750 | |
6bfc18ae JJ |
1751 | ls = labels_set(label); |
1752 | write_lock_irqsave(&ls->lock, flags); | |
a4d2e2f9 JJ |
1753 | /* circular ref only broken by replace or remove */ |
1754 | l->replacedby = aa_get_replacedby(label->replacedby); | |
1755 | __aa_update_replacedby(label, l); | |
1756 | ||
6bfc18ae JJ |
1757 | label_for_each(i, label, p) { |
1758 | l->ent[i.i] = aa_get_newest_profile(p); | |
1759 | if (&l->ent[i.i]->label.replacedby != &p->label.replacedby) | |
1760 | invcount++; | |
1761 | } | |
1762 | ||
1763 | /* updated label invalidated by being removed/renamed from labelset */ | |
1764 | if (invcount) { | |
1765 | l->size -= aa_sort_and_merge_profiles(l->size, &l->ent[0]); | |
7e972668 | 1766 | if (labels_set(label) == labels_set(l)) { |
a4fb04fb | 1767 | AA_BUG(__aa_label_remove_and_insert(labels_set(label), label, l) != l); |
7e972668 | 1768 | } else { |
8caa4d52 | 1769 | aa_label_remove(labels_set(label), label); |
7e972668 | 1770 | goto other_ls_insert; |
6bfc18ae | 1771 | } |
7e972668 | 1772 | } else { |
0fe6d20b | 1773 | AA_BUG(labels_ns(label) != labels_ns(l)); |
a4fb04fb | 1774 | AA_BUG(__aa_label_remove_and_insert(labels_set(label), label, l) != l); |
7e972668 | 1775 | } |
6bfc18ae | 1776 | write_unlock_irqrestore(&ls->lock, flags); |
a4d2e2f9 | 1777 | |
7e972668 | 1778 | return l; |
6bfc18ae | 1779 | |
7e972668 JJ |
1780 | other_ls_insert: |
1781 | write_unlock_irqrestore(&ls->lock, flags); | |
1782 | tmp = aa_label_insert(labels_set(l), l); | |
1783 | if (tmp != l) { | |
1784 | aa_put_label(l); | |
1785 | l = tmp; | |
2c5f23c4 | 1786 | } |
7e972668 JJ |
1787 | |
1788 | return l; | |
6bfc18ae JJ |
1789 | } |
1790 | ||
1791 | /** | |
1792 | * __labelset_update - invalidate and update labels in @ns | |
1793 | * @ns: namespace to update and invalidate labels in (NOT NULL) | |
1794 | * | |
1795 | * Requires: @ns lock be held | |
1796 | * | |
1797 | * Walk the labelset ensuring that all labels are up to date and valid | |
1798 | * Any label that is outdated is replaced and by an updated version | |
1799 | * invalidated and removed from the tree. | |
1800 | * | |
1801 | * If failures happen due to memory pressures then stale labels will | |
1802 | * be left in place until the next pass. | |
1803 | */ | |
1804 | static void __labelset_update(struct aa_namespace *ns) | |
1805 | { | |
1806 | struct aa_label *label; | |
1807 | ||
1808 | AA_BUG(!ns); | |
1809 | AA_BUG(!mutex_is_locked(&ns->lock)); | |
1810 | ||
1811 | do { | |
1812 | label = labelset_next_invalid(&ns->labels); | |
1813 | if (label) { | |
1814 | struct aa_label *l; | |
1815 | l = __label_update(label); | |
1816 | aa_put_label(l); | |
1817 | aa_put_label(label); | |
1818 | } | |
1819 | } while (label); | |
1820 | } | |
1821 | ||
1822 | /** | |
1823 | * __aa_labelset_invalidate_all - invalidate labels in @ns and below | |
1824 | * @ns: ns to start invalidation at (NOT NULL) | |
1825 | * | |
1826 | * Requires: @ns lock be held | |
1827 | * | |
1828 | * Invalidates labels based on @p in @ns and any children namespaces. | |
1829 | */ | |
1830 | void __aa_labelset_update_all(struct aa_namespace *ns) | |
1831 | { | |
1832 | struct aa_namespace *child; | |
1833 | ||
1834 | AA_BUG(!ns); | |
1835 | AA_BUG(!mutex_is_locked(&ns->lock)); | |
1836 | ||
1837 | __labelset_update(ns); | |
1838 | ||
1839 | list_for_each_entry(child, &ns->sub_ns, base.list) { | |
1840 | mutex_lock(&child->lock); | |
1841 | __aa_labelset_update_all(child); | |
1842 | mutex_unlock(&child->lock); | |
1843 | } | |
1844 | } |