KVM guest_memfd is implementing its own inodes to store metadata for
backing memory using a custom filesystem. This requires the ability to
allocate an anonymous inode with security context using
anon_inode_make_secure_inode().

As guest_memfd currently resides in the KVM module, we need to export this
symbol for use outside the core kernel. In the future, guest_memfd might be
moved to core-mm, at which point the symbols no longer would have to be
exported. When/if that happens is still unclear.

Signed-off-by: Shivank Garg <shiva...@amd.com>
---

The handling of the S_PRIVATE flag for these inodes was discussed
extensively ([1], [2])
My understanding [3], is that because KVM guest_memfd and secretmem
results in user-visible file descriptors, its inodes should not bypass
LSM security checks. Therefore, anon_inode_make_secure_inode() (as
implemented in this patch) correctly clears the S_PRIVATE flag
set by alloc_anon_inode() to ensure proper security policy enforcement.

[1] https://lore.kernel.org/all/b9e5fa41-62fd-4b3d-bb2d-24ae9d3c3...@redhat.com
[2] https://lore.kernel.org/all/cover.1748890962.git.ackerley...@google.com
[3] https://lore.kernel.org/all/647ab7a4-790f-4858-acf2-0f6bae5b7...@amd.com

 fs/anon_inodes.c   | 20 +++++++++++++++++---
 include/linux/fs.h |  2 ++
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index e51e7d88980a..441fff40b55a 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -98,14 +98,26 @@ static struct file_system_type anon_inode_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 
-static struct inode *anon_inode_make_secure_inode(
+/**
+ * anon_inode_make_secure_inode - allocate an anonymous inode with security 
context
+ * @sb:                [in]    Superblock to allocate from
+ * @name:      [in]    Name of the class of the newfile (e.g., "secretmem")
+ * @context_inode:
+ *             [in]    Optional parent inode for security inheritance
+ *
+ * The function ensures proper security initialization through the LSM hook
+ * security_inode_init_security_anon().
+ *
+ * Return:     Pointer to new inode on success, ERR_PTR on failure.
+ */
+struct inode *anon_inode_make_secure_inode(struct super_block *sb,
        const char *name,
        const struct inode *context_inode)
 {
        struct inode *inode;
        int error;
 
-       inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
+       inode = alloc_anon_inode(sb);
        if (IS_ERR(inode))
                return inode;
        inode->i_flags &= ~S_PRIVATE;
@@ -118,6 +130,7 @@ static struct inode *anon_inode_make_secure_inode(
        }
        return inode;
 }
+EXPORT_SYMBOL_GPL(anon_inode_make_secure_inode);
 
 static struct file *__anon_inode_getfile(const char *name,
                                         const struct file_operations *fops,
@@ -132,7 +145,8 @@ static struct file *__anon_inode_getfile(const char *name,
                return ERR_PTR(-ENOENT);
 
        if (make_inode) {
-               inode = anon_inode_make_secure_inode(name, context_inode);
+               inode = anon_inode_make_secure_inode(anon_inode_mnt->mnt_sb,
+                                                    name, context_inode);
                if (IS_ERR(inode)) {
                        file = ERR_CAST(inode);
                        goto err;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 96c7925a6551..7ba45be0d7a0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3604,6 +3604,8 @@ extern int simple_write_begin(struct file *file, struct 
address_space *mapping,
 extern const struct address_space_operations ram_aops;
 extern int always_delete_dentry(const struct dentry *);
 extern struct inode *alloc_anon_inode(struct super_block *);
+extern struct inode *anon_inode_make_secure_inode(struct super_block *sb,
+       const char *name, const struct inode *context_inode);
 extern int simple_nosetlease(struct file *, int, struct file_lease **, void 
**);
 extern const struct dentry_operations simple_dentry_operations;
 
-- 
2.43.0


Reply via email to