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