summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-01-16 11:42:34 +0300
committerJohn Johansen <john.johansen@canonical.com>2017-01-16 12:18:28 +0300
commit73688d1ed0b8f800f312f7bc9d583463858da861 (patch)
tree41d58fc6558b4a07554da9dc3ff4db3a36d1ad59
parent5fd1b95fc9b96629d185f5fe3d9342fcff78eb30 (diff)
downloadlinux-73688d1ed0b8f800f312f7bc9d583463858da861.tar.xz
apparmor: refactor prepare_ns() and make usable from different views
prepare_ns() will need to be called from alternate views, and namespaces will need to be created via different interfaces. So refactor and allow specifying the view ns. Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r--security/apparmor/apparmorfs.c6
-rw-r--r--security/apparmor/include/policy.h3
-rw-r--r--security/apparmor/include/policy_ns.h4
-rw-r--r--security/apparmor/policy.c6
-rw-r--r--security/apparmor/policy_ns.c98
5 files changed, 79 insertions, 38 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 96a02ee9c499..2b48be2169cb 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -125,7 +125,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
error = PTR_ERR(data);
if (!IS_ERR(data)) {
- error = aa_replace_profiles(data, size, PROF_ADD);
+ error = aa_replace_profiles(__aa_current_profile()->ns, data,
+ size, PROF_ADD);
kvfree(data);
}
@@ -147,7 +148,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf,
data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
- error = aa_replace_profiles(data, size, PROF_REPLACE);
+ error = aa_replace_profiles(__aa_current_profile()->ns, data,
+ size, PROF_REPLACE);
kvfree(data);
}
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index da62d29d3992..1573cade8812 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -184,7 +184,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
const char *fqname, size_t n);
struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
-ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
+ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
+ bool noreplace);
ssize_t aa_remove_profiles(char *name, size_t size);
void __aa_profile_list_release(struct list_head *head);
diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h
index e4c876544adc..820d86d266fe 100644
--- a/security/apparmor/include/policy_ns.h
+++ b/security/apparmor/include/policy_ns.h
@@ -83,7 +83,9 @@ void aa_free_ns_kref(struct kref *kref);
struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
-struct aa_ns *aa_prepare_ns(const char *name);
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+ struct dentry *dir);
+struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name);
void __aa_remove_ns(struct aa_ns *ns);
static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 5d99fb7ac881..e02ab20b0a8d 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -731,6 +731,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
/**
* aa_replace_profiles - replace profile(s) on the profile list
+ * @view: namespace load is viewed from
* @udata: serialized data stream (NOT NULL)
* @size: size of the serialized data stream
* @noreplace: true if only doing addition, no replacement allowed
@@ -741,7 +742,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname,
*
* Returns: size of data consumed else error code on failure.
*/
-ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
+ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size,
+ bool noreplace)
{
const char *ns_name, *info = NULL;
struct aa_ns *ns = NULL;
@@ -756,7 +758,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
goto out;
/* released below */
- ns = aa_prepare_ns(ns_name);
+ ns = aa_prepare_ns(view, ns_name);
if (!ns) {
error = audit_policy(op, GFP_KERNEL, ns_name,
"failed to prepare namespace", -ENOMEM);
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index 8a5632f39751..f6cdc738ffcd 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -181,48 +181,82 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
return aa_findn_ns(root, name, strlen(name));
}
+static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
+ struct dentry *dir)
+{
+ struct aa_ns *ns;
+ int error;
+
+ AA_BUG(!parent);
+ AA_BUG(!name);
+ AA_BUG(!mutex_is_locked(&parent->lock));
+
+ ns = alloc_ns(parent->base.hname, name);
+ if (!ns)
+ return NULL;
+ mutex_lock(&ns->lock);
+ error = __aa_fs_ns_mkdir(ns, ns_subns_dir(parent), name);
+ if (error) {
+ AA_ERROR("Failed to create interface for ns %s\n",
+ ns->base.name);
+ mutex_unlock(&ns->lock);
+ aa_free_ns(ns);
+ return ERR_PTR(error);
+ }
+ ns->parent = aa_get_ns(parent);
+ list_add_rcu(&ns->base.list, &parent->sub_ns);
+ /* add list ref */
+ aa_get_ns(ns);
+ mutex_unlock(&ns->lock);
+
+ return ns;
+}
+
/**
- * aa_prepare_ns - find an existing or create a new namespace of @name
- * @name: the namespace to find or add (MAYBE NULL)
+ * aa_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
*
- * Returns: refcounted ns or NULL if failed to create one
+ * Returns: the a refcounted ns that has been add or an ERR_PTR
*/
-struct aa_ns *aa_prepare_ns(const char *name)
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+ struct dentry *dir)
{
- struct aa_ns *ns, *root;
+ struct aa_ns *ns;
- root = aa_current_profile()->ns;
+ AA_BUG(!mutex_is_locked(&parent->lock));
- mutex_lock(&root->lock);
+ /* try and find the specified ns */
+ /* released by caller */
+ ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
+ if (!ns)
+ ns = __aa_create_ns(parent, name, dir);
+ else
+ ns = ERR_PTR(-EEXIST);
- /* if name isn't specified the profile is loaded to the current ns */
- if (!name) {
- /* released by caller */
- ns = aa_get_ns(root);
- goto out;
- }
+ /* return ref */
+ return ns;
+}
+/**
+ * aa_prepare_ns - find an existing or create a new namespace of @name
+ * @parent: ns to treat as parent
+ * @name: the namespace to find or add (NOT NULL)
+ *
+ * Returns: refcounted namespace or PTR_ERR if failed to create one
+ */
+struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name)
+{
+ struct aa_ns *ns;
+
+ mutex_lock(&parent->lock);
/* try and find the specified ns and if it doesn't exist create it */
/* released by caller */
- ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name));
- if (!ns) {
- ns = alloc_ns(root->base.hname, name);
- if (!ns)
- goto out;
- if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) {
- AA_ERROR("Failed to create interface for ns %s\n",
- ns->base.name);
- aa_free_ns(ns);
- ns = NULL;
- goto out;
- }
- ns->parent = aa_get_ns(root);
- list_add_rcu(&ns->base.list, &root->sub_ns);
- /* add list ref */
- aa_get_ns(ns);
- }
-out:
- mutex_unlock(&root->lock);
+ ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
+ if (!ns)
+ ns = __aa_create_ns(parent, name, NULL);
+ mutex_unlock(&parent->lock);
/* return ref */
return ns;