Extend 'securityfs' for support of IMA namespacing so that each IMA (user) namespace can have its own front-end for showing the currently active policy, the measurement list, number of violations and so on. The filesystem can be mounted to the usual securityfs mount point like this: mount -t securityfs /sys/kernel/security /sys/kernel/security Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> --- include/linux/security.h | 8 +++++ include/linux/user_namespace.h | 1 + security/inode.c | 58 ++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index 7e0ba63b5dde..b5266bedef3f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1929,6 +1929,14 @@ struct dentry *securityfs_create_symlink(const char *name, const struct inode_operations *iops); extern void securityfs_remove(struct dentry *dentry); +enum { + SECURITYFS_NS_ADD, + SECURITYFS_NS_REMOVE, +}; + +extern int securityfs_register_ns_notifier(struct notifier_block *nb); +extern int securityfs_unregister_ns_notifier(struct notifier_block *nb); + #else /* CONFIG_SECURITYFS */ static inline struct dentry *securityfs_create_dir(const char *name, diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 89663e6e0e85..6b8bd060d8c4 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -105,6 +105,7 @@ struct user_namespace { #endif #ifdef CONFIG_SECURITYFS struct vfsmount *securityfs_mount; + bool securityfs_notifier_sent; #endif } __randomize_layout; diff --git a/security/inode.c b/security/inode.c index f1006cec6ce6..45211845fc31 100644 --- a/security/inode.c +++ b/security/inode.c @@ -18,6 +18,7 @@ #include <linux/pagemap.h> #include <linux/init.h> #include <linux/namei.h> +#include <linux/notifier.h> #include <linux/security.h> #include <linux/lsm_hooks.h> #include <linux/magic.h> @@ -25,6 +26,8 @@ static int securityfs_mount_count; +static BLOCKING_NOTIFIER_HEAD(securityfs_ns_notifier); + static void securityfs_free_inode(struct inode *inode) { if (S_ISLNK(inode->i_mode)) @@ -37,6 +40,32 @@ static const struct super_operations securityfs_super_operations = { .free_inode = securityfs_free_inode, }; +static struct file_system_type fs_type; + +static void securityfs_free_context(struct fs_context *fc) +{ + struct user_namespace *ns = fc->user_ns; + + if (ns == &init_user_ns || + ns->securityfs_notifier_sent) + return; + + ns->securityfs_notifier_sent = true; + + ns->securityfs_mount = vfs_kern_mount(&fs_type, SB_KERNMOUNT, + fs_type.name, NULL); + if (IS_ERR(ns->securityfs_mount)) { + printk(KERN_ERR "kern mount on securityfs ERROR: %ld\n", + PTR_ERR(ns->securityfs_mount)); + ns->securityfs_mount = NULL; + return; + } + + blocking_notifier_call_chain(&securityfs_ns_notifier, + SECURITYFS_NS_ADD, fc->user_ns); + mntput(ns->securityfs_mount); +} + static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr files[] = {{""}}; @@ -53,11 +82,12 @@ static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) static int securityfs_get_tree(struct fs_context *fc) { - return get_tree_single(fc, securityfs_fill_super); + return get_tree_keyed(fc, securityfs_fill_super, fc->user_ns); } static const struct fs_context_operations securityfs_context_ops = { .get_tree = securityfs_get_tree, + .free = securityfs_free_context, }; static int securityfs_init_fs_context(struct fs_context *fc) @@ -66,13 +96,37 @@ static int securityfs_init_fs_context(struct fs_context *fc) return 0; } +static void securityfs_kill_super(struct super_block *sb) +{ + struct user_namespace *ns = sb->s_fs_info; + + if (ns != &init_user_ns) + blocking_notifier_call_chain(&securityfs_ns_notifier, + SECURITYFS_NS_REMOVE, + sb->s_fs_info); + ns->securityfs_notifier_sent = false; + ns->securityfs_mount = NULL; + kill_litter_super(sb); +} + static struct file_system_type fs_type = { .owner = THIS_MODULE, .name = "securityfs", .init_fs_context = securityfs_init_fs_context, - .kill_sb = kill_litter_super, + .kill_sb = securityfs_kill_super, + .fs_flags = FS_USERNS_MOUNT, }; +int securityfs_register_ns_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&securityfs_ns_notifier, nb); +} + +int securityfs_unregister_ns_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&securityfs_ns_notifier, nb); +} + /** * securityfs_create_dentry - create a dentry in the securityfs filesystem * -- 2.31.1