18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor policy manipulation functions 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * AppArmor policy namespaces, allow for different sets of policies 118c2ecf20Sopenharmony_ci * to be loaded for tasks within the namespace. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/list.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "include/apparmor.h" 208c2ecf20Sopenharmony_ci#include "include/cred.h" 218c2ecf20Sopenharmony_ci#include "include/policy_ns.h" 228c2ecf20Sopenharmony_ci#include "include/label.h" 238c2ecf20Sopenharmony_ci#include "include/policy.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* root profile namespace */ 268c2ecf20Sopenharmony_cistruct aa_ns *root_ns; 278c2ecf20Sopenharmony_ciconst char *aa_hidden_ns_name = "---"; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/** 308c2ecf20Sopenharmony_ci * aa_ns_visible - test if @view is visible from @curr 318c2ecf20Sopenharmony_ci * @curr: namespace to treat as the parent (NOT NULL) 328c2ecf20Sopenharmony_ci * @view: namespace to test if visible from @curr (NOT NULL) 338c2ecf20Sopenharmony_ci * @subns: whether view of a subns is allowed 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Returns: true if @view is visible from @curr else false 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cibool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci if (curr == view) 408c2ecf20Sopenharmony_ci return true; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (!subns) 438c2ecf20Sopenharmony_ci return false; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci for ( ; view; view = view->parent) { 468c2ecf20Sopenharmony_ci if (view->parent == curr) 478c2ecf20Sopenharmony_ci return true; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return false; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * aa_na_name - Find the ns name to display for @view from @curr 558c2ecf20Sopenharmony_ci * @curr - current namespace (NOT NULL) 568c2ecf20Sopenharmony_ci * @view - namespace attempting to view (NOT NULL) 578c2ecf20Sopenharmony_ci * @subns - are subns visible 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Returns: name of @view visible from @curr 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciconst char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci /* if view == curr then the namespace name isn't displayed */ 648c2ecf20Sopenharmony_ci if (curr == view) 658c2ecf20Sopenharmony_ci return ""; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (aa_ns_visible(curr, view, subns)) { 688c2ecf20Sopenharmony_ci /* at this point if a ns is visible it is in a view ns 698c2ecf20Sopenharmony_ci * thus the curr ns.hname is a prefix of its name. 708c2ecf20Sopenharmony_ci * Only output the virtualized portion of the name 718c2ecf20Sopenharmony_ci * Add + 2 to skip over // separating curr hname prefix 728c2ecf20Sopenharmony_ci * from the visible tail of the views hname 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci return view->base.hname + strlen(curr->base.hname) + 2; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return aa_hidden_ns_name; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/** 818c2ecf20Sopenharmony_ci * alloc_ns - allocate, initialize and return a new namespace 828c2ecf20Sopenharmony_ci * @prefix: parent namespace name (MAYBE NULL) 838c2ecf20Sopenharmony_ci * @name: a preallocated name (NOT NULL) 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Returns: refcounted namespace or NULL on failure. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic struct aa_ns *alloc_ns(const char *prefix, const char *name) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct aa_ns *ns; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ns = kzalloc(sizeof(*ns), GFP_KERNEL); 928c2ecf20Sopenharmony_ci AA_DEBUG("%s(%p)\n", __func__, ns); 938c2ecf20Sopenharmony_ci if (!ns) 948c2ecf20Sopenharmony_ci return NULL; 958c2ecf20Sopenharmony_ci if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL)) 968c2ecf20Sopenharmony_ci goto fail_ns; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ns->sub_ns); 998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ns->rawdata_list); 1008c2ecf20Sopenharmony_ci mutex_init(&ns->lock); 1018c2ecf20Sopenharmony_ci init_waitqueue_head(&ns->wait); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* released by aa_free_ns() */ 1048c2ecf20Sopenharmony_ci ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL); 1058c2ecf20Sopenharmony_ci if (!ns->unconfined) 1068c2ecf20Sopenharmony_ci goto fail_unconfined; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR | 1098c2ecf20Sopenharmony_ci FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; 1108c2ecf20Sopenharmony_ci ns->unconfined->mode = APPARMOR_UNCONFINED; 1118c2ecf20Sopenharmony_ci ns->unconfined->file.dfa = aa_get_dfa(nulldfa); 1128c2ecf20Sopenharmony_ci ns->unconfined->policy.dfa = aa_get_dfa(nulldfa); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* ns and ns->unconfined share ns->unconfined refcount */ 1158c2ecf20Sopenharmony_ci ns->unconfined->ns = ns; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci atomic_set(&ns->uniq_null, 0); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci aa_labelset_init(&ns->labels); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return ns; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cifail_unconfined: 1248c2ecf20Sopenharmony_ci aa_policy_destroy(&ns->base); 1258c2ecf20Sopenharmony_cifail_ns: 1268c2ecf20Sopenharmony_ci kfree_sensitive(ns); 1278c2ecf20Sopenharmony_ci return NULL; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/** 1318c2ecf20Sopenharmony_ci * aa_free_ns - free a profile namespace 1328c2ecf20Sopenharmony_ci * @ns: the namespace to free (MAYBE NULL) 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Requires: All references to the namespace must have been put, if the 1358c2ecf20Sopenharmony_ci * namespace was referenced by a profile confining a task, 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_civoid aa_free_ns(struct aa_ns *ns) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci if (!ns) 1408c2ecf20Sopenharmony_ci return; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci aa_policy_destroy(&ns->base); 1438c2ecf20Sopenharmony_ci aa_labelset_destroy(&ns->labels); 1448c2ecf20Sopenharmony_ci aa_put_ns(ns->parent); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci ns->unconfined->ns = NULL; 1478c2ecf20Sopenharmony_ci aa_free_profile(ns->unconfined); 1488c2ecf20Sopenharmony_ci kfree_sensitive(ns); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/** 1528c2ecf20Sopenharmony_ci * aa_findn_ns - look up a profile namespace on the namespace list 1538c2ecf20Sopenharmony_ci * @root: namespace to search in (NOT NULL) 1548c2ecf20Sopenharmony_ci * @name: name of namespace to find (NOT NULL) 1558c2ecf20Sopenharmony_ci * @n: length of @name 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Returns: a refcounted namespace on the list, or NULL if no namespace 1588c2ecf20Sopenharmony_ci * called @name exists. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * refcount released by caller 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistruct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct aa_ns *ns = NULL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci rcu_read_lock(); 1678c2ecf20Sopenharmony_ci ns = aa_get_ns(__aa_findn_ns(&root->sub_ns, name, n)); 1688c2ecf20Sopenharmony_ci rcu_read_unlock(); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return ns; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * aa_find_ns - look up a profile namespace on the namespace list 1758c2ecf20Sopenharmony_ci * @root: namespace to search in (NOT NULL) 1768c2ecf20Sopenharmony_ci * @name: name of namespace to find (NOT NULL) 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Returns: a refcounted namespace on the list, or NULL if no namespace 1798c2ecf20Sopenharmony_ci * called @name exists. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * refcount released by caller 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistruct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci return aa_findn_ns(root, name, strlen(name)); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * __aa_lookupn_ns - lookup the namespace matching @hname 1908c2ecf20Sopenharmony_ci * @base: base list to start looking up profile name from (NOT NULL) 1918c2ecf20Sopenharmony_ci * @hname: hierarchical ns name (NOT NULL) 1928c2ecf20Sopenharmony_ci * @n: length of @hname 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Requires: rcu_read_lock be held 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * Returns: unrefcounted ns pointer or NULL if not found 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * Do a relative name lookup, recursing through profile tree. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistruct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct aa_ns *ns = view; 2038c2ecf20Sopenharmony_ci const char *split; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (split = strnstr(hname, "//", n); split; 2068c2ecf20Sopenharmony_ci split = strnstr(hname, "//", n)) { 2078c2ecf20Sopenharmony_ci ns = __aa_findn_ns(&ns->sub_ns, hname, split - hname); 2088c2ecf20Sopenharmony_ci if (!ns) 2098c2ecf20Sopenharmony_ci return NULL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci n -= split + 2 - hname; 2128c2ecf20Sopenharmony_ci hname = split + 2; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (n) 2168c2ecf20Sopenharmony_ci return __aa_findn_ns(&ns->sub_ns, hname, n); 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/** 2218c2ecf20Sopenharmony_ci * aa_lookupn_ns - look up a policy namespace relative to @view 2228c2ecf20Sopenharmony_ci * @view: namespace to search in (NOT NULL) 2238c2ecf20Sopenharmony_ci * @name: name of namespace to find (NOT NULL) 2248c2ecf20Sopenharmony_ci * @n: length of @name 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Returns: a refcounted namespace on the list, or NULL if no namespace 2278c2ecf20Sopenharmony_ci * called @name exists. 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * refcount released by caller 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistruct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct aa_ns *ns = NULL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci rcu_read_lock(); 2368c2ecf20Sopenharmony_ci ns = aa_get_ns(__aa_lookupn_ns(view, name, n)); 2378c2ecf20Sopenharmony_ci rcu_read_unlock(); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return ns; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, 2438c2ecf20Sopenharmony_ci struct dentry *dir) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct aa_ns *ns; 2468c2ecf20Sopenharmony_ci int error; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci AA_BUG(!parent); 2498c2ecf20Sopenharmony_ci AA_BUG(!name); 2508c2ecf20Sopenharmony_ci AA_BUG(!mutex_is_locked(&parent->lock)); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ns = alloc_ns(parent->base.hname, name); 2538c2ecf20Sopenharmony_ci if (!ns) 2548c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2558c2ecf20Sopenharmony_ci ns->level = parent->level + 1; 2568c2ecf20Sopenharmony_ci mutex_lock_nested(&ns->lock, ns->level); 2578c2ecf20Sopenharmony_ci error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir); 2588c2ecf20Sopenharmony_ci if (error) { 2598c2ecf20Sopenharmony_ci AA_ERROR("Failed to create interface for ns %s\n", 2608c2ecf20Sopenharmony_ci ns->base.name); 2618c2ecf20Sopenharmony_ci mutex_unlock(&ns->lock); 2628c2ecf20Sopenharmony_ci aa_free_ns(ns); 2638c2ecf20Sopenharmony_ci return ERR_PTR(error); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci ns->parent = aa_get_ns(parent); 2668c2ecf20Sopenharmony_ci list_add_rcu(&ns->base.list, &parent->sub_ns); 2678c2ecf20Sopenharmony_ci /* add list ref */ 2688c2ecf20Sopenharmony_ci aa_get_ns(ns); 2698c2ecf20Sopenharmony_ci mutex_unlock(&ns->lock); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return ns; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * aa_create_ns - create an ns, fail if it already exists 2768c2ecf20Sopenharmony_ci * @parent: the parent of the namespace being created 2778c2ecf20Sopenharmony_ci * @name: the name of the namespace 2788c2ecf20Sopenharmony_ci * @dir: if not null the dir to put the ns entries in 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * Returns: the a refcounted ns that has been add or an ERR_PTR 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_cistruct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name, 2838c2ecf20Sopenharmony_ci struct dentry *dir) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct aa_ns *ns; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci AA_BUG(!mutex_is_locked(&parent->lock)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* try and find the specified ns */ 2908c2ecf20Sopenharmony_ci /* released by caller */ 2918c2ecf20Sopenharmony_ci ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); 2928c2ecf20Sopenharmony_ci if (!ns) 2938c2ecf20Sopenharmony_ci ns = __aa_create_ns(parent, name, dir); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci ns = ERR_PTR(-EEXIST); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* return ref */ 2988c2ecf20Sopenharmony_ci return ns; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/** 3028c2ecf20Sopenharmony_ci * aa_prepare_ns - find an existing or create a new namespace of @name 3038c2ecf20Sopenharmony_ci * @parent: ns to treat as parent 3048c2ecf20Sopenharmony_ci * @name: the namespace to find or add (NOT NULL) 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * Returns: refcounted namespace or PTR_ERR if failed to create one 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_cistruct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct aa_ns *ns; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci mutex_lock_nested(&parent->lock, parent->level); 3138c2ecf20Sopenharmony_ci /* try and find the specified ns and if it doesn't exist create it */ 3148c2ecf20Sopenharmony_ci /* released by caller */ 3158c2ecf20Sopenharmony_ci ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); 3168c2ecf20Sopenharmony_ci if (!ns) 3178c2ecf20Sopenharmony_ci ns = __aa_create_ns(parent, name, NULL); 3188c2ecf20Sopenharmony_ci mutex_unlock(&parent->lock); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* return ref */ 3218c2ecf20Sopenharmony_ci return ns; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void __ns_list_release(struct list_head *head); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/** 3278c2ecf20Sopenharmony_ci * destroy_ns - remove everything contained by @ns 3288c2ecf20Sopenharmony_ci * @ns: namespace to have it contents removed (NOT NULL) 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic void destroy_ns(struct aa_ns *ns) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci if (!ns) 3338c2ecf20Sopenharmony_ci return; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci mutex_lock_nested(&ns->lock, ns->level); 3368c2ecf20Sopenharmony_ci /* release all profiles in this namespace */ 3378c2ecf20Sopenharmony_ci __aa_profile_list_release(&ns->base.profiles); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* release all sub namespaces */ 3408c2ecf20Sopenharmony_ci __ns_list_release(&ns->sub_ns); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (ns->parent) { 3438c2ecf20Sopenharmony_ci unsigned long flags; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci write_lock_irqsave(&ns->labels.lock, flags); 3468c2ecf20Sopenharmony_ci __aa_proxy_redirect(ns_unconfined(ns), 3478c2ecf20Sopenharmony_ci ns_unconfined(ns->parent)); 3488c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ns->labels.lock, flags); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci __aafs_ns_rmdir(ns); 3518c2ecf20Sopenharmony_ci mutex_unlock(&ns->lock); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/** 3558c2ecf20Sopenharmony_ci * __aa_remove_ns - remove a namespace and all its children 3568c2ecf20Sopenharmony_ci * @ns: namespace to be removed (NOT NULL) 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * Requires: ns->parent->lock be held and ns removed from parent. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_civoid __aa_remove_ns(struct aa_ns *ns) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci /* remove ns from namespace list */ 3638c2ecf20Sopenharmony_ci list_del_rcu(&ns->base.list); 3648c2ecf20Sopenharmony_ci destroy_ns(ns); 3658c2ecf20Sopenharmony_ci aa_put_ns(ns); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/** 3698c2ecf20Sopenharmony_ci * __ns_list_release - remove all profile namespaces on the list put refs 3708c2ecf20Sopenharmony_ci * @head: list of profile namespaces (NOT NULL) 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * Requires: namespace lock be held 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_cistatic void __ns_list_release(struct list_head *head) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct aa_ns *ns, *tmp; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci list_for_each_entry_safe(ns, tmp, head, base.list) 3798c2ecf20Sopenharmony_ci __aa_remove_ns(ns); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * aa_alloc_root_ns - allocate the root profile namespace 3858c2ecf20Sopenharmony_ci * 3868c2ecf20Sopenharmony_ci * Returns: %0 on success else error 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ciint __init aa_alloc_root_ns(void) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci /* released by aa_free_root_ns - used as list ref*/ 3928c2ecf20Sopenharmony_ci root_ns = alloc_ns(NULL, "root"); 3938c2ecf20Sopenharmony_ci if (!root_ns) 3948c2ecf20Sopenharmony_ci return -ENOMEM; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /** 4008c2ecf20Sopenharmony_ci * aa_free_root_ns - free the root profile namespace 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_civoid __init aa_free_root_ns(void) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct aa_ns *ns = root_ns; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci root_ns = NULL; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci destroy_ns(ns); 4098c2ecf20Sopenharmony_ci aa_put_ns(ns); 4108c2ecf20Sopenharmony_ci} 411