apparmor: add special .null file used to "close" fds at exec
authorJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 08:42:45 +0000 (00:42 -0800)
committerJohn Johansen <john.johansen@canonical.com>
Mon, 16 Jan 2017 09:18:35 +0000 (01:18 -0800)
Borrow the special null device file from selinux to "close" fds that
don't have sufficient permissions at exec time.

Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/apparmorfs.c
security/apparmor/include/apparmorfs.h
security/apparmor/include/policy_ns.h

index 5c000cb7ef8e1741c5669340f7b2594e138a1ffa..2501a65fe7d3001347681b83efd6f8bbcc7a9e7d 100644 (file)
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/capability.h>
 #include <linux/rcupdate.h>
+#include <uapi/linux/major.h>
+#include <linux/fs.h>
 
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
@@ -352,6 +355,28 @@ static const struct file_operations aa_fs_seq_hash_fops = {
        .release        = single_release,
 };
 
+static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v)
+{
+       struct aa_ns *ns = aa_current_profile()->ns;
+
+       seq_printf(seq, "%d\n", ns->level);
+
+       return 0;
+}
+
+static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file)
+{
+       return single_open(file, aa_fs_seq_show_ns_level, inode->i_private);
+}
+
+static const struct file_operations aa_fs_ns_level = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_open_ns_level,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /** fns to setup dynamic per profile/namespace files **/
 void __aa_fs_profile_rmdir(struct aa_profile *profile)
 {
@@ -825,6 +850,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = {
        AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
        AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
        AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
+       AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
        AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
        AA_FS_DIR("features", aa_fs_entry_features),
        { }
@@ -934,6 +960,52 @@ void __init aa_destroy_aafs(void)
        aafs_remove_dir(&aa_fs_entry);
 }
 
+
+#define NULL_FILE_NAME ".null"
+struct path aa_null;
+
+static int aa_mk_null_file(struct dentry *parent)
+{
+       struct vfsmount *mount = NULL;
+       struct dentry *dentry;
+       struct inode *inode;
+       int count = 0;
+       int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count);
+
+       if (error)
+               return error;
+
+       inode_lock(d_inode(parent));
+       dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
+       if (IS_ERR(dentry)) {
+               error = PTR_ERR(dentry);
+               goto out;
+       }
+       inode = new_inode(parent->d_inode->i_sb);
+       if (!inode) {
+               error = -ENOMEM;
+               goto out1;
+       }
+
+       inode->i_ino = get_next_ino();
+       inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO,
+                          MKDEV(MEM_MAJOR, 3));
+       d_instantiate(dentry, inode);
+       aa_null.dentry = dget(dentry);
+       aa_null.mnt = mntget(mount);
+
+       error = 0;
+
+out1:
+       dput(dentry);
+out:
+       inode_unlock(d_inode(parent));
+       simple_release_fs(&mount, &count);
+       return error;
+}
+
 /**
  * aa_create_aafs - create the apparmor security filesystem
  *
@@ -962,7 +1034,11 @@ static int __init aa_create_aafs(void)
        if (error)
                goto error;
 
-       /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
+       error = aa_mk_null_file(aa_fs_entry.dentry);
+       if (error)
+               goto error;
+
+       /* TODO: add default profile to apparmorfs */
 
        /* Report that AppArmor fs is enabled */
        aa_info_message("AppArmor Filesystem Enabled");
index 5626bd48d7cb27e801fc74a138a9680e90d21c44..eeeae5b0cc36ab02c73f51ca3a17c126a97f7721 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __AA_APPARMORFS_H
 #define __AA_APPARMORFS_H
 
+extern struct path aa_null;
+
 enum aa_fs_type {
        AA_FS_TYPE_BOOLEAN,
        AA_FS_TYPE_STRING,
index 820d86d266feecdb39cfc74264b3a37807cb7d51..89cffddd7e75c6ab5e55d29b71dcd0ff24fb1fd2 100644 (file)
@@ -44,6 +44,7 @@ struct aa_ns_acct {
  * @sub_ns: list of namespaces under the current namespace.
  * @uniq_null: uniq value used for null learning profiles
  * @uniq_id: a unique id count for the profiles in the namespace
+ * @level: level of ns within the tree hierarchy
  * @dents: dentries for the namespaces file entries in apparmorfs
  *
  * An aa_ns defines the set profiles that are searched to determine which
@@ -66,6 +67,7 @@ struct aa_ns {
        struct list_head sub_ns;
        atomic_t uniq_null;
        long uniq_id;
+       int level;
 
        struct dentry *dents[AAFS_NS_SIZEOF];
 };