Setup securityfs with symlinks, directories, and files for IMA namespacing support. The same directory structure that IMA uses on the host is also created for the namespacing case. The securityfs file and directory ownerships cannot be set when the IMA namespace is initialized. Therefore, delay the setup of the file system to a later point when securityfs is in securityfs_fill_super. This filesystem can now be mounted as follows: mount -t securityfs /sys/kernel/security/ /sys/kernel/security/ The following directories, symlinks, and files are then available. $ ls -l sys/kernel/security/ total 0 lr--r--r--. 1 root root 0 Dec 2 00:18 ima -> integrity/ima drwxr-xr-x. 3 root root 0 Dec 2 00:18 integrity $ ls -l sys/kernel/security/ima/ total 0 -r--r-----. 1 root root 0 Dec 2 00:18 ascii_runtime_measurements -r--r-----. 1 root root 0 Dec 2 00:18 binary_runtime_measurements -rw-------. 1 root root 0 Dec 2 00:18 policy -r--r-----. 1 root root 0 Dec 2 00:18 runtime_measurements_count -r--r-----. 1 root root 0 Dec 2 00:18 violations Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> --- include/linux/ima.h | 17 ++++++++++++++++- security/inode.c | 12 +++++++++++- security/integrity/ima/ima_fs.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/include/linux/ima.h b/include/linux/ima.h index bfb978a7f8d5..a8017272d78d 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -66,6 +66,10 @@ static inline const char * const *arch_get_ima_policy(void) } #endif +extern int ima_fs_ns_init(struct user_namespace *user_ns, + struct dentry *root); +extern void ima_fs_ns_free_dentries(struct user_namespace *user_ns); + #else static inline enum hash_algo ima_get_current_hash_algo(void) { @@ -154,6 +158,15 @@ static inline int ima_measure_critical_data(const char *event_label, return -ENOENT; } +static inline int ima_fs_ns_init(struct user_namespace *ns, struct dentry *root) +{ + return 0; +} + +static inline void ima_fs_ns_free_dentries(struct user_namespace *user_ns) +{ +} + #endif /* CONFIG_IMA */ #ifndef CONFIG_IMA_KEXEC @@ -221,7 +234,8 @@ struct ima_h_table { }; enum { - IMAFS_DENTRY_DIR = 0, + IMAFS_DENTRY_INTEGRITY_DIR = 0, + IMAFS_DENTRY_DIR, IMAFS_DENTRY_SYMLINK, IMAFS_DENTRY_BINARY_RUNTIME_MEASUREMENTS, IMAFS_DENTRY_ASCII_RUNTIME_MEASUREMENTS, @@ -333,6 +347,7 @@ static inline struct ima_namespace *get_current_ns(void) { return &init_ima_ns; } + #endif /* CONFIG_IMA_NS */ #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) diff --git a/security/inode.c b/security/inode.c index 121ac1874dde..10ee20917f42 100644 --- a/security/inode.c +++ b/security/inode.c @@ -16,6 +16,7 @@ #include <linux/fs_context.h> #include <linux/mount.h> #include <linux/pagemap.h> +#include <linux/ima.h> #include <linux/init.h> #include <linux/namei.h> #include <linux/security.h> @@ -41,6 +42,7 @@ static const struct super_operations securityfs_super_operations = { static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr files[] = {{""}}; + struct user_namespace *ns = fc->user_ns; int error; error = simple_fill_super(sb, SECURITYFS_MAGIC, files); @@ -49,7 +51,10 @@ static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_op = &securityfs_super_operations; - return 0; + if (ns != &init_user_ns) + error = ima_fs_ns_init(ns, sb->s_root); + + return error; } static int securityfs_get_tree(struct fs_context *fc) @@ -69,6 +74,11 @@ static int securityfs_init_fs_context(struct fs_context *fc) static void securityfs_kill_super(struct super_block *sb) { + struct user_namespace *ns = sb->s_fs_info; + + if (ns != &init_user_ns) + ima_fs_ns_free_dentries(ns); + kill_litter_super(sb); } diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index e2cee1457aaa..ea366c8e68c6 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -447,8 +447,9 @@ static const struct file_operations ima_measure_policy_ops = { .llseek = generic_file_llseek, }; -static void ima_fs_ns_free_dentries(struct ima_namespace *ns) +void ima_fs_ns_free_dentries(struct user_namespace *user_ns) { + struct ima_namespace *ns = user_ns->ima_ns; int i; for (i = IMAFS_DENTRY_LAST - 1; i >= 0; i--) @@ -457,18 +458,36 @@ static void ima_fs_ns_free_dentries(struct ima_namespace *ns) memset(ns->dentry, 0, sizeof(ns->dentry)); } -static int __init ima_fs_ns_init(struct user_namespace *user_ns) +int ima_fs_ns_init(struct user_namespace *user_ns, + struct dentry *root) { struct ima_namespace *ns = user_ns->ima_ns; struct dentry *ima_dir; - ns->dentry[IMAFS_DENTRY_DIR] = securityfs_create_dir("ima", integrity_dir); + /* already initialized? */ + if (ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR]) + return 0; + + /* FIXME: update when evm and integrity are namespaced */ + if (user_ns != &init_user_ns) { + ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR] = + securityfs_create_dir("integrity", root); + if (IS_ERR(ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR])) { + ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR] = NULL; + return -1; + } + } else + ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR] = integrity_dir; + + ns->dentry[IMAFS_DENTRY_DIR] = + securityfs_create_dir("ima", + ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR]); if (IS_ERR(ns->dentry[IMAFS_DENTRY_DIR])) - return -1; + goto out; ima_dir = ns->dentry[IMAFS_DENTRY_DIR]; ns->dentry[IMAFS_DENTRY_SYMLINK] = - securityfs_create_symlink("ima", NULL, "integrity/ima", NULL); + securityfs_create_symlink("ima", root, "integrity/ima", NULL); if (IS_ERR(ns->dentry[IMAFS_DENTRY_SYMLINK])) goto out; @@ -508,11 +527,11 @@ static int __init ima_fs_ns_init(struct user_namespace *user_ns) return 0; out: - ima_fs_ns_free_dentries(ns); + ima_fs_ns_free_dentries(user_ns); return -1; } int __init ima_fs_init(void) { - return ima_fs_ns_init(&init_user_ns); + return ima_fs_ns_init(&init_user_ns, NULL); } -- 2.31.1