Commit a71ada30 authored by John Johansen's avatar John Johansen

apparmor: add special .null file used to "close" fds at exec

Borrow the special null device file from selinux to "close" fds that
don't have sufficient permissions at exec time.
Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 34c426ac
...@@ -18,9 +18,12 @@ ...@@ -18,9 +18,12 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/mount.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <uapi/linux/major.h>
#include <linux/fs.h>
#include "include/apparmor.h" #include "include/apparmor.h"
#include "include/apparmorfs.h" #include "include/apparmorfs.h"
...@@ -352,6 +355,28 @@ static const struct file_operations aa_fs_seq_hash_fops = { ...@@ -352,6 +355,28 @@ static const struct file_operations aa_fs_seq_hash_fops = {
.release = single_release, .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 **/ /** fns to setup dynamic per profile/namespace files **/
void __aa_fs_profile_rmdir(struct aa_profile *profile) void __aa_fs_profile_rmdir(struct aa_profile *profile)
{ {
...@@ -825,6 +850,7 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = { ...@@ -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(".load", 0640, &aa_fs_profile_load),
AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), 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_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
AA_FS_DIR("features", aa_fs_entry_features), AA_FS_DIR("features", aa_fs_entry_features),
{ } { }
...@@ -934,6 +960,52 @@ void __init aa_destroy_aafs(void) ...@@ -934,6 +960,52 @@ void __init aa_destroy_aafs(void)
aafs_remove_dir(&aa_fs_entry); 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 * aa_create_aafs - create the apparmor security filesystem
* *
...@@ -962,7 +1034,11 @@ static int __init aa_create_aafs(void) ...@@ -962,7 +1034,11 @@ static int __init aa_create_aafs(void)
if (error) if (error)
goto 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 */ /* Report that AppArmor fs is enabled */
aa_info_message("AppArmor Filesystem Enabled"); aa_info_message("AppArmor Filesystem Enabled");
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#ifndef __AA_APPARMORFS_H #ifndef __AA_APPARMORFS_H
#define __AA_APPARMORFS_H #define __AA_APPARMORFS_H
extern struct path aa_null;
enum aa_fs_type { enum aa_fs_type {
AA_FS_TYPE_BOOLEAN, AA_FS_TYPE_BOOLEAN,
AA_FS_TYPE_STRING, AA_FS_TYPE_STRING,
......
...@@ -44,6 +44,7 @@ struct aa_ns_acct { ...@@ -44,6 +44,7 @@ struct aa_ns_acct {
* @sub_ns: list of namespaces under the current namespace. * @sub_ns: list of namespaces under the current namespace.
* @uniq_null: uniq value used for null learning profiles * @uniq_null: uniq value used for null learning profiles
* @uniq_id: a unique id count for the profiles in the namespace * @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 * @dents: dentries for the namespaces file entries in apparmorfs
* *
* An aa_ns defines the set profiles that are searched to determine which * An aa_ns defines the set profiles that are searched to determine which
...@@ -66,6 +67,7 @@ struct aa_ns { ...@@ -66,6 +67,7 @@ struct aa_ns {
struct list_head sub_ns; struct list_head sub_ns;
atomic_t uniq_null; atomic_t uniq_null;
long uniq_id; long uniq_id;
int level;
struct dentry *dents[AAFS_NS_SIZEOF]; struct dentry *dents[AAFS_NS_SIZEOF];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment