18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor label definitions 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2017 Canonical Ltd. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/audit.h> 118c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 128c2ecf20Sopenharmony_ci#include <linux/sort.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "include/apparmor.h" 158c2ecf20Sopenharmony_ci#include "include/cred.h" 168c2ecf20Sopenharmony_ci#include "include/label.h" 178c2ecf20Sopenharmony_ci#include "include/policy.h" 188c2ecf20Sopenharmony_ci#include "include/secid.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * the aa_label represents the set of profiles confining an object 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Labels maintain a reference count to the set of pointers they reference 258c2ecf20Sopenharmony_ci * Labels are ref counted by 268c2ecf20Sopenharmony_ci * tasks and object via the security field/security context off the field 278c2ecf20Sopenharmony_ci * code - will take a ref count on a label if it needs the label 288c2ecf20Sopenharmony_ci * beyond what is possible with an rcu_read_lock. 298c2ecf20Sopenharmony_ci * profiles - each profile is a label 308c2ecf20Sopenharmony_ci * secids - a pinned secid will keep a refcount of the label it is 318c2ecf20Sopenharmony_ci * referencing 328c2ecf20Sopenharmony_ci * objects - inode, files, sockets, ... 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Labels are not ref counted by the label set, so they maybe removed and 358c2ecf20Sopenharmony_ci * freed when no longer in use. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define PROXY_POISON 97 408c2ecf20Sopenharmony_ci#define LABEL_POISON 100 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void free_proxy(struct aa_proxy *proxy) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci if (proxy) { 458c2ecf20Sopenharmony_ci /* p->label will not updated any more as p is dead */ 468c2ecf20Sopenharmony_ci aa_put_label(rcu_dereference_protected(proxy->label, true)); 478c2ecf20Sopenharmony_ci memset(proxy, 0, sizeof(*proxy)); 488c2ecf20Sopenharmony_ci RCU_INIT_POINTER(proxy->label, (struct aa_label *)PROXY_POISON); 498c2ecf20Sopenharmony_ci kfree(proxy); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_civoid aa_proxy_kref(struct kref *kref) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct aa_proxy *proxy = container_of(kref, struct aa_proxy, count); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci free_proxy(proxy); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct aa_proxy *new; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci new = kzalloc(sizeof(struct aa_proxy), gfp); 658c2ecf20Sopenharmony_ci if (new) { 668c2ecf20Sopenharmony_ci kref_init(&new->count); 678c2ecf20Sopenharmony_ci rcu_assign_pointer(new->label, aa_get_label(label)); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return new; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* requires profile list write lock held */ 738c2ecf20Sopenharmony_civoid __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct aa_label *tmp; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci AA_BUG(!orig); 788c2ecf20Sopenharmony_ci AA_BUG(!new); 798c2ecf20Sopenharmony_ci lockdep_assert_held_write(&labels_set(orig)->lock); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci tmp = rcu_dereference_protected(orig->proxy->label, 828c2ecf20Sopenharmony_ci &labels_ns(orig)->lock); 838c2ecf20Sopenharmony_ci rcu_assign_pointer(orig->proxy->label, aa_get_label(new)); 848c2ecf20Sopenharmony_ci orig->flags |= FLAG_STALE; 858c2ecf20Sopenharmony_ci aa_put_label(tmp); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void __proxy_share(struct aa_label *old, struct aa_label *new) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct aa_proxy *proxy = new->proxy; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci new->proxy = aa_get_proxy(old->proxy); 938c2ecf20Sopenharmony_ci __aa_proxy_redirect(old, new); 948c2ecf20Sopenharmony_ci aa_put_proxy(proxy); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * ns_cmp - compare ns for label set ordering 1008c2ecf20Sopenharmony_ci * @a: ns to compare (NOT NULL) 1018c2ecf20Sopenharmony_ci * @b: ns to compare (NOT NULL) 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Returns: <0 if a < b 1048c2ecf20Sopenharmony_ci * ==0 if a == b 1058c2ecf20Sopenharmony_ci * >0 if a > b 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistatic int ns_cmp(struct aa_ns *a, struct aa_ns *b) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int res; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci AA_BUG(!a); 1128c2ecf20Sopenharmony_ci AA_BUG(!b); 1138c2ecf20Sopenharmony_ci AA_BUG(!a->base.hname); 1148c2ecf20Sopenharmony_ci AA_BUG(!b->base.hname); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (a == b) 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci res = a->level - b->level; 1208c2ecf20Sopenharmony_ci if (res) 1218c2ecf20Sopenharmony_ci return res; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return strcmp(a->base.hname, b->base.hname); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/** 1278c2ecf20Sopenharmony_ci * profile_cmp - profile comparison for set ordering 1288c2ecf20Sopenharmony_ci * @a: profile to compare (NOT NULL) 1298c2ecf20Sopenharmony_ci * @b: profile to compare (NOT NULL) 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Returns: <0 if a < b 1328c2ecf20Sopenharmony_ci * ==0 if a == b 1338c2ecf20Sopenharmony_ci * >0 if a > b 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic int profile_cmp(struct aa_profile *a, struct aa_profile *b) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int res; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci AA_BUG(!a); 1408c2ecf20Sopenharmony_ci AA_BUG(!b); 1418c2ecf20Sopenharmony_ci AA_BUG(!a->ns); 1428c2ecf20Sopenharmony_ci AA_BUG(!b->ns); 1438c2ecf20Sopenharmony_ci AA_BUG(!a->base.hname); 1448c2ecf20Sopenharmony_ci AA_BUG(!b->base.hname); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (a == b || a->base.hname == b->base.hname) 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci res = ns_cmp(a->ns, b->ns); 1498c2ecf20Sopenharmony_ci if (res) 1508c2ecf20Sopenharmony_ci return res; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return strcmp(a->base.hname, b->base.hname); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/** 1568c2ecf20Sopenharmony_ci * vec_cmp - label comparison for set ordering 1578c2ecf20Sopenharmony_ci * @a: label to compare (NOT NULL) 1588c2ecf20Sopenharmony_ci * @vec: vector of profiles to compare (NOT NULL) 1598c2ecf20Sopenharmony_ci * @n: length of @vec 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Returns: <0 if a < vec 1628c2ecf20Sopenharmony_ci * ==0 if a == vec 1638c2ecf20Sopenharmony_ci * >0 if a > vec 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic int vec_cmp(struct aa_profile **a, int an, struct aa_profile **b, int bn) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int i; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci AA_BUG(!a); 1708c2ecf20Sopenharmony_ci AA_BUG(!*a); 1718c2ecf20Sopenharmony_ci AA_BUG(!b); 1728c2ecf20Sopenharmony_ci AA_BUG(!*b); 1738c2ecf20Sopenharmony_ci AA_BUG(an <= 0); 1748c2ecf20Sopenharmony_ci AA_BUG(bn <= 0); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci for (i = 0; i < an && i < bn; i++) { 1778c2ecf20Sopenharmony_ci int res = profile_cmp(a[i], b[i]); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (res != 0) 1808c2ecf20Sopenharmony_ci return res; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return an - bn; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic bool vec_is_stale(struct aa_profile **vec, int n) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci int i; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci AA_BUG(!vec); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 1938c2ecf20Sopenharmony_ci if (profile_is_stale(vec[i])) 1948c2ecf20Sopenharmony_ci return true; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return false; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic bool vec_unconfined(struct aa_profile **vec, int n) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int i; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci AA_BUG(!vec); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 2078c2ecf20Sopenharmony_ci if (!profile_unconfined(vec[i])) 2088c2ecf20Sopenharmony_ci return false; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return true; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int sort_cmp(const void *a, const void *b) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return profile_cmp(*(struct aa_profile **)a, *(struct aa_profile **)b); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * assumes vec is sorted 2218c2ecf20Sopenharmony_ci * Assumes @vec has null terminator at vec[n], and will null terminate 2228c2ecf20Sopenharmony_ci * vec[n - dups] 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic inline int unique(struct aa_profile **vec, int n) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci int i, pos, dups = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci AA_BUG(n < 1); 2298c2ecf20Sopenharmony_ci AA_BUG(!vec); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci pos = 0; 2328c2ecf20Sopenharmony_ci for (i = 1; i < n; i++) { 2338c2ecf20Sopenharmony_ci int res = profile_cmp(vec[pos], vec[i]); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci AA_BUG(res > 0, "vec not sorted"); 2368c2ecf20Sopenharmony_ci if (res == 0) { 2378c2ecf20Sopenharmony_ci /* drop duplicate */ 2388c2ecf20Sopenharmony_ci aa_put_profile(vec[i]); 2398c2ecf20Sopenharmony_ci dups++; 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci pos++; 2438c2ecf20Sopenharmony_ci if (dups) 2448c2ecf20Sopenharmony_ci vec[pos] = vec[i]; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci AA_BUG(dups < 0); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return dups; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/** 2538c2ecf20Sopenharmony_ci * aa_vec_unique - canonical sort and unique a list of profiles 2548c2ecf20Sopenharmony_ci * @n: number of refcounted profiles in the list (@n > 0) 2558c2ecf20Sopenharmony_ci * @vec: list of profiles to sort and merge 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * Returns: the number of duplicates eliminated == references put 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * If @flags & VEC_FLAG_TERMINATE @vec has null terminator at vec[n], and will 2608c2ecf20Sopenharmony_ci * null terminate vec[n - dups] 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ciint aa_vec_unique(struct aa_profile **vec, int n, int flags) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int i, dups = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci AA_BUG(n < 1); 2678c2ecf20Sopenharmony_ci AA_BUG(!vec); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* vecs are usually small and inorder, have a fallback for larger */ 2708c2ecf20Sopenharmony_ci if (n > 8) { 2718c2ecf20Sopenharmony_ci sort(vec, n, sizeof(struct aa_profile *), sort_cmp, NULL); 2728c2ecf20Sopenharmony_ci dups = unique(vec, n); 2738c2ecf20Sopenharmony_ci goto out; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* insertion sort + unique in one */ 2778c2ecf20Sopenharmony_ci for (i = 1; i < n; i++) { 2788c2ecf20Sopenharmony_ci struct aa_profile *tmp = vec[i]; 2798c2ecf20Sopenharmony_ci int pos, j; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci for (pos = i - 1 - dups; pos >= 0; pos--) { 2828c2ecf20Sopenharmony_ci int res = profile_cmp(vec[pos], tmp); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (res == 0) { 2858c2ecf20Sopenharmony_ci /* drop duplicate entry */ 2868c2ecf20Sopenharmony_ci aa_put_profile(tmp); 2878c2ecf20Sopenharmony_ci dups++; 2888c2ecf20Sopenharmony_ci goto continue_outer; 2898c2ecf20Sopenharmony_ci } else if (res < 0) 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci /* pos is at entry < tmp, or index -1. Set to insert pos */ 2938c2ecf20Sopenharmony_ci pos++; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci for (j = i - dups; j > pos; j--) 2968c2ecf20Sopenharmony_ci vec[j] = vec[j - 1]; 2978c2ecf20Sopenharmony_ci vec[pos] = tmp; 2988c2ecf20Sopenharmony_cicontinue_outer: 2998c2ecf20Sopenharmony_ci ; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci AA_BUG(dups < 0); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciout: 3058c2ecf20Sopenharmony_ci if (flags & VEC_FLAG_TERMINATE) 3068c2ecf20Sopenharmony_ci vec[n - dups] = NULL; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return dups; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_civoid aa_label_destroy(struct aa_label *label) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci AA_BUG(!label); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!label_isprofile(label)) { 3178c2ecf20Sopenharmony_ci struct aa_profile *profile; 3188c2ecf20Sopenharmony_ci struct label_it i; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci aa_put_str(label->hname); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci label_for_each(i, label, profile) { 3238c2ecf20Sopenharmony_ci aa_put_profile(profile); 3248c2ecf20Sopenharmony_ci label->vec[i.i] = (struct aa_profile *) 3258c2ecf20Sopenharmony_ci (LABEL_POISON + (long) i.i); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (label->proxy) { 3308c2ecf20Sopenharmony_ci if (rcu_dereference_protected(label->proxy->label, true) == label) 3318c2ecf20Sopenharmony_ci rcu_assign_pointer(label->proxy->label, NULL); 3328c2ecf20Sopenharmony_ci aa_put_proxy(label->proxy); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci aa_free_secid(label->secid); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci label->proxy = (struct aa_proxy *) PROXY_POISON + 1; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_civoid aa_label_free(struct aa_label *label) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci if (!label) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci aa_label_destroy(label); 3458c2ecf20Sopenharmony_ci kfree(label); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void label_free_switch(struct aa_label *label) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci if (label->flags & FLAG_NS_COUNT) 3518c2ecf20Sopenharmony_ci aa_free_ns(labels_ns(label)); 3528c2ecf20Sopenharmony_ci else if (label_isprofile(label)) 3538c2ecf20Sopenharmony_ci aa_free_profile(labels_profile(label)); 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci aa_label_free(label); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void label_free_rcu(struct rcu_head *head) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct aa_label *label = container_of(head, struct aa_label, rcu); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (label->flags & FLAG_IN_TREE) 3638c2ecf20Sopenharmony_ci (void) aa_label_remove(label); 3648c2ecf20Sopenharmony_ci label_free_switch(label); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_civoid aa_label_kref(struct kref *kref) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct aa_label *label = container_of(kref, struct aa_label, count); 3708c2ecf20Sopenharmony_ci struct aa_ns *ns = labels_ns(label); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!ns) { 3738c2ecf20Sopenharmony_ci /* never live, no rcu callback needed, just using the fn */ 3748c2ecf20Sopenharmony_ci label_free_switch(label); 3758c2ecf20Sopenharmony_ci return; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci /* TODO: update labels_profile macro so it works here */ 3788c2ecf20Sopenharmony_ci AA_BUG(label_isprofile(label) && 3798c2ecf20Sopenharmony_ci on_list_rcu(&label->vec[0]->base.profiles)); 3808c2ecf20Sopenharmony_ci AA_BUG(label_isprofile(label) && 3818c2ecf20Sopenharmony_ci on_list_rcu(&label->vec[0]->base.list)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* TODO: if compound label and not stale add to reclaim cache */ 3848c2ecf20Sopenharmony_ci call_rcu(&label->rcu, label_free_rcu); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void label_free_or_put_new(struct aa_label *label, struct aa_label *new) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (label != new) 3908c2ecf20Sopenharmony_ci /* need to free directly to break circular ref with proxy */ 3918c2ecf20Sopenharmony_ci aa_label_free(new); 3928c2ecf20Sopenharmony_ci else 3938c2ecf20Sopenharmony_ci aa_put_label(new); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cibool aa_label_init(struct aa_label *label, int size, gfp_t gfp) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci AA_BUG(!label); 3998c2ecf20Sopenharmony_ci AA_BUG(size < 1); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (aa_alloc_secid(label, gfp) < 0) 4028c2ecf20Sopenharmony_ci return false; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci label->size = size; /* doesn't include null */ 4058c2ecf20Sopenharmony_ci label->vec[size] = NULL; /* null terminate */ 4068c2ecf20Sopenharmony_ci kref_init(&label->count); 4078c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&label->node); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return true; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/** 4138c2ecf20Sopenharmony_ci * aa_label_alloc - allocate a label with a profile vector of @size length 4148c2ecf20Sopenharmony_ci * @size: size of profile vector in the label 4158c2ecf20Sopenharmony_ci * @proxy: proxy to use OR null if to allocate a new one 4168c2ecf20Sopenharmony_ci * @gfp: memory allocation type 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Returns: new label 4198c2ecf20Sopenharmony_ci * else NULL if failed 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_cistruct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct aa_label *new; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci AA_BUG(size < 1); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* + 1 for null terminator entry on vec */ 4288c2ecf20Sopenharmony_ci new = kzalloc(sizeof(*new) + sizeof(struct aa_profile *) * (size + 1), 4298c2ecf20Sopenharmony_ci gfp); 4308c2ecf20Sopenharmony_ci AA_DEBUG("%s (%p)\n", __func__, new); 4318c2ecf20Sopenharmony_ci if (!new) 4328c2ecf20Sopenharmony_ci goto fail; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!aa_label_init(new, size, gfp)) 4358c2ecf20Sopenharmony_ci goto fail; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (!proxy) { 4388c2ecf20Sopenharmony_ci proxy = aa_alloc_proxy(new, gfp); 4398c2ecf20Sopenharmony_ci if (!proxy) 4408c2ecf20Sopenharmony_ci goto fail; 4418c2ecf20Sopenharmony_ci } else 4428c2ecf20Sopenharmony_ci aa_get_proxy(proxy); 4438c2ecf20Sopenharmony_ci /* just set new's proxy, don't redirect proxy here if it was passed in*/ 4448c2ecf20Sopenharmony_ci new->proxy = proxy; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return new; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cifail: 4498c2ecf20Sopenharmony_ci kfree(new); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return NULL; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/** 4568c2ecf20Sopenharmony_ci * label_cmp - label comparison for set ordering 4578c2ecf20Sopenharmony_ci * @a: label to compare (NOT NULL) 4588c2ecf20Sopenharmony_ci * @b: label to compare (NOT NULL) 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * Returns: <0 if a < b 4618c2ecf20Sopenharmony_ci * ==0 if a == b 4628c2ecf20Sopenharmony_ci * >0 if a > b 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic int label_cmp(struct aa_label *a, struct aa_label *b) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci AA_BUG(!b); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (a == b) 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return vec_cmp(a->vec, a->size, b->vec, b->size); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci/* helper fn for label_for_each_confined */ 4758c2ecf20Sopenharmony_ciint aa_label_next_confined(struct aa_label *label, int i) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci AA_BUG(!label); 4788c2ecf20Sopenharmony_ci AA_BUG(i < 0); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci for (; i < label->size; i++) { 4818c2ecf20Sopenharmony_ci if (!profile_unconfined(label->vec[i])) 4828c2ecf20Sopenharmony_ci return i; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return i; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * aa_label_next_not_in_set - return the next profile of @sub not in @set 4908c2ecf20Sopenharmony_ci * @I: label iterator 4918c2ecf20Sopenharmony_ci * @set: label to test against 4928c2ecf20Sopenharmony_ci * @sub: label to if is subset of @set 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * Returns: profile in @sub that is not in @set, with iterator set pos after 4958c2ecf20Sopenharmony_ci * else NULL if @sub is a subset of @set 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistruct aa_profile *__aa_label_next_not_in_set(struct label_it *I, 4988c2ecf20Sopenharmony_ci struct aa_label *set, 4998c2ecf20Sopenharmony_ci struct aa_label *sub) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci AA_BUG(!set); 5028c2ecf20Sopenharmony_ci AA_BUG(!I); 5038c2ecf20Sopenharmony_ci AA_BUG(I->i < 0); 5048c2ecf20Sopenharmony_ci AA_BUG(I->i > set->size); 5058c2ecf20Sopenharmony_ci AA_BUG(!sub); 5068c2ecf20Sopenharmony_ci AA_BUG(I->j < 0); 5078c2ecf20Sopenharmony_ci AA_BUG(I->j > sub->size); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci while (I->j < sub->size && I->i < set->size) { 5108c2ecf20Sopenharmony_ci int res = profile_cmp(sub->vec[I->j], set->vec[I->i]); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (res == 0) { 5138c2ecf20Sopenharmony_ci (I->j)++; 5148c2ecf20Sopenharmony_ci (I->i)++; 5158c2ecf20Sopenharmony_ci } else if (res > 0) 5168c2ecf20Sopenharmony_ci (I->i)++; 5178c2ecf20Sopenharmony_ci else 5188c2ecf20Sopenharmony_ci return sub->vec[(I->j)++]; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (I->j < sub->size) 5228c2ecf20Sopenharmony_ci return sub->vec[(I->j)++]; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return NULL; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/** 5288c2ecf20Sopenharmony_ci * aa_label_is_subset - test if @sub is a subset of @set 5298c2ecf20Sopenharmony_ci * @set: label to test against 5308c2ecf20Sopenharmony_ci * @sub: label to test if is subset of @set 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * Returns: true if @sub is subset of @set 5338c2ecf20Sopenharmony_ci * else false 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cibool aa_label_is_subset(struct aa_label *set, struct aa_label *sub) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct label_it i = { }; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci AA_BUG(!set); 5408c2ecf20Sopenharmony_ci AA_BUG(!sub); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (sub == set) 5438c2ecf20Sopenharmony_ci return true; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return __aa_label_next_not_in_set(&i, set, sub) == NULL; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/** 5498c2ecf20Sopenharmony_ci * aa_label_is_unconfined_subset - test if @sub is a subset of @set 5508c2ecf20Sopenharmony_ci * @set: label to test against 5518c2ecf20Sopenharmony_ci * @sub: label to test if is subset of @set 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * This checks for subset but taking into account unconfined. IF 5548c2ecf20Sopenharmony_ci * @sub contains an unconfined profile that does not have a matching 5558c2ecf20Sopenharmony_ci * unconfined in @set then this will not cause the test to fail. 5568c2ecf20Sopenharmony_ci * Conversely we don't care about an unconfined in @set that is not in 5578c2ecf20Sopenharmony_ci * @sub 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Returns: true if @sub is special_subset of @set 5608c2ecf20Sopenharmony_ci * else false 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_cibool aa_label_is_unconfined_subset(struct aa_label *set, struct aa_label *sub) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct label_it i = { }; 5658c2ecf20Sopenharmony_ci struct aa_profile *p; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci AA_BUG(!set); 5688c2ecf20Sopenharmony_ci AA_BUG(!sub); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (sub == set) 5718c2ecf20Sopenharmony_ci return true; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci do { 5748c2ecf20Sopenharmony_ci p = __aa_label_next_not_in_set(&i, set, sub); 5758c2ecf20Sopenharmony_ci if (p && !profile_unconfined(p)) 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci } while (p); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return p == NULL; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/** 5848c2ecf20Sopenharmony_ci * __label_remove - remove @label from the label set 5858c2ecf20Sopenharmony_ci * @l: label to remove 5868c2ecf20Sopenharmony_ci * @new: label to redirect to 5878c2ecf20Sopenharmony_ci * 5888c2ecf20Sopenharmony_ci * Requires: labels_set(@label)->lock write_lock 5898c2ecf20Sopenharmony_ci * Returns: true if the label was in the tree and removed 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_cistatic bool __label_remove(struct aa_label *label, struct aa_label *new) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct aa_labelset *ls = labels_set(label); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci AA_BUG(!ls); 5968c2ecf20Sopenharmony_ci AA_BUG(!label); 5978c2ecf20Sopenharmony_ci lockdep_assert_held_write(&ls->lock); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (new) 6008c2ecf20Sopenharmony_ci __aa_proxy_redirect(label, new); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (!label_is_stale(label)) 6038c2ecf20Sopenharmony_ci __label_make_stale(label); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (label->flags & FLAG_IN_TREE) { 6068c2ecf20Sopenharmony_ci rb_erase(&label->node, &ls->root); 6078c2ecf20Sopenharmony_ci label->flags &= ~FLAG_IN_TREE; 6088c2ecf20Sopenharmony_ci return true; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return false; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/** 6158c2ecf20Sopenharmony_ci * __label_replace - replace @old with @new in label set 6168c2ecf20Sopenharmony_ci * @old: label to remove from label set 6178c2ecf20Sopenharmony_ci * @new: label to replace @old with 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * Requires: labels_set(@old)->lock write_lock 6208c2ecf20Sopenharmony_ci * valid ref count be held on @new 6218c2ecf20Sopenharmony_ci * Returns: true if @old was in set and replaced by @new 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * Note: current implementation requires label set be order in such a way 6248c2ecf20Sopenharmony_ci * that @new directly replaces @old position in the set (ie. 6258c2ecf20Sopenharmony_ci * using pointer comparison of the label address would not work) 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_cistatic bool __label_replace(struct aa_label *old, struct aa_label *new) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct aa_labelset *ls = labels_set(old); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci AA_BUG(!ls); 6328c2ecf20Sopenharmony_ci AA_BUG(!old); 6338c2ecf20Sopenharmony_ci AA_BUG(!new); 6348c2ecf20Sopenharmony_ci lockdep_assert_held_write(&ls->lock); 6358c2ecf20Sopenharmony_ci AA_BUG(new->flags & FLAG_IN_TREE); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (!label_is_stale(old)) 6388c2ecf20Sopenharmony_ci __label_make_stale(old); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (old->flags & FLAG_IN_TREE) { 6418c2ecf20Sopenharmony_ci rb_replace_node(&old->node, &new->node, &ls->root); 6428c2ecf20Sopenharmony_ci old->flags &= ~FLAG_IN_TREE; 6438c2ecf20Sopenharmony_ci new->flags |= FLAG_IN_TREE; 6448c2ecf20Sopenharmony_ci return true; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return false; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci/** 6518c2ecf20Sopenharmony_ci * __label_insert - attempt to insert @l into a label set 6528c2ecf20Sopenharmony_ci * @ls: set of labels to insert @l into (NOT NULL) 6538c2ecf20Sopenharmony_ci * @label: new label to insert (NOT NULL) 6548c2ecf20Sopenharmony_ci * @replace: whether insertion should replace existing entry that is not stale 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * Requires: @ls->lock 6578c2ecf20Sopenharmony_ci * caller to hold a valid ref on l 6588c2ecf20Sopenharmony_ci * if @replace is true l has a preallocated proxy associated 6598c2ecf20Sopenharmony_ci * Returns: @l if successful in inserting @l - with additional refcount 6608c2ecf20Sopenharmony_ci * else ref counted equivalent label that is already in the set, 6618c2ecf20Sopenharmony_ci * the else condition only happens if @replace is false 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_cistatic struct aa_label *__label_insert(struct aa_labelset *ls, 6648c2ecf20Sopenharmony_ci struct aa_label *label, bool replace) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct rb_node **new, *parent = NULL; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci AA_BUG(!ls); 6698c2ecf20Sopenharmony_ci AA_BUG(!label); 6708c2ecf20Sopenharmony_ci AA_BUG(labels_set(label) != ls); 6718c2ecf20Sopenharmony_ci lockdep_assert_held_write(&ls->lock); 6728c2ecf20Sopenharmony_ci AA_BUG(label->flags & FLAG_IN_TREE); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Figure out where to put new node */ 6758c2ecf20Sopenharmony_ci new = &ls->root.rb_node; 6768c2ecf20Sopenharmony_ci while (*new) { 6778c2ecf20Sopenharmony_ci struct aa_label *this = rb_entry(*new, struct aa_label, node); 6788c2ecf20Sopenharmony_ci int result = label_cmp(label, this); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci parent = *new; 6818c2ecf20Sopenharmony_ci if (result == 0) { 6828c2ecf20Sopenharmony_ci /* !__aa_get_label means queued for destruction, 6838c2ecf20Sopenharmony_ci * so replace in place, however the label has 6848c2ecf20Sopenharmony_ci * died before the replacement so do not share 6858c2ecf20Sopenharmony_ci * the proxy 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci if (!replace && !label_is_stale(this)) { 6888c2ecf20Sopenharmony_ci if (__aa_get_label(this)) 6898c2ecf20Sopenharmony_ci return this; 6908c2ecf20Sopenharmony_ci } else 6918c2ecf20Sopenharmony_ci __proxy_share(this, label); 6928c2ecf20Sopenharmony_ci AA_BUG(!__label_replace(this, label)); 6938c2ecf20Sopenharmony_ci return aa_get_label(label); 6948c2ecf20Sopenharmony_ci } else if (result < 0) 6958c2ecf20Sopenharmony_ci new = &((*new)->rb_left); 6968c2ecf20Sopenharmony_ci else /* (result > 0) */ 6978c2ecf20Sopenharmony_ci new = &((*new)->rb_right); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Add new node and rebalance tree. */ 7018c2ecf20Sopenharmony_ci rb_link_node(&label->node, parent, new); 7028c2ecf20Sopenharmony_ci rb_insert_color(&label->node, &ls->root); 7038c2ecf20Sopenharmony_ci label->flags |= FLAG_IN_TREE; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return aa_get_label(label); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci/** 7098c2ecf20Sopenharmony_ci * __vec_find - find label that matches @vec in label set 7108c2ecf20Sopenharmony_ci * @vec: vec of profiles to find matching label for (NOT NULL) 7118c2ecf20Sopenharmony_ci * @n: length of @vec 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * Requires: @vec_labelset(vec) lock held 7148c2ecf20Sopenharmony_ci * caller to hold a valid ref on l 7158c2ecf20Sopenharmony_ci * 7168c2ecf20Sopenharmony_ci * Returns: ref counted @label if matching label is in tree 7178c2ecf20Sopenharmony_ci * ref counted label that is equiv to @l in tree 7188c2ecf20Sopenharmony_ci * else NULL if @vec equiv is not in tree 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_cistatic struct aa_label *__vec_find(struct aa_profile **vec, int n) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct rb_node *node; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci AA_BUG(!vec); 7258c2ecf20Sopenharmony_ci AA_BUG(!*vec); 7268c2ecf20Sopenharmony_ci AA_BUG(n <= 0); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci node = vec_labelset(vec, n)->root.rb_node; 7298c2ecf20Sopenharmony_ci while (node) { 7308c2ecf20Sopenharmony_ci struct aa_label *this = rb_entry(node, struct aa_label, node); 7318c2ecf20Sopenharmony_ci int result = vec_cmp(this->vec, this->size, vec, n); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (result > 0) 7348c2ecf20Sopenharmony_ci node = node->rb_left; 7358c2ecf20Sopenharmony_ci else if (result < 0) 7368c2ecf20Sopenharmony_ci node = node->rb_right; 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci return __aa_get_label(this); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return NULL; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/** 7458c2ecf20Sopenharmony_ci * __label_find - find label @label in label set 7468c2ecf20Sopenharmony_ci * @label: label to find (NOT NULL) 7478c2ecf20Sopenharmony_ci * 7488c2ecf20Sopenharmony_ci * Requires: labels_set(@label)->lock held 7498c2ecf20Sopenharmony_ci * caller to hold a valid ref on l 7508c2ecf20Sopenharmony_ci * 7518c2ecf20Sopenharmony_ci * Returns: ref counted @label if @label is in tree OR 7528c2ecf20Sopenharmony_ci * ref counted label that is equiv to @label in tree 7538c2ecf20Sopenharmony_ci * else NULL if @label or equiv is not in tree 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_cistatic struct aa_label *__label_find(struct aa_label *label) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci AA_BUG(!label); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return __vec_find(label->vec, label->size); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/** 7648c2ecf20Sopenharmony_ci * aa_label_remove - remove a label from the labelset 7658c2ecf20Sopenharmony_ci * @label: label to remove 7668c2ecf20Sopenharmony_ci * 7678c2ecf20Sopenharmony_ci * Returns: true if @label was removed from the tree 7688c2ecf20Sopenharmony_ci * else @label was not in tree so it could not be removed 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_cibool aa_label_remove(struct aa_label *label) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct aa_labelset *ls = labels_set(label); 7738c2ecf20Sopenharmony_ci unsigned long flags; 7748c2ecf20Sopenharmony_ci bool res; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci AA_BUG(!ls); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 7798c2ecf20Sopenharmony_ci res = __label_remove(label, ns_unconfined(labels_ns(label))); 7808c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return res; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/** 7868c2ecf20Sopenharmony_ci * aa_label_replace - replace a label @old with a new version @new 7878c2ecf20Sopenharmony_ci * @old: label to replace 7888c2ecf20Sopenharmony_ci * @new: label replacing @old 7898c2ecf20Sopenharmony_ci * 7908c2ecf20Sopenharmony_ci * Returns: true if @old was in tree and replaced 7918c2ecf20Sopenharmony_ci * else @old was not in tree, and @new was not inserted 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_cibool aa_label_replace(struct aa_label *old, struct aa_label *new) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci unsigned long flags; 7968c2ecf20Sopenharmony_ci bool res; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (name_is_shared(old, new) && labels_ns(old) == labels_ns(new)) { 7998c2ecf20Sopenharmony_ci write_lock_irqsave(&labels_set(old)->lock, flags); 8008c2ecf20Sopenharmony_ci if (old->proxy != new->proxy) 8018c2ecf20Sopenharmony_ci __proxy_share(old, new); 8028c2ecf20Sopenharmony_ci else 8038c2ecf20Sopenharmony_ci __aa_proxy_redirect(old, new); 8048c2ecf20Sopenharmony_ci res = __label_replace(old, new); 8058c2ecf20Sopenharmony_ci write_unlock_irqrestore(&labels_set(old)->lock, flags); 8068c2ecf20Sopenharmony_ci } else { 8078c2ecf20Sopenharmony_ci struct aa_label *l; 8088c2ecf20Sopenharmony_ci struct aa_labelset *ls = labels_set(old); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 8118c2ecf20Sopenharmony_ci res = __label_remove(old, new); 8128c2ecf20Sopenharmony_ci if (labels_ns(old) != labels_ns(new)) { 8138c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 8148c2ecf20Sopenharmony_ci ls = labels_set(new); 8158c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci l = __label_insert(ls, new, true); 8188c2ecf20Sopenharmony_ci res = (l == new); 8198c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 8208c2ecf20Sopenharmony_ci aa_put_label(l); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return res; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/** 8278c2ecf20Sopenharmony_ci * vec_find - find label @l in label set 8288c2ecf20Sopenharmony_ci * @vec: array of profiles to find equiv label for (NOT NULL) 8298c2ecf20Sopenharmony_ci * @n: length of @vec 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * Returns: refcounted label if @vec equiv is in tree 8328c2ecf20Sopenharmony_ci * else NULL if @vec equiv is not in tree 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_cistatic struct aa_label *vec_find(struct aa_profile **vec, int n) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct aa_labelset *ls; 8378c2ecf20Sopenharmony_ci struct aa_label *label; 8388c2ecf20Sopenharmony_ci unsigned long flags; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci AA_BUG(!vec); 8418c2ecf20Sopenharmony_ci AA_BUG(!*vec); 8428c2ecf20Sopenharmony_ci AA_BUG(n <= 0); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ls = vec_labelset(vec, n); 8458c2ecf20Sopenharmony_ci read_lock_irqsave(&ls->lock, flags); 8468c2ecf20Sopenharmony_ci label = __vec_find(vec, n); 8478c2ecf20Sopenharmony_ci read_unlock_irqrestore(&ls->lock, flags); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci return label; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/* requires sort and merge done first */ 8538c2ecf20Sopenharmony_cistatic struct aa_label *vec_create_and_insert_label(struct aa_profile **vec, 8548c2ecf20Sopenharmony_ci int len, gfp_t gfp) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct aa_label *label = NULL; 8578c2ecf20Sopenharmony_ci struct aa_labelset *ls; 8588c2ecf20Sopenharmony_ci unsigned long flags; 8598c2ecf20Sopenharmony_ci struct aa_label *new; 8608c2ecf20Sopenharmony_ci int i; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci AA_BUG(!vec); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (len == 1) 8658c2ecf20Sopenharmony_ci return aa_get_label(&vec[0]->label); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci ls = labels_set(&vec[len - 1]->label); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* TODO: enable when read side is lockless 8708c2ecf20Sopenharmony_ci * check if label exists before taking locks 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci new = aa_label_alloc(len, NULL, gfp); 8738c2ecf20Sopenharmony_ci if (!new) 8748c2ecf20Sopenharmony_ci return NULL; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 8778c2ecf20Sopenharmony_ci new->vec[i] = aa_get_profile(vec[i]); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 8808c2ecf20Sopenharmony_ci label = __label_insert(ls, new, false); 8818c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 8828c2ecf20Sopenharmony_ci label_free_or_put_new(label, new); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return label; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistruct aa_label *aa_vec_find_or_create_label(struct aa_profile **vec, int len, 8888c2ecf20Sopenharmony_ci gfp_t gfp) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct aa_label *label = vec_find(vec, len); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (label) 8938c2ecf20Sopenharmony_ci return label; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return vec_create_and_insert_label(vec, len, gfp); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/** 8998c2ecf20Sopenharmony_ci * aa_label_find - find label @label in label set 9008c2ecf20Sopenharmony_ci * @label: label to find (NOT NULL) 9018c2ecf20Sopenharmony_ci * 9028c2ecf20Sopenharmony_ci * Requires: caller to hold a valid ref on l 9038c2ecf20Sopenharmony_ci * 9048c2ecf20Sopenharmony_ci * Returns: refcounted @label if @label is in tree 9058c2ecf20Sopenharmony_ci * refcounted label that is equiv to @label in tree 9068c2ecf20Sopenharmony_ci * else NULL if @label or equiv is not in tree 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_cistruct aa_label *aa_label_find(struct aa_label *label) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci AA_BUG(!label); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return vec_find(label->vec, label->size); 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci/** 9178c2ecf20Sopenharmony_ci * aa_label_insert - insert label @label into @ls or return existing label 9188c2ecf20Sopenharmony_ci * @ls - labelset to insert @label into 9198c2ecf20Sopenharmony_ci * @label - label to insert 9208c2ecf20Sopenharmony_ci * 9218c2ecf20Sopenharmony_ci * Requires: caller to hold a valid ref on @label 9228c2ecf20Sopenharmony_ci * 9238c2ecf20Sopenharmony_ci * Returns: ref counted @label if successful in inserting @label 9248c2ecf20Sopenharmony_ci * else ref counted equivalent label that is already in the set 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_cistruct aa_label *aa_label_insert(struct aa_labelset *ls, struct aa_label *label) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct aa_label *l; 9298c2ecf20Sopenharmony_ci unsigned long flags; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci AA_BUG(!ls); 9328c2ecf20Sopenharmony_ci AA_BUG(!label); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* check if label exists before taking lock */ 9358c2ecf20Sopenharmony_ci if (!label_is_stale(label)) { 9368c2ecf20Sopenharmony_ci read_lock_irqsave(&ls->lock, flags); 9378c2ecf20Sopenharmony_ci l = __label_find(label); 9388c2ecf20Sopenharmony_ci read_unlock_irqrestore(&ls->lock, flags); 9398c2ecf20Sopenharmony_ci if (l) 9408c2ecf20Sopenharmony_ci return l; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 9448c2ecf20Sopenharmony_ci l = __label_insert(ls, label, false); 9458c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return l; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci/** 9528c2ecf20Sopenharmony_ci * aa_label_next_in_merge - find the next profile when merging @a and @b 9538c2ecf20Sopenharmony_ci * @I: label iterator 9548c2ecf20Sopenharmony_ci * @a: label to merge 9558c2ecf20Sopenharmony_ci * @b: label to merge 9568c2ecf20Sopenharmony_ci * 9578c2ecf20Sopenharmony_ci * Returns: next profile 9588c2ecf20Sopenharmony_ci * else null if no more profiles 9598c2ecf20Sopenharmony_ci */ 9608c2ecf20Sopenharmony_cistruct aa_profile *aa_label_next_in_merge(struct label_it *I, 9618c2ecf20Sopenharmony_ci struct aa_label *a, 9628c2ecf20Sopenharmony_ci struct aa_label *b) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci AA_BUG(!a); 9658c2ecf20Sopenharmony_ci AA_BUG(!b); 9668c2ecf20Sopenharmony_ci AA_BUG(!I); 9678c2ecf20Sopenharmony_ci AA_BUG(I->i < 0); 9688c2ecf20Sopenharmony_ci AA_BUG(I->i > a->size); 9698c2ecf20Sopenharmony_ci AA_BUG(I->j < 0); 9708c2ecf20Sopenharmony_ci AA_BUG(I->j > b->size); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (I->i < a->size) { 9738c2ecf20Sopenharmony_ci if (I->j < b->size) { 9748c2ecf20Sopenharmony_ci int res = profile_cmp(a->vec[I->i], b->vec[I->j]); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (res > 0) 9778c2ecf20Sopenharmony_ci return b->vec[(I->j)++]; 9788c2ecf20Sopenharmony_ci if (res == 0) 9798c2ecf20Sopenharmony_ci (I->j)++; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return a->vec[(I->i)++]; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (I->j < b->size) 9868c2ecf20Sopenharmony_ci return b->vec[(I->j)++]; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return NULL; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/** 9928c2ecf20Sopenharmony_ci * label_merge_cmp - cmp of @a merging with @b against @z for set ordering 9938c2ecf20Sopenharmony_ci * @a: label to merge then compare (NOT NULL) 9948c2ecf20Sopenharmony_ci * @b: label to merge then compare (NOT NULL) 9958c2ecf20Sopenharmony_ci * @z: label to compare merge against (NOT NULL) 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * Assumes: using the most recent versions of @a, @b, and @z 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * Returns: <0 if a < b 10008c2ecf20Sopenharmony_ci * ==0 if a == b 10018c2ecf20Sopenharmony_ci * >0 if a > b 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_cistatic int label_merge_cmp(struct aa_label *a, struct aa_label *b, 10048c2ecf20Sopenharmony_ci struct aa_label *z) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct aa_profile *p = NULL; 10078c2ecf20Sopenharmony_ci struct label_it i = { }; 10088c2ecf20Sopenharmony_ci int k; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci AA_BUG(!a); 10118c2ecf20Sopenharmony_ci AA_BUG(!b); 10128c2ecf20Sopenharmony_ci AA_BUG(!z); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci for (k = 0; 10158c2ecf20Sopenharmony_ci k < z->size && (p = aa_label_next_in_merge(&i, a, b)); 10168c2ecf20Sopenharmony_ci k++) { 10178c2ecf20Sopenharmony_ci int res = profile_cmp(p, z->vec[k]); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (res != 0) 10208c2ecf20Sopenharmony_ci return res; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (p) 10248c2ecf20Sopenharmony_ci return 1; 10258c2ecf20Sopenharmony_ci else if (k < z->size) 10268c2ecf20Sopenharmony_ci return -1; 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci/** 10318c2ecf20Sopenharmony_ci * label_merge_insert - create a new label by merging @a and @b 10328c2ecf20Sopenharmony_ci * @new: preallocated label to merge into (NOT NULL) 10338c2ecf20Sopenharmony_ci * @a: label to merge with @b (NOT NULL) 10348c2ecf20Sopenharmony_ci * @b: label to merge with @a (NOT NULL) 10358c2ecf20Sopenharmony_ci * 10368c2ecf20Sopenharmony_ci * Requires: preallocated proxy 10378c2ecf20Sopenharmony_ci * 10388c2ecf20Sopenharmony_ci * Returns: ref counted label either @new if merge is unique 10398c2ecf20Sopenharmony_ci * @a if @b is a subset of @a 10408c2ecf20Sopenharmony_ci * @b if @a is a subset of @b 10418c2ecf20Sopenharmony_ci * 10428c2ecf20Sopenharmony_ci * NOTE: will not use @new if the merge results in @new == @a or @b 10438c2ecf20Sopenharmony_ci * 10448c2ecf20Sopenharmony_ci * Must be used within labelset write lock to avoid racing with 10458c2ecf20Sopenharmony_ci * setting labels stale. 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_cistatic struct aa_label *label_merge_insert(struct aa_label *new, 10488c2ecf20Sopenharmony_ci struct aa_label *a, 10498c2ecf20Sopenharmony_ci struct aa_label *b) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci struct aa_label *label; 10528c2ecf20Sopenharmony_ci struct aa_labelset *ls; 10538c2ecf20Sopenharmony_ci struct aa_profile *next; 10548c2ecf20Sopenharmony_ci struct label_it i; 10558c2ecf20Sopenharmony_ci unsigned long flags; 10568c2ecf20Sopenharmony_ci int k = 0, invcount = 0; 10578c2ecf20Sopenharmony_ci bool stale = false; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci AA_BUG(!a); 10608c2ecf20Sopenharmony_ci AA_BUG(a->size < 0); 10618c2ecf20Sopenharmony_ci AA_BUG(!b); 10628c2ecf20Sopenharmony_ci AA_BUG(b->size < 0); 10638c2ecf20Sopenharmony_ci AA_BUG(!new); 10648c2ecf20Sopenharmony_ci AA_BUG(new->size < a->size + b->size); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci label_for_each_in_merge(i, a, b, next) { 10678c2ecf20Sopenharmony_ci AA_BUG(!next); 10688c2ecf20Sopenharmony_ci if (profile_is_stale(next)) { 10698c2ecf20Sopenharmony_ci new->vec[k] = aa_get_newest_profile(next); 10708c2ecf20Sopenharmony_ci AA_BUG(!new->vec[k]->label.proxy); 10718c2ecf20Sopenharmony_ci AA_BUG(!new->vec[k]->label.proxy->label); 10728c2ecf20Sopenharmony_ci if (next->label.proxy != new->vec[k]->label.proxy) 10738c2ecf20Sopenharmony_ci invcount++; 10748c2ecf20Sopenharmony_ci k++; 10758c2ecf20Sopenharmony_ci stale = true; 10768c2ecf20Sopenharmony_ci } else 10778c2ecf20Sopenharmony_ci new->vec[k++] = aa_get_profile(next); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci /* set to actual size which is <= allocated len */ 10808c2ecf20Sopenharmony_ci new->size = k; 10818c2ecf20Sopenharmony_ci new->vec[k] = NULL; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (invcount) { 10848c2ecf20Sopenharmony_ci new->size -= aa_vec_unique(&new->vec[0], new->size, 10858c2ecf20Sopenharmony_ci VEC_FLAG_TERMINATE); 10868c2ecf20Sopenharmony_ci /* TODO: deal with reference labels */ 10878c2ecf20Sopenharmony_ci if (new->size == 1) { 10888c2ecf20Sopenharmony_ci label = aa_get_label(&new->vec[0]->label); 10898c2ecf20Sopenharmony_ci return label; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci } else if (!stale) { 10928c2ecf20Sopenharmony_ci /* 10938c2ecf20Sopenharmony_ci * merge could be same as a || b, note: it is not possible 10948c2ecf20Sopenharmony_ci * for new->size == a->size == b->size unless a == b 10958c2ecf20Sopenharmony_ci */ 10968c2ecf20Sopenharmony_ci if (k == a->size) 10978c2ecf20Sopenharmony_ci return aa_get_label(a); 10988c2ecf20Sopenharmony_ci else if (k == b->size) 10998c2ecf20Sopenharmony_ci return aa_get_label(b); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci if (vec_unconfined(new->vec, new->size)) 11028c2ecf20Sopenharmony_ci new->flags |= FLAG_UNCONFINED; 11038c2ecf20Sopenharmony_ci ls = labels_set(new); 11048c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 11058c2ecf20Sopenharmony_ci label = __label_insert(labels_set(new), new, false); 11068c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return label; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci/** 11128c2ecf20Sopenharmony_ci * labelset_of_merge - find which labelset a merged label should be inserted 11138c2ecf20Sopenharmony_ci * @a: label to merge and insert 11148c2ecf20Sopenharmony_ci * @b: label to merge and insert 11158c2ecf20Sopenharmony_ci * 11168c2ecf20Sopenharmony_ci * Returns: labelset that the merged label should be inserted into 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_cistatic struct aa_labelset *labelset_of_merge(struct aa_label *a, 11198c2ecf20Sopenharmony_ci struct aa_label *b) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci struct aa_ns *nsa = labels_ns(a); 11228c2ecf20Sopenharmony_ci struct aa_ns *nsb = labels_ns(b); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (ns_cmp(nsa, nsb) <= 0) 11258c2ecf20Sopenharmony_ci return &nsa->labels; 11268c2ecf20Sopenharmony_ci return &nsb->labels; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci/** 11308c2ecf20Sopenharmony_ci * __label_find_merge - find label that is equiv to merge of @a and @b 11318c2ecf20Sopenharmony_ci * @ls: set of labels to search (NOT NULL) 11328c2ecf20Sopenharmony_ci * @a: label to merge with @b (NOT NULL) 11338c2ecf20Sopenharmony_ci * @b: label to merge with @a (NOT NULL) 11348c2ecf20Sopenharmony_ci * 11358c2ecf20Sopenharmony_ci * Requires: ls->lock read_lock held 11368c2ecf20Sopenharmony_ci * 11378c2ecf20Sopenharmony_ci * Returns: ref counted label that is equiv to merge of @a and @b 11388c2ecf20Sopenharmony_ci * else NULL if merge of @a and @b is not in set 11398c2ecf20Sopenharmony_ci */ 11408c2ecf20Sopenharmony_cistatic struct aa_label *__label_find_merge(struct aa_labelset *ls, 11418c2ecf20Sopenharmony_ci struct aa_label *a, 11428c2ecf20Sopenharmony_ci struct aa_label *b) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci struct rb_node *node; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci AA_BUG(!ls); 11478c2ecf20Sopenharmony_ci AA_BUG(!a); 11488c2ecf20Sopenharmony_ci AA_BUG(!b); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (a == b) 11518c2ecf20Sopenharmony_ci return __label_find(a); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci node = ls->root.rb_node; 11548c2ecf20Sopenharmony_ci while (node) { 11558c2ecf20Sopenharmony_ci struct aa_label *this = container_of(node, struct aa_label, 11568c2ecf20Sopenharmony_ci node); 11578c2ecf20Sopenharmony_ci int result = label_merge_cmp(a, b, this); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (result < 0) 11608c2ecf20Sopenharmony_ci node = node->rb_left; 11618c2ecf20Sopenharmony_ci else if (result > 0) 11628c2ecf20Sopenharmony_ci node = node->rb_right; 11638c2ecf20Sopenharmony_ci else 11648c2ecf20Sopenharmony_ci return __aa_get_label(this); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return NULL; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/** 11728c2ecf20Sopenharmony_ci * aa_label_find_merge - find label that is equiv to merge of @a and @b 11738c2ecf20Sopenharmony_ci * @a: label to merge with @b (NOT NULL) 11748c2ecf20Sopenharmony_ci * @b: label to merge with @a (NOT NULL) 11758c2ecf20Sopenharmony_ci * 11768c2ecf20Sopenharmony_ci * Requires: labels be fully constructed with a valid ns 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * Returns: ref counted label that is equiv to merge of @a and @b 11798c2ecf20Sopenharmony_ci * else NULL if merge of @a and @b is not in set 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_cistruct aa_label *aa_label_find_merge(struct aa_label *a, struct aa_label *b) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci struct aa_labelset *ls; 11848c2ecf20Sopenharmony_ci struct aa_label *label, *ar = NULL, *br = NULL; 11858c2ecf20Sopenharmony_ci unsigned long flags; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci AA_BUG(!a); 11888c2ecf20Sopenharmony_ci AA_BUG(!b); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (label_is_stale(a)) 11918c2ecf20Sopenharmony_ci a = ar = aa_get_newest_label(a); 11928c2ecf20Sopenharmony_ci if (label_is_stale(b)) 11938c2ecf20Sopenharmony_ci b = br = aa_get_newest_label(b); 11948c2ecf20Sopenharmony_ci ls = labelset_of_merge(a, b); 11958c2ecf20Sopenharmony_ci read_lock_irqsave(&ls->lock, flags); 11968c2ecf20Sopenharmony_ci label = __label_find_merge(ls, a, b); 11978c2ecf20Sopenharmony_ci read_unlock_irqrestore(&ls->lock, flags); 11988c2ecf20Sopenharmony_ci aa_put_label(ar); 11998c2ecf20Sopenharmony_ci aa_put_label(br); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return label; 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/** 12058c2ecf20Sopenharmony_ci * aa_label_merge - attempt to insert new merged label of @a and @b 12068c2ecf20Sopenharmony_ci * @ls: set of labels to insert label into (NOT NULL) 12078c2ecf20Sopenharmony_ci * @a: label to merge with @b (NOT NULL) 12088c2ecf20Sopenharmony_ci * @b: label to merge with @a (NOT NULL) 12098c2ecf20Sopenharmony_ci * @gfp: memory allocation type 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * Requires: caller to hold valid refs on @a and @b 12128c2ecf20Sopenharmony_ci * labels be fully constructed with a valid ns 12138c2ecf20Sopenharmony_ci * 12148c2ecf20Sopenharmony_ci * Returns: ref counted new label if successful in inserting merge of a & b 12158c2ecf20Sopenharmony_ci * else ref counted equivalent label that is already in the set. 12168c2ecf20Sopenharmony_ci * else NULL if could not create label (-ENOMEM) 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_cistruct aa_label *aa_label_merge(struct aa_label *a, struct aa_label *b, 12198c2ecf20Sopenharmony_ci gfp_t gfp) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct aa_label *label = NULL; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci AA_BUG(!a); 12248c2ecf20Sopenharmony_ci AA_BUG(!b); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (a == b) 12278c2ecf20Sopenharmony_ci return aa_get_newest_label(a); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* TODO: enable when read side is lockless 12308c2ecf20Sopenharmony_ci * check if label exists before taking locks 12318c2ecf20Sopenharmony_ci if (!label_is_stale(a) && !label_is_stale(b)) 12328c2ecf20Sopenharmony_ci label = aa_label_find_merge(a, b); 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if (!label) { 12368c2ecf20Sopenharmony_ci struct aa_label *new; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci a = aa_get_newest_label(a); 12398c2ecf20Sopenharmony_ci b = aa_get_newest_label(b); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* could use label_merge_len(a, b), but requires double 12428c2ecf20Sopenharmony_ci * comparison for small savings 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci new = aa_label_alloc(a->size + b->size, NULL, gfp); 12458c2ecf20Sopenharmony_ci if (!new) 12468c2ecf20Sopenharmony_ci goto out; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci label = label_merge_insert(new, a, b); 12498c2ecf20Sopenharmony_ci label_free_or_put_new(label, new); 12508c2ecf20Sopenharmony_ciout: 12518c2ecf20Sopenharmony_ci aa_put_label(a); 12528c2ecf20Sopenharmony_ci aa_put_label(b); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci return label; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic inline bool label_is_visible(struct aa_profile *profile, 12598c2ecf20Sopenharmony_ci struct aa_label *label) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci return aa_ns_visible(profile->ns, labels_ns(label), true); 12628c2ecf20Sopenharmony_ci} 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci/* match a profile and its associated ns component if needed 12658c2ecf20Sopenharmony_ci * Assumes visibility test has already been done. 12668c2ecf20Sopenharmony_ci * If a subns profile is not to be matched should be prescreened with 12678c2ecf20Sopenharmony_ci * visibility test. 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_cistatic inline unsigned int match_component(struct aa_profile *profile, 12708c2ecf20Sopenharmony_ci struct aa_profile *tp, 12718c2ecf20Sopenharmony_ci unsigned int state) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci const char *ns_name; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (profile->ns == tp->ns) 12768c2ecf20Sopenharmony_ci return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* try matching with namespace name and then profile */ 12798c2ecf20Sopenharmony_ci ns_name = aa_ns_name(profile->ns, tp->ns, true); 12808c2ecf20Sopenharmony_ci state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); 12818c2ecf20Sopenharmony_ci state = aa_dfa_match(profile->policy.dfa, state, ns_name); 12828c2ecf20Sopenharmony_ci state = aa_dfa_match_len(profile->policy.dfa, state, ":", 1); 12838c2ecf20Sopenharmony_ci return aa_dfa_match(profile->policy.dfa, state, tp->base.hname); 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci/** 12878c2ecf20Sopenharmony_ci * label_compound_match - find perms for full compound label 12888c2ecf20Sopenharmony_ci * @profile: profile to find perms for 12898c2ecf20Sopenharmony_ci * @label: label to check access permissions for 12908c2ecf20Sopenharmony_ci * @start: state to start match in 12918c2ecf20Sopenharmony_ci * @subns: whether to do permission checks on components in a subns 12928c2ecf20Sopenharmony_ci * @request: permissions to request 12938c2ecf20Sopenharmony_ci * @perms: perms struct to set 12948c2ecf20Sopenharmony_ci * 12958c2ecf20Sopenharmony_ci * Returns: 0 on success else ERROR 12968c2ecf20Sopenharmony_ci * 12978c2ecf20Sopenharmony_ci * For the label A//&B//&C this does the perm match for A//&B//&C 12988c2ecf20Sopenharmony_ci * @perms should be preinitialized with allperms OR a previous permission 12998c2ecf20Sopenharmony_ci * check to be stacked. 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_cistatic int label_compound_match(struct aa_profile *profile, 13028c2ecf20Sopenharmony_ci struct aa_label *label, 13038c2ecf20Sopenharmony_ci unsigned int state, bool subns, u32 request, 13048c2ecf20Sopenharmony_ci struct aa_perms *perms) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci struct aa_profile *tp; 13078c2ecf20Sopenharmony_ci struct label_it i; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* find first subcomponent that is visible */ 13108c2ecf20Sopenharmony_ci label_for_each(i, label, tp) { 13118c2ecf20Sopenharmony_ci if (!aa_ns_visible(profile->ns, tp->ns, subns)) 13128c2ecf20Sopenharmony_ci continue; 13138c2ecf20Sopenharmony_ci state = match_component(profile, tp, state); 13148c2ecf20Sopenharmony_ci if (!state) 13158c2ecf20Sopenharmony_ci goto fail; 13168c2ecf20Sopenharmony_ci goto next; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci /* no component visible */ 13208c2ecf20Sopenharmony_ci *perms = allperms; 13218c2ecf20Sopenharmony_ci return 0; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cinext: 13248c2ecf20Sopenharmony_ci label_for_each_cont(i, label, tp) { 13258c2ecf20Sopenharmony_ci if (!aa_ns_visible(profile->ns, tp->ns, subns)) 13268c2ecf20Sopenharmony_ci continue; 13278c2ecf20Sopenharmony_ci state = aa_dfa_match(profile->policy.dfa, state, "//&"); 13288c2ecf20Sopenharmony_ci state = match_component(profile, tp, state); 13298c2ecf20Sopenharmony_ci if (!state) 13308c2ecf20Sopenharmony_ci goto fail; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci aa_compute_perms(profile->policy.dfa, state, perms); 13338c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, perms); 13348c2ecf20Sopenharmony_ci if ((perms->allow & request) != request) 13358c2ecf20Sopenharmony_ci return -EACCES; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return 0; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cifail: 13408c2ecf20Sopenharmony_ci *perms = nullperms; 13418c2ecf20Sopenharmony_ci return state; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci/** 13458c2ecf20Sopenharmony_ci * label_components_match - find perms for all subcomponents of a label 13468c2ecf20Sopenharmony_ci * @profile: profile to find perms for 13478c2ecf20Sopenharmony_ci * @label: label to check access permissions for 13488c2ecf20Sopenharmony_ci * @start: state to start match in 13498c2ecf20Sopenharmony_ci * @subns: whether to do permission checks on components in a subns 13508c2ecf20Sopenharmony_ci * @request: permissions to request 13518c2ecf20Sopenharmony_ci * @perms: an initialized perms struct to add accumulation to 13528c2ecf20Sopenharmony_ci * 13538c2ecf20Sopenharmony_ci * Returns: 0 on success else ERROR 13548c2ecf20Sopenharmony_ci * 13558c2ecf20Sopenharmony_ci * For the label A//&B//&C this does the perm match for each of A and B and C 13568c2ecf20Sopenharmony_ci * @perms should be preinitialized with allperms OR a previous permission 13578c2ecf20Sopenharmony_ci * check to be stacked. 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_cistatic int label_components_match(struct aa_profile *profile, 13608c2ecf20Sopenharmony_ci struct aa_label *label, unsigned int start, 13618c2ecf20Sopenharmony_ci bool subns, u32 request, 13628c2ecf20Sopenharmony_ci struct aa_perms *perms) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct aa_profile *tp; 13658c2ecf20Sopenharmony_ci struct label_it i; 13668c2ecf20Sopenharmony_ci struct aa_perms tmp; 13678c2ecf20Sopenharmony_ci unsigned int state = 0; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* find first subcomponent to test */ 13708c2ecf20Sopenharmony_ci label_for_each(i, label, tp) { 13718c2ecf20Sopenharmony_ci if (!aa_ns_visible(profile->ns, tp->ns, subns)) 13728c2ecf20Sopenharmony_ci continue; 13738c2ecf20Sopenharmony_ci state = match_component(profile, tp, start); 13748c2ecf20Sopenharmony_ci if (!state) 13758c2ecf20Sopenharmony_ci goto fail; 13768c2ecf20Sopenharmony_ci goto next; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* no subcomponents visible - no change in perms */ 13808c2ecf20Sopenharmony_ci return 0; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cinext: 13838c2ecf20Sopenharmony_ci aa_compute_perms(profile->policy.dfa, state, &tmp); 13848c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, &tmp); 13858c2ecf20Sopenharmony_ci aa_perms_accum(perms, &tmp); 13868c2ecf20Sopenharmony_ci label_for_each_cont(i, label, tp) { 13878c2ecf20Sopenharmony_ci if (!aa_ns_visible(profile->ns, tp->ns, subns)) 13888c2ecf20Sopenharmony_ci continue; 13898c2ecf20Sopenharmony_ci state = match_component(profile, tp, start); 13908c2ecf20Sopenharmony_ci if (!state) 13918c2ecf20Sopenharmony_ci goto fail; 13928c2ecf20Sopenharmony_ci aa_compute_perms(profile->policy.dfa, state, &tmp); 13938c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, &tmp); 13948c2ecf20Sopenharmony_ci aa_perms_accum(perms, &tmp); 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if ((perms->allow & request) != request) 13988c2ecf20Sopenharmony_ci return -EACCES; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci return 0; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cifail: 14038c2ecf20Sopenharmony_ci *perms = nullperms; 14048c2ecf20Sopenharmony_ci return -EACCES; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci/** 14088c2ecf20Sopenharmony_ci * aa_label_match - do a multi-component label match 14098c2ecf20Sopenharmony_ci * @profile: profile to match against (NOT NULL) 14108c2ecf20Sopenharmony_ci * @label: label to match (NOT NULL) 14118c2ecf20Sopenharmony_ci * @state: state to start in 14128c2ecf20Sopenharmony_ci * @subns: whether to match subns components 14138c2ecf20Sopenharmony_ci * @request: permission request 14148c2ecf20Sopenharmony_ci * @perms: Returns computed perms (NOT NULL) 14158c2ecf20Sopenharmony_ci * 14168c2ecf20Sopenharmony_ci * Returns: the state the match finished in, may be the none matching state 14178c2ecf20Sopenharmony_ci */ 14188c2ecf20Sopenharmony_ciint aa_label_match(struct aa_profile *profile, struct aa_label *label, 14198c2ecf20Sopenharmony_ci unsigned int state, bool subns, u32 request, 14208c2ecf20Sopenharmony_ci struct aa_perms *perms) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci int error = label_compound_match(profile, label, state, subns, request, 14238c2ecf20Sopenharmony_ci perms); 14248c2ecf20Sopenharmony_ci if (!error) 14258c2ecf20Sopenharmony_ci return error; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci *perms = allperms; 14288c2ecf20Sopenharmony_ci return label_components_match(profile, label, state, subns, request, 14298c2ecf20Sopenharmony_ci perms); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci/** 14348c2ecf20Sopenharmony_ci * aa_update_label_name - update a label to have a stored name 14358c2ecf20Sopenharmony_ci * @ns: ns being viewed from (NOT NULL) 14368c2ecf20Sopenharmony_ci * @label: label to update (NOT NULL) 14378c2ecf20Sopenharmony_ci * @gfp: type of memory allocation 14388c2ecf20Sopenharmony_ci * 14398c2ecf20Sopenharmony_ci * Requires: labels_set(label) not locked in caller 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * note: only updates the label name if it does not have a name already 14428c2ecf20Sopenharmony_ci * and if it is in the labelset 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_cibool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci struct aa_labelset *ls; 14478c2ecf20Sopenharmony_ci unsigned long flags; 14488c2ecf20Sopenharmony_ci char __counted *name; 14498c2ecf20Sopenharmony_ci bool res = false; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci AA_BUG(!ns); 14528c2ecf20Sopenharmony_ci AA_BUG(!label); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (label->hname || labels_ns(label) != ns) 14558c2ecf20Sopenharmony_ci return res; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0) 14588c2ecf20Sopenharmony_ci return res; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci ls = labels_set(label); 14618c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 14628c2ecf20Sopenharmony_ci if (!label->hname && label->flags & FLAG_IN_TREE) { 14638c2ecf20Sopenharmony_ci label->hname = name; 14648c2ecf20Sopenharmony_ci res = true; 14658c2ecf20Sopenharmony_ci } else 14668c2ecf20Sopenharmony_ci aa_put_str(name); 14678c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci return res; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci/* 14738c2ecf20Sopenharmony_ci * cached label name is present and visible 14748c2ecf20Sopenharmony_ci * @label->hname only exists if label is namespace hierachical 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_cistatic inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label, 14778c2ecf20Sopenharmony_ci int flags) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci if (label->hname && (!ns || labels_ns(label) == ns) && 14808c2ecf20Sopenharmony_ci !(flags & ~FLAG_SHOW_MODE)) 14818c2ecf20Sopenharmony_ci return true; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci return false; 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci/* helper macro for snprint routines */ 14878c2ecf20Sopenharmony_ci#define update_for_len(total, len, size, str) \ 14888c2ecf20Sopenharmony_cido { \ 14898c2ecf20Sopenharmony_ci size_t ulen = len; \ 14908c2ecf20Sopenharmony_ci \ 14918c2ecf20Sopenharmony_ci AA_BUG(len < 0); \ 14928c2ecf20Sopenharmony_ci total += ulen; \ 14938c2ecf20Sopenharmony_ci ulen = min(ulen, size); \ 14948c2ecf20Sopenharmony_ci size -= ulen; \ 14958c2ecf20Sopenharmony_ci str += ulen; \ 14968c2ecf20Sopenharmony_ci} while (0) 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci/** 14998c2ecf20Sopenharmony_ci * aa_profile_snxprint - print a profile name to a buffer 15008c2ecf20Sopenharmony_ci * @str: buffer to write to. (MAY BE NULL if @size == 0) 15018c2ecf20Sopenharmony_ci * @size: size of buffer 15028c2ecf20Sopenharmony_ci * @view: namespace profile is being viewed from 15038c2ecf20Sopenharmony_ci * @profile: profile to view (NOT NULL) 15048c2ecf20Sopenharmony_ci * @flags: whether to include the mode string 15058c2ecf20Sopenharmony_ci * @prev_ns: last ns printed when used in compound print 15068c2ecf20Sopenharmony_ci * 15078c2ecf20Sopenharmony_ci * Returns: size of name written or would be written if larger than 15088c2ecf20Sopenharmony_ci * available buffer 15098c2ecf20Sopenharmony_ci * 15108c2ecf20Sopenharmony_ci * Note: will not print anything if the profile is not visible 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_cistatic int aa_profile_snxprint(char *str, size_t size, struct aa_ns *view, 15138c2ecf20Sopenharmony_ci struct aa_profile *profile, int flags, 15148c2ecf20Sopenharmony_ci struct aa_ns **prev_ns) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci const char *ns_name = NULL; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci AA_BUG(!str && size != 0); 15198c2ecf20Sopenharmony_ci AA_BUG(!profile); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (!view) 15228c2ecf20Sopenharmony_ci view = profiles_ns(profile); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (view != profile->ns && 15258c2ecf20Sopenharmony_ci (!prev_ns || (*prev_ns != profile->ns))) { 15268c2ecf20Sopenharmony_ci if (prev_ns) 15278c2ecf20Sopenharmony_ci *prev_ns = profile->ns; 15288c2ecf20Sopenharmony_ci ns_name = aa_ns_name(view, profile->ns, 15298c2ecf20Sopenharmony_ci flags & FLAG_VIEW_SUBNS); 15308c2ecf20Sopenharmony_ci if (ns_name == aa_hidden_ns_name) { 15318c2ecf20Sopenharmony_ci if (flags & FLAG_HIDDEN_UNCONFINED) 15328c2ecf20Sopenharmony_ci return snprintf(str, size, "%s", "unconfined"); 15338c2ecf20Sopenharmony_ci return snprintf(str, size, "%s", ns_name); 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if ((flags & FLAG_SHOW_MODE) && profile != profile->ns->unconfined) { 15388c2ecf20Sopenharmony_ci const char *modestr = aa_profile_mode_names[profile->mode]; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci if (ns_name) 15418c2ecf20Sopenharmony_ci return snprintf(str, size, ":%s:%s (%s)", ns_name, 15428c2ecf20Sopenharmony_ci profile->base.hname, modestr); 15438c2ecf20Sopenharmony_ci return snprintf(str, size, "%s (%s)", profile->base.hname, 15448c2ecf20Sopenharmony_ci modestr); 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (ns_name) 15488c2ecf20Sopenharmony_ci return snprintf(str, size, ":%s:%s", ns_name, 15498c2ecf20Sopenharmony_ci profile->base.hname); 15508c2ecf20Sopenharmony_ci return snprintf(str, size, "%s", profile->base.hname); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic const char *label_modename(struct aa_ns *ns, struct aa_label *label, 15548c2ecf20Sopenharmony_ci int flags) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci struct aa_profile *profile; 15578c2ecf20Sopenharmony_ci struct label_it i; 15588c2ecf20Sopenharmony_ci int mode = -1, count = 0; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci label_for_each(i, label, profile) { 15618c2ecf20Sopenharmony_ci if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) { 15628c2ecf20Sopenharmony_ci count++; 15638c2ecf20Sopenharmony_ci if (profile == profile->ns->unconfined) 15648c2ecf20Sopenharmony_ci /* special case unconfined so stacks with 15658c2ecf20Sopenharmony_ci * unconfined don't report as mixed. ie. 15668c2ecf20Sopenharmony_ci * profile_foo//&:ns1:unconfined (mixed) 15678c2ecf20Sopenharmony_ci */ 15688c2ecf20Sopenharmony_ci continue; 15698c2ecf20Sopenharmony_ci if (mode == -1) 15708c2ecf20Sopenharmony_ci mode = profile->mode; 15718c2ecf20Sopenharmony_ci else if (mode != profile->mode) 15728c2ecf20Sopenharmony_ci return "mixed"; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (count == 0) 15778c2ecf20Sopenharmony_ci return "-"; 15788c2ecf20Sopenharmony_ci if (mode == -1) 15798c2ecf20Sopenharmony_ci /* everything was unconfined */ 15808c2ecf20Sopenharmony_ci mode = APPARMOR_UNCONFINED; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci return aa_profile_mode_names[mode]; 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci/* if any visible label is not unconfined the display_mode returns true */ 15868c2ecf20Sopenharmony_cistatic inline bool display_mode(struct aa_ns *ns, struct aa_label *label, 15878c2ecf20Sopenharmony_ci int flags) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci if ((flags & FLAG_SHOW_MODE)) { 15908c2ecf20Sopenharmony_ci struct aa_profile *profile; 15918c2ecf20Sopenharmony_ci struct label_it i; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci label_for_each(i, label, profile) { 15948c2ecf20Sopenharmony_ci if (aa_ns_visible(ns, profile->ns, 15958c2ecf20Sopenharmony_ci flags & FLAG_VIEW_SUBNS) && 15968c2ecf20Sopenharmony_ci profile != profile->ns->unconfined) 15978c2ecf20Sopenharmony_ci return true; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci /* only ns->unconfined in set of profiles in ns */ 16008c2ecf20Sopenharmony_ci return false; 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return false; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci/** 16078c2ecf20Sopenharmony_ci * aa_label_snxprint - print a label name to a string buffer 16088c2ecf20Sopenharmony_ci * @str: buffer to write to. (MAY BE NULL if @size == 0) 16098c2ecf20Sopenharmony_ci * @size: size of buffer 16108c2ecf20Sopenharmony_ci * @ns: namespace profile is being viewed from 16118c2ecf20Sopenharmony_ci * @label: label to view (NOT NULL) 16128c2ecf20Sopenharmony_ci * @flags: whether to include the mode string 16138c2ecf20Sopenharmony_ci * 16148c2ecf20Sopenharmony_ci * Returns: size of name written or would be written if larger than 16158c2ecf20Sopenharmony_ci * available buffer 16168c2ecf20Sopenharmony_ci * 16178c2ecf20Sopenharmony_ci * Note: labels do not have to be strictly hierarchical to the ns as 16188c2ecf20Sopenharmony_ci * objects may be shared across different namespaces and thus 16198c2ecf20Sopenharmony_ci * pickup labeling from each ns. If a particular part of the 16208c2ecf20Sopenharmony_ci * label is not visible it will just be excluded. And if none 16218c2ecf20Sopenharmony_ci * of the label is visible "---" will be used. 16228c2ecf20Sopenharmony_ci */ 16238c2ecf20Sopenharmony_ciint aa_label_snxprint(char *str, size_t size, struct aa_ns *ns, 16248c2ecf20Sopenharmony_ci struct aa_label *label, int flags) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci struct aa_profile *profile; 16278c2ecf20Sopenharmony_ci struct aa_ns *prev_ns = NULL; 16288c2ecf20Sopenharmony_ci struct label_it i; 16298c2ecf20Sopenharmony_ci int count = 0, total = 0; 16308c2ecf20Sopenharmony_ci ssize_t len; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci AA_BUG(!str && size != 0); 16338c2ecf20Sopenharmony_ci AA_BUG(!label); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) { 16368c2ecf20Sopenharmony_ci ns = root_ns; 16378c2ecf20Sopenharmony_ci len = snprintf(str, size, "_"); 16388c2ecf20Sopenharmony_ci update_for_len(total, len, size, str); 16398c2ecf20Sopenharmony_ci } else if (!ns) { 16408c2ecf20Sopenharmony_ci ns = labels_ns(label); 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci label_for_each(i, label, profile) { 16448c2ecf20Sopenharmony_ci if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) { 16458c2ecf20Sopenharmony_ci if (count > 0) { 16468c2ecf20Sopenharmony_ci len = snprintf(str, size, "//&"); 16478c2ecf20Sopenharmony_ci update_for_len(total, len, size, str); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci len = aa_profile_snxprint(str, size, ns, profile, 16508c2ecf20Sopenharmony_ci flags & FLAG_VIEW_SUBNS, 16518c2ecf20Sopenharmony_ci &prev_ns); 16528c2ecf20Sopenharmony_ci update_for_len(total, len, size, str); 16538c2ecf20Sopenharmony_ci count++; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (count == 0) { 16588c2ecf20Sopenharmony_ci if (flags & FLAG_HIDDEN_UNCONFINED) 16598c2ecf20Sopenharmony_ci return snprintf(str, size, "%s", "unconfined"); 16608c2ecf20Sopenharmony_ci return snprintf(str, size, "%s", aa_hidden_ns_name); 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* count == 1 && ... is for backwards compat where the mode 16648c2ecf20Sopenharmony_ci * is not displayed for 'unconfined' in the current ns 16658c2ecf20Sopenharmony_ci */ 16668c2ecf20Sopenharmony_ci if (display_mode(ns, label, flags)) { 16678c2ecf20Sopenharmony_ci len = snprintf(str, size, " (%s)", 16688c2ecf20Sopenharmony_ci label_modename(ns, label, flags)); 16698c2ecf20Sopenharmony_ci update_for_len(total, len, size, str); 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci return total; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci#undef update_for_len 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci/** 16778c2ecf20Sopenharmony_ci * aa_label_asxprint - allocate a string buffer and print label into it 16788c2ecf20Sopenharmony_ci * @strp: Returns - the allocated buffer with the label name. (NOT NULL) 16798c2ecf20Sopenharmony_ci * @ns: namespace profile is being viewed from 16808c2ecf20Sopenharmony_ci * @label: label to view (NOT NULL) 16818c2ecf20Sopenharmony_ci * @flags: flags controlling what label info is printed 16828c2ecf20Sopenharmony_ci * @gfp: kernel memory allocation type 16838c2ecf20Sopenharmony_ci * 16848c2ecf20Sopenharmony_ci * Returns: size of name written or would be written if larger than 16858c2ecf20Sopenharmony_ci * available buffer 16868c2ecf20Sopenharmony_ci */ 16878c2ecf20Sopenharmony_ciint aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label, 16888c2ecf20Sopenharmony_ci int flags, gfp_t gfp) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci int size; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci AA_BUG(!strp); 16938c2ecf20Sopenharmony_ci AA_BUG(!label); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci size = aa_label_snxprint(NULL, 0, ns, label, flags); 16968c2ecf20Sopenharmony_ci if (size < 0) 16978c2ecf20Sopenharmony_ci return size; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci *strp = kmalloc(size + 1, gfp); 17008c2ecf20Sopenharmony_ci if (!*strp) 17018c2ecf20Sopenharmony_ci return -ENOMEM; 17028c2ecf20Sopenharmony_ci return aa_label_snxprint(*strp, size + 1, ns, label, flags); 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci/** 17068c2ecf20Sopenharmony_ci * aa_label_acntsxprint - allocate a __counted string buffer and print label 17078c2ecf20Sopenharmony_ci * @strp: buffer to write to. 17088c2ecf20Sopenharmony_ci * @ns: namespace profile is being viewed from 17098c2ecf20Sopenharmony_ci * @label: label to view (NOT NULL) 17108c2ecf20Sopenharmony_ci * @flags: flags controlling what label info is printed 17118c2ecf20Sopenharmony_ci * @gfp: kernel memory allocation type 17128c2ecf20Sopenharmony_ci * 17138c2ecf20Sopenharmony_ci * Returns: size of name written or would be written if larger than 17148c2ecf20Sopenharmony_ci * available buffer 17158c2ecf20Sopenharmony_ci */ 17168c2ecf20Sopenharmony_ciint aa_label_acntsxprint(char __counted **strp, struct aa_ns *ns, 17178c2ecf20Sopenharmony_ci struct aa_label *label, int flags, gfp_t gfp) 17188c2ecf20Sopenharmony_ci{ 17198c2ecf20Sopenharmony_ci int size; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci AA_BUG(!strp); 17228c2ecf20Sopenharmony_ci AA_BUG(!label); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci size = aa_label_snxprint(NULL, 0, ns, label, flags); 17258c2ecf20Sopenharmony_ci if (size < 0) 17268c2ecf20Sopenharmony_ci return size; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci *strp = aa_str_alloc(size + 1, gfp); 17298c2ecf20Sopenharmony_ci if (!*strp) 17308c2ecf20Sopenharmony_ci return -ENOMEM; 17318c2ecf20Sopenharmony_ci return aa_label_snxprint(*strp, size + 1, ns, label, flags); 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_civoid aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns, 17368c2ecf20Sopenharmony_ci struct aa_label *label, int flags, gfp_t gfp) 17378c2ecf20Sopenharmony_ci{ 17388c2ecf20Sopenharmony_ci const char *str; 17398c2ecf20Sopenharmony_ci char *name = NULL; 17408c2ecf20Sopenharmony_ci int len; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci AA_BUG(!ab); 17438c2ecf20Sopenharmony_ci AA_BUG(!label); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (!use_label_hname(ns, label, flags) || 17468c2ecf20Sopenharmony_ci display_mode(ns, label, flags)) { 17478c2ecf20Sopenharmony_ci len = aa_label_asxprint(&name, ns, label, flags, gfp); 17488c2ecf20Sopenharmony_ci if (len < 0) { 17498c2ecf20Sopenharmony_ci AA_DEBUG("label print error"); 17508c2ecf20Sopenharmony_ci return; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci str = name; 17538c2ecf20Sopenharmony_ci } else { 17548c2ecf20Sopenharmony_ci str = (char *) label->hname; 17558c2ecf20Sopenharmony_ci len = strlen(str); 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci if (audit_string_contains_control(str, len)) 17588c2ecf20Sopenharmony_ci audit_log_n_hex(ab, str, len); 17598c2ecf20Sopenharmony_ci else 17608c2ecf20Sopenharmony_ci audit_log_n_string(ab, str, len); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci kfree(name); 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_civoid aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns, 17668c2ecf20Sopenharmony_ci struct aa_label *label, int flags, gfp_t gfp) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci AA_BUG(!f); 17698c2ecf20Sopenharmony_ci AA_BUG(!label); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (!use_label_hname(ns, label, flags)) { 17728c2ecf20Sopenharmony_ci char *str; 17738c2ecf20Sopenharmony_ci int len; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci len = aa_label_asxprint(&str, ns, label, flags, gfp); 17768c2ecf20Sopenharmony_ci if (len < 0) { 17778c2ecf20Sopenharmony_ci AA_DEBUG("label print error"); 17788c2ecf20Sopenharmony_ci return; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci seq_puts(f, str); 17818c2ecf20Sopenharmony_ci kfree(str); 17828c2ecf20Sopenharmony_ci } else if (display_mode(ns, label, flags)) 17838c2ecf20Sopenharmony_ci seq_printf(f, "%s (%s)", label->hname, 17848c2ecf20Sopenharmony_ci label_modename(ns, label, flags)); 17858c2ecf20Sopenharmony_ci else 17868c2ecf20Sopenharmony_ci seq_puts(f, label->hname); 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_civoid aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, 17908c2ecf20Sopenharmony_ci gfp_t gfp) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci AA_BUG(!label); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (!use_label_hname(ns, label, flags)) { 17958c2ecf20Sopenharmony_ci char *str; 17968c2ecf20Sopenharmony_ci int len; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci len = aa_label_asxprint(&str, ns, label, flags, gfp); 17998c2ecf20Sopenharmony_ci if (len < 0) { 18008c2ecf20Sopenharmony_ci AA_DEBUG("label print error"); 18018c2ecf20Sopenharmony_ci return; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci pr_info("%s", str); 18048c2ecf20Sopenharmony_ci kfree(str); 18058c2ecf20Sopenharmony_ci } else if (display_mode(ns, label, flags)) 18068c2ecf20Sopenharmony_ci pr_info("%s (%s)", label->hname, 18078c2ecf20Sopenharmony_ci label_modename(ns, label, flags)); 18088c2ecf20Sopenharmony_ci else 18098c2ecf20Sopenharmony_ci pr_info("%s", label->hname); 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_civoid aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct aa_ns *ns = aa_get_current_ns(); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci aa_label_xaudit(ab, ns, label, FLAG_VIEW_SUBNS, gfp); 18178c2ecf20Sopenharmony_ci aa_put_ns(ns); 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_civoid aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp) 18218c2ecf20Sopenharmony_ci{ 18228c2ecf20Sopenharmony_ci struct aa_ns *ns = aa_get_current_ns(); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci aa_label_seq_xprint(f, ns, label, FLAG_VIEW_SUBNS, gfp); 18258c2ecf20Sopenharmony_ci aa_put_ns(ns); 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_civoid aa_label_printk(struct aa_label *label, gfp_t gfp) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci struct aa_ns *ns = aa_get_current_ns(); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci aa_label_xprintk(ns, label, FLAG_VIEW_SUBNS, gfp); 18338c2ecf20Sopenharmony_ci aa_put_ns(ns); 18348c2ecf20Sopenharmony_ci} 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_cistatic int label_count_strn_entries(const char *str, size_t n) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci const char *end = str + n; 18398c2ecf20Sopenharmony_ci const char *split; 18408c2ecf20Sopenharmony_ci int count = 1; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci AA_BUG(!str); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci for (split = aa_label_strn_split(str, end - str); 18458c2ecf20Sopenharmony_ci split; 18468c2ecf20Sopenharmony_ci split = aa_label_strn_split(str, end - str)) { 18478c2ecf20Sopenharmony_ci count++; 18488c2ecf20Sopenharmony_ci str = split + 3; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci return count; 18528c2ecf20Sopenharmony_ci} 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci/* 18558c2ecf20Sopenharmony_ci * ensure stacks with components like 18568c2ecf20Sopenharmony_ci * :ns:A//&B 18578c2ecf20Sopenharmony_ci * have :ns: applied to both 'A' and 'B' by making the lookup relative 18588c2ecf20Sopenharmony_ci * to the base if the lookup specifies an ns, else making the stacked lookup 18598c2ecf20Sopenharmony_ci * relative to the last embedded ns in the string. 18608c2ecf20Sopenharmony_ci */ 18618c2ecf20Sopenharmony_cistatic struct aa_profile *fqlookupn_profile(struct aa_label *base, 18628c2ecf20Sopenharmony_ci struct aa_label *currentbase, 18638c2ecf20Sopenharmony_ci const char *str, size_t n) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci const char *first = skipn_spaces(str, n); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (first && *first == ':') 18688c2ecf20Sopenharmony_ci return aa_fqlookupn_profile(base, str, n); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci return aa_fqlookupn_profile(currentbase, str, n); 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci/** 18748c2ecf20Sopenharmony_ci * aa_label_strn_parse - parse, validate and convert a text string to a label 18758c2ecf20Sopenharmony_ci * @base: base label to use for lookups (NOT NULL) 18768c2ecf20Sopenharmony_ci * @str: null terminated text string (NOT NULL) 18778c2ecf20Sopenharmony_ci * @n: length of str to parse, will stop at \0 if encountered before n 18788c2ecf20Sopenharmony_ci * @gfp: allocation type 18798c2ecf20Sopenharmony_ci * @create: true if should create compound labels if they don't exist 18808c2ecf20Sopenharmony_ci * @force_stack: true if should stack even if no leading & 18818c2ecf20Sopenharmony_ci * 18828c2ecf20Sopenharmony_ci * Returns: the matching refcounted label if present 18838c2ecf20Sopenharmony_ci * else ERRPTR 18848c2ecf20Sopenharmony_ci */ 18858c2ecf20Sopenharmony_cistruct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, 18868c2ecf20Sopenharmony_ci size_t n, gfp_t gfp, bool create, 18878c2ecf20Sopenharmony_ci bool force_stack) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci DEFINE_VEC(profile, vec); 18908c2ecf20Sopenharmony_ci struct aa_label *label, *currbase = base; 18918c2ecf20Sopenharmony_ci int i, len, stack = 0, error; 18928c2ecf20Sopenharmony_ci const char *end = str + n; 18938c2ecf20Sopenharmony_ci const char *split; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci AA_BUG(!base); 18968c2ecf20Sopenharmony_ci AA_BUG(!str); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci str = skipn_spaces(str, n); 18998c2ecf20Sopenharmony_ci if (str == NULL || (AA_DEBUG_LABEL && *str == '_' && 19008c2ecf20Sopenharmony_ci base != &root_ns->unconfined->label)) 19018c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci len = label_count_strn_entries(str, end - str); 19048c2ecf20Sopenharmony_ci if (*str == '&' || force_stack) { 19058c2ecf20Sopenharmony_ci /* stack on top of base */ 19068c2ecf20Sopenharmony_ci stack = base->size; 19078c2ecf20Sopenharmony_ci len += stack; 19088c2ecf20Sopenharmony_ci if (*str == '&') 19098c2ecf20Sopenharmony_ci str++; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci error = vec_setup(profile, vec, len, gfp); 19138c2ecf20Sopenharmony_ci if (error) 19148c2ecf20Sopenharmony_ci return ERR_PTR(error); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci for (i = 0; i < stack; i++) 19178c2ecf20Sopenharmony_ci vec[i] = aa_get_profile(base->vec[i]); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci for (split = aa_label_strn_split(str, end - str), i = stack; 19208c2ecf20Sopenharmony_ci split && i < len; i++) { 19218c2ecf20Sopenharmony_ci vec[i] = fqlookupn_profile(base, currbase, str, split - str); 19228c2ecf20Sopenharmony_ci if (!vec[i]) 19238c2ecf20Sopenharmony_ci goto fail; 19248c2ecf20Sopenharmony_ci /* 19258c2ecf20Sopenharmony_ci * if component specified a new ns it becomes the new base 19268c2ecf20Sopenharmony_ci * so that subsequent lookups are relative to it 19278c2ecf20Sopenharmony_ci */ 19288c2ecf20Sopenharmony_ci if (vec[i]->ns != labels_ns(currbase)) 19298c2ecf20Sopenharmony_ci currbase = &vec[i]->label; 19308c2ecf20Sopenharmony_ci str = split + 3; 19318c2ecf20Sopenharmony_ci split = aa_label_strn_split(str, end - str); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci /* last element doesn't have a split */ 19348c2ecf20Sopenharmony_ci if (i < len) { 19358c2ecf20Sopenharmony_ci vec[i] = fqlookupn_profile(base, currbase, str, end - str); 19368c2ecf20Sopenharmony_ci if (!vec[i]) 19378c2ecf20Sopenharmony_ci goto fail; 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci if (len == 1) 19408c2ecf20Sopenharmony_ci /* no need to free vec as len < LOCAL_VEC_ENTRIES */ 19418c2ecf20Sopenharmony_ci return &vec[0]->label; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci len -= aa_vec_unique(vec, len, VEC_FLAG_TERMINATE); 19448c2ecf20Sopenharmony_ci /* TODO: deal with reference labels */ 19458c2ecf20Sopenharmony_ci if (len == 1) { 19468c2ecf20Sopenharmony_ci label = aa_get_label(&vec[0]->label); 19478c2ecf20Sopenharmony_ci goto out; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (create) 19518c2ecf20Sopenharmony_ci label = aa_vec_find_or_create_label(vec, len, gfp); 19528c2ecf20Sopenharmony_ci else 19538c2ecf20Sopenharmony_ci label = vec_find(vec, len); 19548c2ecf20Sopenharmony_ci if (!label) 19558c2ecf20Sopenharmony_ci goto fail; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ciout: 19588c2ecf20Sopenharmony_ci /* use adjusted len from after vec_unique, not original */ 19598c2ecf20Sopenharmony_ci vec_cleanup(profile, vec, len); 19608c2ecf20Sopenharmony_ci return label; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cifail: 19638c2ecf20Sopenharmony_ci label = ERR_PTR(-ENOENT); 19648c2ecf20Sopenharmony_ci goto out; 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistruct aa_label *aa_label_parse(struct aa_label *base, const char *str, 19688c2ecf20Sopenharmony_ci gfp_t gfp, bool create, bool force_stack) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci return aa_label_strn_parse(base, str, strlen(str), gfp, create, 19718c2ecf20Sopenharmony_ci force_stack); 19728c2ecf20Sopenharmony_ci} 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci/** 19758c2ecf20Sopenharmony_ci * aa_labelset_destroy - remove all labels from the label set 19768c2ecf20Sopenharmony_ci * @ls: label set to cleanup (NOT NULL) 19778c2ecf20Sopenharmony_ci * 19788c2ecf20Sopenharmony_ci * Labels that are removed from the set may still exist beyond the set 19798c2ecf20Sopenharmony_ci * being destroyed depending on their reference counting 19808c2ecf20Sopenharmony_ci */ 19818c2ecf20Sopenharmony_civoid aa_labelset_destroy(struct aa_labelset *ls) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci struct rb_node *node; 19848c2ecf20Sopenharmony_ci unsigned long flags; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci AA_BUG(!ls); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 19898c2ecf20Sopenharmony_ci for (node = rb_first(&ls->root); node; node = rb_first(&ls->root)) { 19908c2ecf20Sopenharmony_ci struct aa_label *this = rb_entry(node, struct aa_label, node); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (labels_ns(this) != root_ns) 19938c2ecf20Sopenharmony_ci __label_remove(this, 19948c2ecf20Sopenharmony_ci ns_unconfined(labels_ns(this)->parent)); 19958c2ecf20Sopenharmony_ci else 19968c2ecf20Sopenharmony_ci __label_remove(this, NULL); 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci/* 20028c2ecf20Sopenharmony_ci * @ls: labelset to init (NOT NULL) 20038c2ecf20Sopenharmony_ci */ 20048c2ecf20Sopenharmony_civoid aa_labelset_init(struct aa_labelset *ls) 20058c2ecf20Sopenharmony_ci{ 20068c2ecf20Sopenharmony_ci AA_BUG(!ls); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci rwlock_init(&ls->lock); 20098c2ecf20Sopenharmony_ci ls->root = RB_ROOT; 20108c2ecf20Sopenharmony_ci} 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_cistatic struct aa_label *labelset_next_stale(struct aa_labelset *ls) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci struct aa_label *label; 20158c2ecf20Sopenharmony_ci struct rb_node *node; 20168c2ecf20Sopenharmony_ci unsigned long flags; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci AA_BUG(!ls); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci read_lock_irqsave(&ls->lock, flags); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci __labelset_for_each(ls, node) { 20238c2ecf20Sopenharmony_ci label = rb_entry(node, struct aa_label, node); 20248c2ecf20Sopenharmony_ci if ((label_is_stale(label) || 20258c2ecf20Sopenharmony_ci vec_is_stale(label->vec, label->size)) && 20268c2ecf20Sopenharmony_ci __aa_get_label(label)) 20278c2ecf20Sopenharmony_ci goto out; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci label = NULL; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ciout: 20338c2ecf20Sopenharmony_ci read_unlock_irqrestore(&ls->lock, flags); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci return label; 20368c2ecf20Sopenharmony_ci} 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci/** 20398c2ecf20Sopenharmony_ci * __label_update - insert updated version of @label into labelset 20408c2ecf20Sopenharmony_ci * @label - the label to update/replace 20418c2ecf20Sopenharmony_ci * 20428c2ecf20Sopenharmony_ci * Returns: new label that is up to date 20438c2ecf20Sopenharmony_ci * else NULL on failure 20448c2ecf20Sopenharmony_ci * 20458c2ecf20Sopenharmony_ci * Requires: @ns lock be held 20468c2ecf20Sopenharmony_ci * 20478c2ecf20Sopenharmony_ci * Note: worst case is the stale @label does not get updated and has 20488c2ecf20Sopenharmony_ci * to be updated at a later time. 20498c2ecf20Sopenharmony_ci */ 20508c2ecf20Sopenharmony_cistatic struct aa_label *__label_update(struct aa_label *label) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct aa_label *new, *tmp; 20538c2ecf20Sopenharmony_ci struct aa_labelset *ls; 20548c2ecf20Sopenharmony_ci unsigned long flags; 20558c2ecf20Sopenharmony_ci int i, invcount = 0; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci AA_BUG(!label); 20588c2ecf20Sopenharmony_ci AA_BUG(!mutex_is_locked(&labels_ns(label)->lock)); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci new = aa_label_alloc(label->size, label->proxy, GFP_KERNEL); 20618c2ecf20Sopenharmony_ci if (!new) 20628c2ecf20Sopenharmony_ci return NULL; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci /* 20658c2ecf20Sopenharmony_ci * while holding the ns_lock will stop profile replacement, removal, 20668c2ecf20Sopenharmony_ci * and label updates, label merging and removal can be occurring 20678c2ecf20Sopenharmony_ci */ 20688c2ecf20Sopenharmony_ci ls = labels_set(label); 20698c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 20708c2ecf20Sopenharmony_ci for (i = 0; i < label->size; i++) { 20718c2ecf20Sopenharmony_ci AA_BUG(!label->vec[i]); 20728c2ecf20Sopenharmony_ci new->vec[i] = aa_get_newest_profile(label->vec[i]); 20738c2ecf20Sopenharmony_ci AA_BUG(!new->vec[i]); 20748c2ecf20Sopenharmony_ci AA_BUG(!new->vec[i]->label.proxy); 20758c2ecf20Sopenharmony_ci AA_BUG(!new->vec[i]->label.proxy->label); 20768c2ecf20Sopenharmony_ci if (new->vec[i]->label.proxy != label->vec[i]->label.proxy) 20778c2ecf20Sopenharmony_ci invcount++; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* updated stale label by being removed/renamed from labelset */ 20818c2ecf20Sopenharmony_ci if (invcount) { 20828c2ecf20Sopenharmony_ci new->size -= aa_vec_unique(&new->vec[0], new->size, 20838c2ecf20Sopenharmony_ci VEC_FLAG_TERMINATE); 20848c2ecf20Sopenharmony_ci /* TODO: deal with reference labels */ 20858c2ecf20Sopenharmony_ci if (new->size == 1) { 20868c2ecf20Sopenharmony_ci tmp = aa_get_label(&new->vec[0]->label); 20878c2ecf20Sopenharmony_ci AA_BUG(tmp == label); 20888c2ecf20Sopenharmony_ci goto remove; 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci if (labels_set(label) != labels_set(new)) { 20918c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 20928c2ecf20Sopenharmony_ci tmp = aa_label_insert(labels_set(new), new); 20938c2ecf20Sopenharmony_ci write_lock_irqsave(&ls->lock, flags); 20948c2ecf20Sopenharmony_ci goto remove; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci } else 20978c2ecf20Sopenharmony_ci AA_BUG(labels_ns(label) != labels_ns(new)); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci tmp = __label_insert(labels_set(label), new, true); 21008c2ecf20Sopenharmony_ciremove: 21018c2ecf20Sopenharmony_ci /* ensure label is removed, and redirected correctly */ 21028c2ecf20Sopenharmony_ci __label_remove(label, tmp); 21038c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ls->lock, flags); 21048c2ecf20Sopenharmony_ci label_free_or_put_new(tmp, new); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci return tmp; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci/** 21108c2ecf20Sopenharmony_ci * __labelset_update - update labels in @ns 21118c2ecf20Sopenharmony_ci * @ns: namespace to update labels in (NOT NULL) 21128c2ecf20Sopenharmony_ci * 21138c2ecf20Sopenharmony_ci * Requires: @ns lock be held 21148c2ecf20Sopenharmony_ci * 21158c2ecf20Sopenharmony_ci * Walk the labelset ensuring that all labels are up to date and valid 21168c2ecf20Sopenharmony_ci * Any label that has a stale component is marked stale and replaced and 21178c2ecf20Sopenharmony_ci * by an updated version. 21188c2ecf20Sopenharmony_ci * 21198c2ecf20Sopenharmony_ci * If failures happen due to memory pressures then stale labels will 21208c2ecf20Sopenharmony_ci * be left in place until the next pass. 21218c2ecf20Sopenharmony_ci */ 21228c2ecf20Sopenharmony_cistatic void __labelset_update(struct aa_ns *ns) 21238c2ecf20Sopenharmony_ci{ 21248c2ecf20Sopenharmony_ci struct aa_label *label; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci AA_BUG(!ns); 21278c2ecf20Sopenharmony_ci AA_BUG(!mutex_is_locked(&ns->lock)); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci do { 21308c2ecf20Sopenharmony_ci label = labelset_next_stale(&ns->labels); 21318c2ecf20Sopenharmony_ci if (label) { 21328c2ecf20Sopenharmony_ci struct aa_label *l = __label_update(label); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci aa_put_label(l); 21358c2ecf20Sopenharmony_ci aa_put_label(label); 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci } while (label); 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci/** 21418c2ecf20Sopenharmony_ci * __aa_labelset_udate_subtree - update all labels with a stale component 21428c2ecf20Sopenharmony_ci * @ns: ns to start update at (NOT NULL) 21438c2ecf20Sopenharmony_ci * 21448c2ecf20Sopenharmony_ci * Requires: @ns lock be held 21458c2ecf20Sopenharmony_ci * 21468c2ecf20Sopenharmony_ci * Invalidates labels based on @p in @ns and any children namespaces. 21478c2ecf20Sopenharmony_ci */ 21488c2ecf20Sopenharmony_civoid __aa_labelset_update_subtree(struct aa_ns *ns) 21498c2ecf20Sopenharmony_ci{ 21508c2ecf20Sopenharmony_ci struct aa_ns *child; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci AA_BUG(!ns); 21538c2ecf20Sopenharmony_ci AA_BUG(!mutex_is_locked(&ns->lock)); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci __labelset_update(ns); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci list_for_each_entry(child, &ns->sub_ns, base.list) { 21588c2ecf20Sopenharmony_ci mutex_lock_nested(&child->lock, child->level); 21598c2ecf20Sopenharmony_ci __aa_labelset_update_subtree(child); 21608c2ecf20Sopenharmony_ci mutex_unlock(&child->lock); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci} 2163