From cff281f6861e72f1416927aaa0c10a08bb7b2d3f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:15 -0800 Subject: apparmor: split apparmor policy namespaces code into its own file Policy namespaces will be diverging from profile management and expanding so put it in its own file. Signed-off-by: John Johansen --- security/apparmor/policy.c | 298 +++------------------------------------------ 1 file changed, 14 insertions(+), 284 deletions(-) (limited to 'security/apparmor/policy.c') diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a331149a4587..2a861824319e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -85,13 +85,11 @@ #include "include/match.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/policy_unpack.h" #include "include/resource.h" -/* root profile namespace */ -struct aa_namespace *root_ns; - const char *const aa_profile_mode_names[] = { "enforce", "complain", @@ -100,202 +98,16 @@ const char *const aa_profile_mode_names[] = { }; -/* - * Routines for AppArmor namespaces - */ - -static const char *hidden_ns_name = "---"; -/** - * aa_ns_visible - test if @view is visible from @curr - * @curr: namespace to treat as the parent (NOT NULL) - * @view: namespace to test if visible from @curr (NOT NULL) - * - * Returns: true if @view is visible from @curr else false - */ -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) -{ - if (curr == view) - return true; - - for ( ; view; view = view->parent) { - if (view->parent == curr) - return true; - } - return false; -} - -/** - * aa_na_name - Find the ns name to display for @view from @curr - * @curr - current namespace (NOT NULL) - * @view - namespace attempting to view (NOT NULL) - * - * Returns: name of @view visible from @curr - */ -const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) -{ - /* if view == curr then the namespace name isn't displayed */ - if (curr == view) - return ""; - - if (aa_ns_visible(curr, view)) { - /* at this point if a ns is visible it is in a view ns - * thus the curr ns.hname is a prefix of its name. - * Only output the virtualized portion of the name - * Add + 2 to skip over // separating curr hname prefix - * from the visible tail of the views hname - */ - return view->base.hname + strlen(curr->base.hname) + 2; - } else - return hidden_ns_name; -} - -/** - * alloc_namespace - allocate, initialize and return a new namespace - * @prefix: parent namespace name (MAYBE NULL) - * @name: a preallocated name (NOT NULL) - * - * Returns: refcounted namespace or NULL on failure. - */ -static struct aa_namespace *alloc_namespace(const char *prefix, - const char *name) -{ - struct aa_namespace *ns; - - ns = kzalloc(sizeof(*ns), GFP_KERNEL); - AA_DEBUG("%s(%p)\n", __func__, ns); - if (!ns) - return NULL; - if (!aa_policy_init(&ns->base, prefix, name)) - goto fail_ns; - - INIT_LIST_HEAD(&ns->sub_ns); - mutex_init(&ns->lock); - - /* released by free_namespace */ - ns->unconfined = aa_alloc_profile("unconfined"); - if (!ns->unconfined) - goto fail_unconfined; - - ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | - PFLAG_IMMUTABLE | PFLAG_NS_COUNT; - ns->unconfined->mode = APPARMOR_UNCONFINED; - - /* ns and ns->unconfined share ns->unconfined refcount */ - ns->unconfined->ns = ns; - - atomic_set(&ns->uniq_null, 0); - - return ns; - -fail_unconfined: - kzfree(ns->base.hname); -fail_ns: - kzfree(ns); - return NULL; -} - -/** - * free_namespace - free a profile namespace - * @ns: the namespace to free (MAYBE NULL) - * - * Requires: All references to the namespace must have been put, if the - * namespace was referenced by a profile confining a task, - */ -static void free_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - aa_policy_destroy(&ns->base); - aa_put_namespace(ns->parent); - - ns->unconfined->ns = NULL; - aa_free_profile(ns->unconfined); - kzfree(ns); -} - -/** - * __aa_find_namespace - find a namespace on a list by @name - * @head: list to search for namespace on (NOT NULL) - * @name: name of namespace to look for (NOT NULL) - * - * Returns: unrefcounted namespace - * - * Requires: rcu_read_lock be held - */ -static struct aa_namespace *__aa_find_namespace(struct list_head *head, - const char *name) -{ - return (struct aa_namespace *)__policy_find(head, name); -} - -/** - * aa_find_namespace - look up a profile namespace on the namespace list - * @root: namespace to search in (NOT NULL) - * @name: name of namespace to find (NOT NULL) - * - * Returns: a refcounted namespace on the list, or NULL if no namespace - * called @name exists. - * - * refcount released by caller - */ -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name) -{ - struct aa_namespace *ns = NULL; - - rcu_read_lock(); - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - rcu_read_unlock(); - - return ns; -} - -/** - * aa_prepare_namespace - find an existing or create a new namespace of @name - * @name: the namespace to find or add (MAYBE NULL) - * - * Returns: refcounted namespace or NULL if failed to create one - */ -static struct aa_namespace *aa_prepare_namespace(const char *name) +/* requires profile list write lock held */ +void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) { - struct aa_namespace *ns, *root; - - root = aa_current_profile()->ns; - - mutex_lock(&root->lock); - - /* if name isn't specified the profile is loaded to the current ns */ - if (!name) { - /* released by caller */ - ns = aa_get_namespace(root); - goto out; - } + struct aa_profile *tmp; - /* try and find the specified ns and if it doesn't exist create it */ - /* released by caller */ - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - if (!ns) { - ns = alloc_namespace(root->base.hname, name); - if (!ns) - goto out; - if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { - AA_ERROR("Failed to create interface for ns %s\n", - ns->base.name); - free_namespace(ns); - ns = NULL; - goto out; - } - ns->parent = aa_get_namespace(root); - list_add_rcu(&ns->base.list, &root->sub_ns); - /* add list ref */ - aa_get_namespace(ns); - } -out: - mutex_unlock(&root->lock); - - /* return ref */ - return ns; + tmp = rcu_dereference_protected(orig->replacedby->profile, + mutex_is_locked(&orig->ns->lock)); + rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); + orig->flags |= PFLAG_INVALID; + aa_put_profile(tmp); } /** @@ -333,8 +145,6 @@ static void __list_remove_profile(struct aa_profile *profile) aa_put_profile(profile); } -static void __profile_list_release(struct list_head *head); - /** * __remove_profile - remove old profile, and children * @profile: profile to be replaced (NOT NULL) @@ -344,7 +154,7 @@ static void __profile_list_release(struct list_head *head); static void __remove_profile(struct aa_profile *profile) { /* release any children lists first */ - __profile_list_release(&profile->base.profiles); + __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ __aa_update_replacedby(profile, profile->ns->unconfined); __aa_fs_profile_rmdir(profile); @@ -352,98 +162,18 @@ static void __remove_profile(struct aa_profile *profile) } /** - * __profile_list_release - remove all profiles on the list and put refs + * __aa_profile_list_release - remove all profiles on the list and put refs * @head: list of profiles (NOT NULL) * * Requires: namespace lock be held */ -static void __profile_list_release(struct list_head *head) +void __aa_profile_list_release(struct list_head *head) { struct aa_profile *profile, *tmp; list_for_each_entry_safe(profile, tmp, head, base.list) __remove_profile(profile); } -static void __ns_list_release(struct list_head *head); - -/** - * destroy_namespace - remove everything contained by @ns - * @ns: namespace to have it contents removed (NOT NULL) - */ -static void destroy_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - mutex_lock(&ns->lock); - /* release all profiles in this namespace */ - __profile_list_release(&ns->base.profiles); - - /* release all sub namespaces */ - __ns_list_release(&ns->sub_ns); - - if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); - __aa_fs_namespace_rmdir(ns); - mutex_unlock(&ns->lock); -} - -/** - * __remove_namespace - remove a namespace and all its children - * @ns: namespace to be removed (NOT NULL) - * - * Requires: ns->parent->lock be held and ns removed from parent. - */ -static void __remove_namespace(struct aa_namespace *ns) -{ - /* remove ns from namespace list */ - list_del_rcu(&ns->base.list); - destroy_namespace(ns); - aa_put_namespace(ns); -} - -/** - * __ns_list_release - remove all profile namespaces on the list put refs - * @head: list of profile namespaces (NOT NULL) - * - * Requires: namespace lock be held - */ -static void __ns_list_release(struct list_head *head) -{ - struct aa_namespace *ns, *tmp; - list_for_each_entry_safe(ns, tmp, head, base.list) - __remove_namespace(ns); - -} - -/** - * aa_alloc_root_ns - allocate the root profile namespace - * - * Returns: %0 on success else error - * - */ -int __init aa_alloc_root_ns(void) -{ - /* released by aa_free_root_ns - used as list ref*/ - root_ns = alloc_namespace(NULL, "root"); - if (!root_ns) - return -ENOMEM; - - return 0; -} - - /** - * aa_free_root_ns - free the root profile namespace - */ -void __init aa_free_root_ns(void) - { - struct aa_namespace *ns = root_ns; - root_ns = NULL; - - destroy_namespace(ns); - aa_put_namespace(ns); -} - static void free_replacedby(struct aa_replacedby *r) { @@ -507,7 +237,7 @@ static void aa_free_profile_rcu(struct rcu_head *head) { struct aa_profile *p = container_of(head, struct aa_profile, rcu); if (p->flags & PFLAG_NS_COUNT) - free_namespace(p->ns); + aa_free_namespace(p->ns); else aa_free_profile(p); } @@ -1181,7 +911,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ mutex_lock(&ns->parent->lock); - __remove_namespace(ns); + __aa_remove_namespace(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ -- cgit v1.2.3