// SPDX-License-Identifier: GPL-2.0-only1/*2* AppArmor security module3*4* This file contains AppArmor policy manipulation functions5*6* Copyright (C) 1998-2008 Novell/SUSE7* Copyright 2009-2017 Canonical Ltd.8*9* AppArmor policy namespaces, allow for different sets of policies10* to be loaded for tasks within the namespace.11*/1213#include <linux/list.h>14#include <linux/mutex.h>15#include <linux/slab.h>16#include <linux/string.h>1718#include "include/apparmor.h"19#include "include/cred.h"20#include "include/policy_ns.h"21#include "include/label.h"22#include "include/policy.h"2324/* kernel label */25struct aa_label *kernel_t;2627/* root profile namespace */28struct aa_ns *root_ns;29const char *aa_hidden_ns_name = "---";3031/**32* aa_ns_visible - test if @view is visible from @curr33* @curr: namespace to treat as the parent (NOT NULL)34* @view: namespace to test if visible from @curr (NOT NULL)35* @subns: whether view of a subns is allowed36*37* Returns: true if @view is visible from @curr else false38*/39bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns)40{41if (curr == view)42return true;4344if (!subns)45return false;4647for ( ; view; view = view->parent) {48if (view->parent == curr)49return true;50}5152return false;53}5455/**56* aa_ns_name - Find the ns name to display for @view from @curr57* @curr: current namespace (NOT NULL)58* @view: namespace attempting to view (NOT NULL)59* @subns: are subns visible60*61* Returns: name of @view visible from @curr62*/63const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)64{65/* if view == curr then the namespace name isn't displayed */66if (curr == view)67return "";6869if (aa_ns_visible(curr, view, subns)) {70/* at this point if a ns is visible it is in a view ns71* thus the curr ns.hname is a prefix of its name.72* Only output the virtualized portion of the name73* Add + 2 to skip over // separating curr hname prefix74* from the visible tail of the views hname75*/76return view->base.hname + strlen(curr->base.hname) + 2;77}7879return aa_hidden_ns_name;80}8182static struct aa_profile *alloc_unconfined(const char *name)83{84struct aa_profile *profile;8586profile = aa_alloc_null(NULL, name, GFP_KERNEL);87if (!profile)88return NULL;8990profile->label.flags |= FLAG_IX_ON_NAME_ERROR |91FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;92profile->mode = APPARMOR_UNCONFINED;9394return profile;95}9697/**98* alloc_ns - allocate, initialize and return a new namespace99* @prefix: parent namespace name (MAYBE NULL)100* @name: a preallocated name (NOT NULL)101*102* Returns: refcounted namespace or NULL on failure.103*/104static struct aa_ns *alloc_ns(const char *prefix, const char *name)105{106struct aa_ns *ns;107108ns = kzalloc(sizeof(*ns), GFP_KERNEL);109AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, ns);110if (!ns)111return NULL;112if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL))113goto fail_ns;114115INIT_LIST_HEAD(&ns->sub_ns);116INIT_LIST_HEAD(&ns->rawdata_list);117mutex_init(&ns->lock);118init_waitqueue_head(&ns->wait);119120/* released by aa_free_ns() */121ns->unconfined = alloc_unconfined("unconfined");122if (!ns->unconfined)123goto fail_unconfined;124/* ns and ns->unconfined share ns->unconfined refcount */125ns->unconfined->ns = ns;126127atomic_set(&ns->uniq_null, 0);128129aa_labelset_init(&ns->labels);130131return ns;132133fail_unconfined:134aa_policy_destroy(&ns->base);135fail_ns:136kfree_sensitive(ns);137return NULL;138}139140/**141* aa_free_ns - free a profile namespace142* @ns: the namespace to free (MAYBE NULL)143*144* Requires: All references to the namespace must have been put, if the145* namespace was referenced by a profile confining a task,146*/147void aa_free_ns(struct aa_ns *ns)148{149if (!ns)150return;151152aa_policy_destroy(&ns->base);153aa_labelset_destroy(&ns->labels);154aa_put_ns(ns->parent);155156ns->unconfined->ns = NULL;157aa_free_profile(ns->unconfined);158kfree_sensitive(ns);159}160161/**162* __aa_lookupn_ns - lookup the namespace matching @hname163* @view: namespace to search in (NOT NULL)164* @hname: hierarchical ns name (NOT NULL)165* @n: length of @hname166*167* Requires: rcu_read_lock be held168*169* Returns: unrefcounted ns pointer or NULL if not found170*171* Do a relative name lookup, recursing through profile tree.172*/173struct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n)174{175struct aa_ns *ns = view;176const char *split;177178for (split = strnstr(hname, "//", n); split;179split = strnstr(hname, "//", n)) {180ns = __aa_findn_ns(&ns->sub_ns, hname, split - hname);181if (!ns)182return NULL;183184n -= split + 2 - hname;185hname = split + 2;186}187188if (n)189return __aa_findn_ns(&ns->sub_ns, hname, n);190return NULL;191}192193/**194* aa_lookupn_ns - look up a policy namespace relative to @view195* @view: namespace to search in (NOT NULL)196* @name: name of namespace to find (NOT NULL)197* @n: length of @name198*199* Returns: a refcounted namespace on the list, or NULL if no namespace200* called @name exists.201*202* refcount released by caller203*/204struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n)205{206struct aa_ns *ns = NULL;207208rcu_read_lock();209ns = aa_get_ns(__aa_lookupn_ns(view, name, n));210rcu_read_unlock();211212return ns;213}214215static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,216struct dentry *dir)217{218struct aa_ns *ns;219int error;220221AA_BUG(!parent);222AA_BUG(!name);223AA_BUG(!mutex_is_locked(&parent->lock));224225ns = alloc_ns(parent->base.hname, name);226if (!ns)227return ERR_PTR(-ENOMEM);228ns->level = parent->level + 1;229mutex_lock_nested(&ns->lock, ns->level);230error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir);231if (error) {232AA_ERROR("Failed to create interface for ns %s\n",233ns->base.name);234mutex_unlock(&ns->lock);235aa_free_ns(ns);236return ERR_PTR(error);237}238ns->parent = aa_get_ns(parent);239list_add_rcu(&ns->base.list, &parent->sub_ns);240/* add list ref */241aa_get_ns(ns);242mutex_unlock(&ns->lock);243244return ns;245}246247/**248* __aa_find_or_create_ns - create an ns, fail if it already exists249* @parent: the parent of the namespace being created250* @name: the name of the namespace251* @dir: if not null the dir to put the ns entries in252*253* Returns: the a refcounted ns that has been add or an ERR_PTR254*/255struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,256struct dentry *dir)257{258struct aa_ns *ns;259260AA_BUG(!mutex_is_locked(&parent->lock));261262/* try and find the specified ns */263/* released by caller */264ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));265if (!ns)266ns = __aa_create_ns(parent, name, dir);267else268ns = ERR_PTR(-EEXIST);269270/* return ref */271return ns;272}273274/**275* aa_prepare_ns - find an existing or create a new namespace of @name276* @parent: ns to treat as parent277* @name: the namespace to find or add (NOT NULL)278*279* Returns: refcounted namespace or PTR_ERR if failed to create one280*/281struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name)282{283struct aa_ns *ns;284285mutex_lock_nested(&parent->lock, parent->level);286/* try and find the specified ns and if it doesn't exist create it */287/* released by caller */288ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));289if (!ns)290ns = __aa_create_ns(parent, name, NULL);291mutex_unlock(&parent->lock);292293/* return ref */294return ns;295}296297static void __ns_list_release(struct list_head *head);298299/**300* destroy_ns - remove everything contained by @ns301* @ns: namespace to have it contents removed (NOT NULL)302*/303static void destroy_ns(struct aa_ns *ns)304{305if (!ns)306return;307308mutex_lock_nested(&ns->lock, ns->level);309/* release all profiles in this namespace */310__aa_profile_list_release(&ns->base.profiles);311312/* release all sub namespaces */313__ns_list_release(&ns->sub_ns);314315if (ns->parent) {316unsigned long flags;317318write_lock_irqsave(&ns->labels.lock, flags);319__aa_proxy_redirect(ns_unconfined(ns),320ns_unconfined(ns->parent));321write_unlock_irqrestore(&ns->labels.lock, flags);322}323__aafs_ns_rmdir(ns);324mutex_unlock(&ns->lock);325}326327/**328* __aa_remove_ns - remove a namespace and all its children329* @ns: namespace to be removed (NOT NULL)330*331* Requires: ns->parent->lock be held and ns removed from parent.332*/333void __aa_remove_ns(struct aa_ns *ns)334{335/* remove ns from namespace list */336list_del_rcu(&ns->base.list);337destroy_ns(ns);338aa_put_ns(ns);339}340341/**342* __ns_list_release - remove all profile namespaces on the list put refs343* @head: list of profile namespaces (NOT NULL)344*345* Requires: namespace lock be held346*/347static void __ns_list_release(struct list_head *head)348{349struct aa_ns *ns, *tmp;350351list_for_each_entry_safe(ns, tmp, head, base.list)352__aa_remove_ns(ns);353354}355356/**357* aa_alloc_root_ns - allocate the root profile namespace358*359* Returns: %0 on success else error360*361*/362int __init aa_alloc_root_ns(void)363{364struct aa_profile *kernel_p;365366/* released by aa_free_root_ns - used as list ref*/367root_ns = alloc_ns(NULL, "root");368if (!root_ns)369return -ENOMEM;370371kernel_p = alloc_unconfined("kernel_t");372if (!kernel_p) {373destroy_ns(root_ns);374aa_free_ns(root_ns);375return -ENOMEM;376}377kernel_t = &kernel_p->label;378root_ns->unconfined->ns = aa_get_ns(root_ns);379380return 0;381}382383/**384* aa_free_root_ns - free the root profile namespace385*/386void __init aa_free_root_ns(void)387{388struct aa_ns *ns = root_ns;389390root_ns = NULL;391392aa_label_free(kernel_t);393destroy_ns(ns);394aa_put_ns(ns);395}396397398