diff options
author | John Johansen <john.johansen@canonical.com> | 2017-05-26 16:45:48 -0700 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-10 17:11:27 -0700 |
commit | 4ae47f33354a96efb4e4231dec0d72a586b3921c (patch) | |
tree | 9d75fc20d9fd75333595aaa17e738087aa6912dc | |
parent | d9bf2c268be6064ae0c9980e4c37fdd262c7effc (diff) |
apparmor: add mkdir/rmdir interface to manage policy namespaces
When setting up namespaces for containers its easier for them to use
an fs interface to create the namespace for the containers
policy. Allow mkdir/rmdir under the policy/namespaces/ dir to be used
to create and remove namespaces.
BugLink: http://bugs.launchpad.net/bugs/1611078
Signed-off-by: John Johansen <john.johansen@canonical.com>
-rw-r--r-- | security/apparmor/apparmorfs.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 8c413333726b..7f3049300ce3 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1322,6 +1322,97 @@ fail2: return error; } +static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + struct aa_ns *ns, *parent; + /* TODO: improve permission check */ + struct aa_profile *profile = aa_current_profile(); + int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); + + if (error) + return error; + + parent = aa_get_ns(dir->i_private); + AA_BUG(d_inode(ns_subns_dir(parent)) != dir); + + /* we have to unlock and then relock to get locking order right + * for pin_fs + */ + inode_unlock(dir); + error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count); + mutex_lock(&parent->lock); + inode_lock_nested(dir, I_MUTEX_PARENT); + if (error) + goto out; + + error = __aafs_setup_d_inode(dir, dentry, mode | S_IFDIR, NULL, + NULL, NULL, NULL); + if (error) + goto out_pin; + + ns = __aa_find_or_create_ns(parent, READ_ONCE(dentry->d_name.name), + dentry); + if (IS_ERR(ns)) { + error = PTR_ERR(ns); + ns = NULL; + } + + aa_put_ns(ns); /* list ref remains */ +out_pin: + if (error) + simple_release_fs(&aafs_mnt, &aafs_count); +out: + mutex_unlock(&parent->lock); + aa_put_ns(parent); + + return error; +} + +static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) +{ + struct aa_ns *ns, *parent; + /* TODO: improve permission check */ + struct aa_profile *profile = aa_current_profile(); + int error = aa_may_manage_policy(profile, NULL, AA_MAY_LOAD_POLICY); + + if (error) + return error; + + parent = aa_get_ns(dir->i_private); + /* rmdir calls the generic securityfs functions to remove files + * from the apparmor dir. It is up to the apparmor ns locking + * to avoid races. + */ + inode_unlock(dir); + inode_unlock(dentry->d_inode); + + mutex_lock(&parent->lock); + ns = aa_get_ns(__aa_findn_ns(&parent->sub_ns, dentry->d_name.name, + dentry->d_name.len)); + if (!ns) { + error = -ENOENT; + goto out; + } + AA_BUG(ns_dir(ns) != dentry); + + __aa_remove_ns(ns); + aa_put_ns(ns); + +out: + mutex_unlock(&parent->lock); + inode_lock_nested(dir, I_MUTEX_PARENT); + inode_lock(dentry->d_inode); + aa_put_ns(parent); + + return error; +} + +static const struct inode_operations ns_dir_inode_operations = { + .lookup = simple_lookup, + .mkdir = ns_mkdir_op, + .rmdir = ns_rmdir_op, +}; + static void __aa_fs_list_remove_rawdata(struct aa_ns *ns) { struct aa_loaddata *ent, *tmp; @@ -1429,7 +1520,9 @@ static int __aafs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir) aa_get_ns(ns); ns_subremove(ns) = dent; - dent = aafs_create_dir("namespaces", dir); + /* use create_dentry so we can supply private data */ + dent = aafs_create("namespaces", S_IFDIR | 0755, dir, ns, NULL, NULL, + &ns_dir_inode_operations); if (IS_ERR(dent)) return PTR_ERR(dent); aa_get_ns(ns); |