summaryrefslogtreecommitdiff
path: root/security/apparmor/policy_ns.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/apparmor/policy_ns.c')
-rw-r--r--security/apparmor/policy_ns.c112
1 files changed, 48 insertions, 64 deletions
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index 351d3bab3a3d..64783ca3b0f2 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AppArmor security module
*
@@ -6,11 +7,6 @@
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2017 Canonical Ltd.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
* AppArmor policy namespaces, allow for different sets of policies
* to be loaded for tasks within the namespace.
*/
@@ -21,11 +17,14 @@
#include <linux/string.h>
#include "include/apparmor.h"
-#include "include/context.h"
+#include "include/cred.h"
#include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h"
+/* kernel label */
+struct aa_label *kernel_t;
+
/* root profile namespace */
struct aa_ns *root_ns;
const char *aa_hidden_ns_name = "---";
@@ -55,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns)
}
/**
- * 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)
- * @subns - are subns visible
+ * aa_ns_name - Find the ns name to display for @view from @curr
+ * @curr: current namespace (NOT NULL)
+ * @view: namespace attempting to view (NOT NULL)
+ * @subns: are subns visible
*
* Returns: name of @view visible from @curr
*/
@@ -81,6 +80,21 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)
return aa_hidden_ns_name;
}
+static struct aa_profile *alloc_unconfined(const char *name)
+{
+ struct aa_profile *profile;
+
+ profile = aa_alloc_null(NULL, name, GFP_KERNEL);
+ if (!profile)
+ return NULL;
+
+ profile->label.flags |= FLAG_IX_ON_NAME_ERROR |
+ FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
+ profile->mode = APPARMOR_UNCONFINED;
+
+ return profile;
+}
+
/**
* alloc_ns - allocate, initialize and return a new namespace
* @prefix: parent namespace name (MAYBE NULL)
@@ -93,7 +107,7 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
struct aa_ns *ns;
ns = kzalloc(sizeof(*ns), GFP_KERNEL);
- AA_DEBUG("%s(%p)\n", __func__, ns);
+ AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, ns);
if (!ns)
return NULL;
if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL))
@@ -105,14 +119,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
init_waitqueue_head(&ns->wait);
/* released by aa_free_ns() */
- ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL);
+ ns->unconfined = alloc_unconfined("unconfined");
if (!ns->unconfined)
goto fail_unconfined;
-
- ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
- FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
- ns->unconfined->mode = APPARMOR_UNCONFINED;
-
/* ns and ns->unconfined share ns->unconfined refcount */
ns->unconfined->ns = ns;
@@ -123,9 +132,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
return ns;
fail_unconfined:
- kzfree(ns->base.hname);
+ aa_policy_destroy(&ns->base);
fail_ns:
- kzfree(ns);
+ kfree_sensitive(ns);
return NULL;
}
@@ -147,49 +156,12 @@ void aa_free_ns(struct aa_ns *ns)
ns->unconfined->ns = NULL;
aa_free_profile(ns->unconfined);
- kzfree(ns);
-}
-
-/**
- * aa_findn_ns - look up a profile namespace on the namespace list
- * @root: namespace to search in (NOT NULL)
- * @name: name of namespace to find (NOT NULL)
- * @n: length of @name
- *
- * Returns: a refcounted namespace on the list, or NULL if no namespace
- * called @name exists.
- *
- * refcount released by caller
- */
-struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n)
-{
- struct aa_ns *ns = NULL;
-
- rcu_read_lock();
- ns = aa_get_ns(__aa_findn_ns(&root->sub_ns, name, n));
- rcu_read_unlock();
-
- return ns;
-}
-
-/**
- * aa_find_ns - 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_ns *aa_find_ns(struct aa_ns *root, const char *name)
-{
- return aa_findn_ns(root, name, strlen(name));
+ kfree_sensitive(ns);
}
/**
* __aa_lookupn_ns - lookup the namespace matching @hname
- * @base: base list to start looking up profile name from (NOT NULL)
+ * @view: namespace to search in (NOT NULL)
* @hname: hierarchical ns name (NOT NULL)
* @n: length of @hname
*
@@ -253,8 +225,9 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
ns = alloc_ns(parent->base.hname, name);
if (!ns)
- return NULL;
- mutex_lock(&ns->lock);
+ return ERR_PTR(-ENOMEM);
+ ns->level = parent->level + 1;
+ mutex_lock_nested(&ns->lock, ns->level);
error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir);
if (error) {
AA_ERROR("Failed to create interface for ns %s\n",
@@ -264,7 +237,6 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
return ERR_PTR(error);
}
ns->parent = aa_get_ns(parent);
- ns->level = parent->level + 1;
list_add_rcu(&ns->base.list, &parent->sub_ns);
/* add list ref */
aa_get_ns(ns);
@@ -274,7 +246,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
}
/**
- * aa_create_ns - create an ns, fail if it already exists
+ * __aa_find_or_create_ns - create an ns, fail if it already exists
* @parent: the parent of the namespace being created
* @name: the name of the namespace
* @dir: if not null the dir to put the ns entries in
@@ -311,7 +283,7 @@ struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name)
{
struct aa_ns *ns;
- mutex_lock(&parent->lock);
+ mutex_lock_nested(&parent->lock, parent->level);
/* try and find the specified ns and if it doesn't exist create it */
/* released by caller */
ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
@@ -334,7 +306,7 @@ static void destroy_ns(struct aa_ns *ns)
if (!ns)
return;
- mutex_lock(&ns->lock);
+ mutex_lock_nested(&ns->lock, ns->level);
/* release all profiles in this namespace */
__aa_profile_list_release(&ns->base.profiles);
@@ -390,11 +362,22 @@ static void __ns_list_release(struct list_head *head)
*/
int __init aa_alloc_root_ns(void)
{
+ struct aa_profile *kernel_p;
+
/* released by aa_free_root_ns - used as list ref*/
root_ns = alloc_ns(NULL, "root");
if (!root_ns)
return -ENOMEM;
+ kernel_p = alloc_unconfined("kernel_t");
+ if (!kernel_p) {
+ destroy_ns(root_ns);
+ aa_free_ns(root_ns);
+ return -ENOMEM;
+ }
+ kernel_t = &kernel_p->label;
+ root_ns->unconfined->ns = aa_get_ns(root_ns);
+
return 0;
}
@@ -407,6 +390,7 @@ void __init aa_free_root_ns(void)
root_ns = NULL;
+ aa_label_free(kernel_t);
destroy_ns(ns);
aa_put_ns(ns);
}