[PATCH] Incremental for root dentry

From: James Bottomley
Date: Mon Dec 06 2021 - 15:27:00 EST


---
include/linux/ima.h | 2 +
include/linux/security.h | 8 ----
include/linux/user_namespace.h | 4 --
security/inode.c | 71 ++++++++++-----------------------
security/integrity/ima/ima_fs.c | 40 ++++---------------
5 files changed, 29 insertions(+), 96 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index cab5fc6caeb3..a6e93bb5ce8a 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -40,6 +40,8 @@ extern int ima_measure_critical_data(const char *event_label,
const char *event_name,
const void *buf, size_t buf_len,
bool hash, u8 *digest, size_t digest_len);
+extern int ima_fs_ns_init(struct user_namespace *ns, struct dentry *root);
+extern void ima_fs_ns_free_dentries(struct user_namespace *ns);

#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
extern void ima_appraise_parse_cmdline(void);
diff --git a/include/linux/security.h b/include/linux/security.h
index a34109c5e3ed..bbf44a466832 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1929,14 +1929,6 @@ 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 6b8bd060d8c4..5249db04d62b 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -103,10 +103,6 @@ struct user_namespace {
#ifdef CONFIG_IMA
struct ima_namespace *ima_ns;
#endif
-#ifdef CONFIG_SECURITYFS
- struct vfsmount *securityfs_mount;
- bool securityfs_notifier_sent;
-#endif
} __randomize_layout;

struct ucounts {
diff --git a/security/inode.c b/security/inode.c
index 45211845fc31..0b173792fbd3 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -16,18 +16,17 @@
#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/notifier.h>
#include <linux/security.h>
#include <linux/lsm_hooks.h>
#include <linux/magic.h>
#include <linux/user_namespace.h>

+static struct vfsmount *securityfs_mount;
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))
@@ -40,36 +39,11 @@ 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[] = {{""}};
int error;
+ struct user_namespace *ns = fc->user_ns;

error = simple_fill_super(sb, SECURITYFS_MAGIC, files);
if (error)
@@ -77,6 +51,10 @@ static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc)

sb->s_op = &securityfs_super_operations;

+ if (ns != &init_user_ns) {
+ ima_fs_ns_init(ns, sb->s_root);
+ }
+
return 0;
}

@@ -87,7 +65,6 @@ static int securityfs_get_tree(struct fs_context *fc)

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)
@@ -100,12 +77,10 @@ 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;
+ if (ns != &init_user_ns) {
+ ima_fs_ns_free_dentries(ns);
+ }
+
kill_litter_super(sb);
}

@@ -117,16 +92,6 @@ static struct file_system_type fs_type = {
.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
*
@@ -174,14 +139,18 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
pr_debug("securityfs: creating file '%s'\n",name);

if (ns == &init_user_ns) {
- error = simple_pin_fs(&fs_type, &ns->securityfs_mount,
+ error = simple_pin_fs(&fs_type, &securityfs_mount,
&securityfs_mount_count);
if (error)
return ERR_PTR(error);
}

- if (!parent)
- parent = ns->securityfs_mount->mnt_root;
+ if (!parent) {
+ if (ns == &init_user_ns)
+ parent = securityfs_mount->mnt_root;
+ else
+ return ERR_PTR(-EINVAL);
+ }

dir = d_inode(parent);

@@ -227,7 +196,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
out:
inode_unlock(dir);
if (ns == &init_user_ns)
- simple_release_fs(&ns->securityfs_mount,
+ simple_release_fs(&securityfs_mount,
&securityfs_mount_count);
return dentry;
}
@@ -371,7 +340,7 @@ void securityfs_remove(struct dentry *dentry)
}
inode_unlock(dir);
if (ns == &init_user_ns)
- simple_release_fs(&ns->securityfs_mount,
+ simple_release_fs(&securityfs_mount,
&securityfs_mount_count);
}
EXPORT_SYMBOL_GPL(securityfs_remove);
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index c17a6b7eeb95..fb29cb7b0384 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -446,9 +446,10 @@ 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)
{
int i;
+ struct ima_namespace *ns = user_ns->ima_ns;

for (i = IMAFS_DENTRY_LAST - 1; i >= 0; i--)
securityfs_remove(ns->dentry[i]);
@@ -456,7 +457,7 @@ static void ima_fs_ns_free_dentries(struct ima_namespace *ns)
memset(ns->dentry, 0, sizeof(ns->dentry));
}

-static int 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;
@@ -468,7 +469,7 @@ static int ima_fs_ns_init(struct user_namespace *user_ns)
/* FIXME: update when evm and integrity are namespaced */
if (user_ns != &init_user_ns)
ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR] =
- securityfs_create_dir("integrity", NULL);
+ securityfs_create_dir("integrity", root);
else
ns->dentry[IMAFS_DENTRY_INTEGRITY_DIR] = integrity_dir;

@@ -480,7 +481,7 @@ static int ima_fs_ns_init(struct user_namespace *user_ns)
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;

@@ -520,38 +521,11 @@ static int 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;
}

-static int ima_ns_notify(struct notifier_block *this, unsigned long msg,
- void *data)
-{
- int rc = 0;
- struct user_namespace *user_ns = data;
-
- switch (msg) {
- case SECURITYFS_NS_ADD:
- rc = ima_fs_ns_init(user_ns);
- break;
- case SECURITYFS_NS_REMOVE:
- ima_fs_ns_free_dentries(user_ns->ima_ns);
- break;
- }
- return rc;
-}
-
-static struct notifier_block ima_ns_notifier = {
- .notifier_call = ima_ns_notify,
-};
-
int ima_fs_init()
{
- int rc;
-
- rc = securityfs_register_ns_notifier(&ima_ns_notifier);
- if (rc)
- return rc;
-
- return ima_fs_ns_init(&init_user_ns);
+ return ima_fs_ns_init(&init_user_ns, NULL);
}
--
2.33.0