Use guest mem inodes instead of anonymous inodes
Subsystems (7)
cover Use guest mem inodes instead of anonymous inodes
Hi,
This small patch series makes guest_memfd use guest mem inodes instead of anonymous inodes and also includes some refactoring to expose a new function that allocates an inode and runs security checks.
This patch series will serve as a common base for some in-flight series:
* Add NUMA mempolicy support for KVM guest-memfd [1]
* New KVM ioctl to link a gmem inode to a new gmem file [2]
* Restricted mapping of guest_memfd at the host and arm64 support [3] aka shared/private conversion support for guest_memfd
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]/
[3] https://lore.kernel.org/all/[email protected]/
Ackerley Tng (2):
fs: Provide function that allocates a secure anonymous inode
KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
fs/anon_inodes.c | 22 ++++-- include/linux/fs.h | 1 + include/uapi/linux/magic.h | 1 + mm/secretmem.c | 9 +-- virt/kvm/guest_memfd.c | 134 +++++++++++++++++++++++++++++++------ virt/kvm/kvm_main.c | 7 +- virt/kvm/kvm_mm.h | 9 ++- 7 files changed, 143 insertions(+), 40 deletions(-)
base-commit: a5806cd506af5a7c19bcd596e4708b5c464bfd21 --
2.49.0.1204.g71687c7c1d-goog
PATCH 1/2 fs: Provide function that allocates a secure anonymous inode
The new function, alloc_anon_secure_inode(), returns an inode after running checks in security_inode_init_security_anon().
Also refactor secretmem's file creation process to use the new function.
--- fs/anon_inodes.c | 22 ++++++++++++++++------ include/linux/fs.h | 1 + mm/secretmem.c | 9 +-------- 3 files changed, 18 insertions(+), 14 deletions(-)
fs/anon_inodes.c +16 -6
@@ -55,17 +55,20 @@ static struct file_system_type anon_inode_fs_type = { .kill_sb = kill_anon_super, }; -static struct inode *anon_inode_make_secure_inode ( -const char *name, -const struct inode *context_inode) +static struct inode *anon_inode_make_secure_inode (struct super_block *s, +const char *name,const struct inode *context_inode, +bool fs_internal) {struct inode *inode;int error; - inode =alloc_anon_inode (anon_inode_mnt->mnt_sb); + inode =alloc_anon_inode (s);if (IS_ERR (inode))return inode; - inode->i_flags &= ~S_PRIVATE ; + +if (!fs_internal) + inode->i_flags &= ~S_PRIVATE ; + error =security_inode_init_security_anon (inode, &QSTR (name), context_inode);if (error) {
@@ -75,6 +78,12 @@ static struct inode *anon_inode_make_secure_inode(return inode; } +struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode); + static struct file *__anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags,
@@ -88,7 +97,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, false);if (IS_ERR (inode)) { file =ERR_CAST (inode); goto err;
include/linux/fs.h +1 -0
@@ -3550,6 +3550,7 @@ 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 *alloc_anon_secure_inode (struct super_block *,const char *);extern int simple_nosetlease (struct file *,int ,struct file_lease **,void **);extern const struct dentry_operations simple_dentry_operations;
mm/secretmem.c +1 -8
@@ -195,18 +195,11 @@ static struct file *secretmem_file_create(unsigned long flags)struct file *file;struct inode *inode;const char *anon_name ="[secretmem]" ; -int err; - inode =alloc_anon_inode (secretmem_mnt->mnt_sb); + inode =alloc_anon_secure_inode (secretmem_mnt->mnt_sb, anon_name);if (IS_ERR (inode))return ERR_CAST (inode); - err =security_inode_init_security_anon (inode, &QSTR (anon_name),NULL ); -if (err) { - file =ERR_PTR (err); - goto err_free_inode; - } - file =alloc_file_pseudo (inode, secretmem_mnt,"secretmem" ,O_RDWR , &secretmem_fops);if (IS_ERR (file))
--
2.49.0.1204.g71687c7c1d-goog
Re: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 9 lines · Ackerley Tng
The new function,
alloc_anon_secure_inode(), returns an inode after running checks insecurity_inode_init_security_anon().Also refactor secretmem's file creation process to use the new function.
Suggested-by David Hildenbrand <[email protected]>Signed-off-by Ackerley Tng <[email protected]>---
Not sure about the subject, "secure anon inode" is misleading, it's an anon inode where we gave security callbacks a chance to intervene, right?
maybe simply "fs: factor out anon inode creation + init security"
Signature · 3 lines
Cheers, David / dhildenb
Re: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
In reply to Ackerley Tngfs/anon_inodes.c static struct inode *anon_inode_make_secure_inode( · line 85
Quoted 5 lines · Ackerley Tng
fs/anon_inodes.c +5
-0+struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode);
What is "secure" about this inode?
A kerneldoc explaining that would probably help.
Quoted 1 line
+extern struct inode *alloc_anon_secure_inode(struct
super_block*, const char *);
No need for the extern here. Spelling out the parameter names in protypes is nice, though. (and fix the long line while you're at it).
Re: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 11 lines · Christoph Hellwig
fs/anon_inodes.c static struct inode *anon_inode_make_secure_inode( · line 85
Quoted 5 lines · Ackerley Tng
fs/anon_inodes.c +5
-0+struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode);What is "secure" about this inode?
A kerneldoc explaining that would probably help.
Hi Ackerley,
I had been working on the same based on David's suggestion and included kernel-doc for the new functions.
https://lore.kernel.org/linux-mm/[email protected]
Feel free to incorporate the documentation from my patches,
Happy to send it as a follow-up patch or you can grab it from my earlier version.
Thanks,
Shivank
Quoted 6 lines
Quoted 1 line
+extern struct inode *alloc_anon_secure_inode(struct
super_block*, const char *);No need for the extern here. Spelling out the parameter names in protypes is nice, though. (and fix the long line while you're at it).
Mike Rapoport
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
In reply to Ackerley Tng(added Paul Moore for selinux bits)
Quoted 84 lines · Ackerley Tng
The new function,
alloc_anon_secure_inode(), returns an inode after running checks insecurity_inode_init_security_anon().Also refactor secretmem's file creation process to use the new function.
Suggested-by David Hildenbrand <[email protected]>Signed-off-by Ackerley Tng <[email protected]>--- fs/anon_inodes.c | 22 ++++++++++++++++------ include/linux/fs.h | 1 + mm/secretmem.c | 9 +-------- 3 files changed, 18 insertions(+), 14 deletions(-)fs/anon_inodes.c +16
-6@@ -55,17 +55,20 @@ static struct file_system_type anon_inode_fs_type = { .kill_sb = kill_anon_super, }; -static struct inode *anon_inode_make_secure_inode ( -const char *name, -const struct inode *context_inode) +static struct inode *anon_inode_make_secure_inode (struct super_block *s, +const char *name,const struct inode *context_inode, +bool fs_internal) {struct inode *inode;int error; - inode =alloc_anon_inode (anon_inode_mnt->mnt_sb); + inode =alloc_anon_inode (s);if (IS_ERR (inode))return inode; - inode->i_flags &= ~S_PRIVATE ; + +if (!fs_internal) + inode->i_flags &= ~S_PRIVATE ; + error =security_inode_init_security_anon (inode, &QSTR (name), context_inode);if (error) {@@ -75,6 +78,12 @@ static struct inode *anon_inode_make_secure_inode(return inode; } +struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode); + static struct file *__anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags,@@ -88,7 +97,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, false);if (IS_ERR (inode)) { file =ERR_CAST (inode); goto err;include/linux/fs.h +1
-0@@ -3550,6 +3550,7 @@ 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 *alloc_anon_secure_inode (struct super_block *,const char *);extern int simple_nosetlease (struct file *,int ,struct file_lease **,void **);extern const struct dentry_operations simple_dentry_operations;mm/secretmem.c +0
-0
mm/secretmem.c static struct file *secretmem_file_create(unsigned long flags) · line 201
Quoted 9 lines
mm/secretmem.c +1
-2@@ -195,18 +195,11 @@ static struct file *secretmem_file_create(unsigned long flags)struct file *file;struct inode *inode;const char *anon_name ="[secretmem]" ; -int err; - inode =alloc_anon_inode (secretmem_mnt->mnt_sb); + inode =alloc_anon_secure_inode (secretmem_mnt->mnt_sb, anon_name);if (IS_ERR (inode))return ERR_CAST (inode);
I don't think we should not hide secretmem and guest_memfd inodes from selinux, so clearing S_PRIVATE for them is not needed and you can just drop fs_internal parameter in anon_inode_make_secure_inode()
Quoted 12 lines
mm/secretmem.c +0
-7- err =security_inode_init_security_anon (inode, &QSTR (anon_name),NULL ); -if (err) { - file =ERR_PTR (err); - goto err_free_inode; - } - file =alloc_file_pseudo (inode, secretmem_mnt,"secretmem" ,O_RDWR , &secretmem_fops);if (IS_ERR (file)) --2.49.0.1204.g71687c7c1d-goog
Signature · 2 lines
Sincerely yours, Mike.
Paul Moore
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 2 lines · Mike Rapoport
(added Paul Moore for selinux bits)
Thanks Mike.
I'm adding the LSM and SELinux lists too since there are others that will be interested as well.
Quoted 90 lines · Ackerley Tng
Quoted 89 lines
The new function,
alloc_anon_secure_inode(), returns an inode after running checks insecurity_inode_init_security_anon().Also refactor secretmem's file creation process to use the new function.
Suggested-by David Hildenbrand <[email protected]>Signed-off-by Ackerley Tng <[email protected]>--- fs/anon_inodes.c | 22 ++++++++++++++++------ include/linux/fs.h | 1 + mm/secretmem.c | 9 +-------- 3 files changed, 18 insertions(+), 14 deletions(-)fs/anon_inodes.c +16
-6@@ -55,17 +55,20 @@ static struct file_system_type anon_inode_fs_type = { .kill_sb = kill_anon_super, }; -static struct inode *anon_inode_make_secure_inode ( -const char *name, -const struct inode *context_inode) +static struct inode *anon_inode_make_secure_inode (struct super_block *s, +const char *name,const struct inode *context_inode, +bool fs_internal) {struct inode *inode;int error; - inode =alloc_anon_inode (anon_inode_mnt->mnt_sb); + inode =alloc_anon_inode (s);if (IS_ERR (inode))return inode; - inode->i_flags &= ~S_PRIVATE ; + +if (!fs_internal) + inode->i_flags &= ~S_PRIVATE ; + error =security_inode_init_security_anon (inode, &QSTR (name), context_inode);if (error) {@@ -75,6 +78,12 @@ static struct inode *anon_inode_make_secure_inode(return inode; } +struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode); + static struct file *__anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags,@@ -88,7 +97,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, false);if (IS_ERR (inode)) { file =ERR_CAST (inode); goto err;include/linux/fs.h +1
-0@@ -3550,6 +3550,7 @@ 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 *alloc_anon_secure_inode (struct super_block *,const char *);extern int simple_nosetlease (struct file *,int ,struct file_lease **,void **);extern const struct dentry_operations simple_dentry_operations;mm/secretmem.c +0
-1@@ -195,18 +195,11 @@ static struct file *secretmem_file_create(unsigned long flags)struct file *file;struct inode *inode;const char *anon_name ="[secretmem]" ; -int err;
Quoted 8 lines
mm/secretmem.c static struct file *secretmem_file_create(unsigned long flags) · line 201
Quoted 4 lines
mm/secretmem.c +1
-1- inode =alloc_anon_inode (secretmem_mnt->mnt_sb); + inode =alloc_anon_secure_inode (secretmem_mnt->mnt_sb, anon_name);if (IS_ERR (inode))return ERR_CAST (inode);I don't think we should not hide secretmem and
guest_memfdinodes from selinux, so clearingS_PRIVATEfor them is not needed and you can just dropfs_internalparameter inanon_inode_make_secure_inode()
It's especially odd since I don't see any comments or descriptions about why this is being done. The secretmem change is concerning as this is user accessible and marking the inode with S_PRIVATE will bypass a number of LSM/SELinux access controls, possibly resulting in a security regression (one would need to dig a bit deeper to see what is possible with secretmem and which LSM/SELinux code paths would be affected).
I'm less familiar with guest_memfd, but generally speaking if userspace can act on the inode/fd then we likely don't want the S_PRIVATE flag stripped from the anon_inode.
Ackerley can you provide an explanation about why the change in S_PRIVATE was necessary?
Quoted 11 lines
Quoted 11 lines
mm/secretmem.c +0
-7- err =security_inode_init_security_anon (inode, &QSTR (anon_name),NULL ); -if (err) { - file =ERR_PTR (err); - goto err_free_inode; - } - file =alloc_file_pseudo (inode, secretmem_mnt,"secretmem" ,O_RDWR , &secretmem_fops);if (IS_ERR (file)) --2.49.0.1204.g71687c7c1d-goog
Signature · 1 line
paul-moore.com
Mike Rapoport
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 108 lines · Paul Moore
Quoted 2 lines · Mike Rapoport
(added Paul Moore for selinux bits)
Thanks Mike.
I'm adding the LSM and SELinux lists too since there are others that will be interested as well.
Quoted 90 lines · Ackerley Tng
Quoted 89 lines
The new function,
alloc_anon_secure_inode(), returns an inode after running checks insecurity_inode_init_security_anon().Also refactor secretmem's file creation process to use the new function.
Suggested-by David Hildenbrand <[email protected]>Signed-off-by Ackerley Tng <[email protected]>--- fs/anon_inodes.c | 22 ++++++++++++++++------ include/linux/fs.h | 1 + mm/secretmem.c | 9 +-------- 3 files changed, 18 insertions(+), 14 deletions(-)fs/anon_inodes.c +16
-6@@ -55,17 +55,20 @@ static struct file_system_type anon_inode_fs_type = { .kill_sb = kill_anon_super, }; -static struct inode *anon_inode_make_secure_inode ( -const char *name, -const struct inode *context_inode) +static struct inode *anon_inode_make_secure_inode (struct super_block *s, +const char *name,const struct inode *context_inode, +bool fs_internal) {struct inode *inode;int error; - inode =alloc_anon_inode (anon_inode_mnt->mnt_sb); + inode =alloc_anon_inode (s);if (IS_ERR (inode))return inode; - inode->i_flags &= ~S_PRIVATE ; + +if (!fs_internal) + inode->i_flags &= ~S_PRIVATE ; + error =security_inode_init_security_anon (inode, &QSTR (name), context_inode);if (error) {@@ -75,6 +78,12 @@ static struct inode *anon_inode_make_secure_inode(return inode; } +struct inode *alloc_anon_secure_inode (struct super_block *s,const char *name) +{ +return anon_inode_make_secure_inode (s, name,NULL , true); +} +EXPORT_SYMBOL_GPL (alloc_anon_secure_inode); + static struct file *__anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags,@@ -88,7 +97,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, false);if (IS_ERR (inode)) { file =ERR_CAST (inode); goto err;include/linux/fs.h +1
-0@@ -3550,6 +3550,7 @@ 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 *alloc_anon_secure_inode (struct super_block *,const char *);extern int simple_nosetlease (struct file *,int ,struct file_lease **,void **);extern const struct dentry_operations simple_dentry_operations;mm/secretmem.c +0
-1@@ -195,18 +195,11 @@ static struct file *secretmem_file_create(unsigned long flags)struct file *file;struct inode *inode;const char *anon_name ="[secretmem]" ; -int err;Quoted 8 lines
mm/secretmem.c static struct file *secretmem_file_create(unsigned long flags) · line 201
Quoted 4 lines
mm/secretmem.c +1
-1- inode =alloc_anon_inode (secretmem_mnt->mnt_sb); + inode =alloc_anon_secure_inode (secretmem_mnt->mnt_sb, anon_name);if (IS_ERR (inode))return ERR_CAST (inode);I don't think we should not hide secretmem and
guest_memfdinodes from selinux, so clearingS_PRIVATEfor them is not needed and you can just dropfs_internalparameter inanon_inode_make_secure_inode()
Quoted 7 lines
It's especially odd since I don't see any comments or descriptions about why this is being done. The secretmem change is concerning as this is user accessible and marking the inode with
S_PRIVATEwill bypass a number of LSM/SELinux access controls, possibly resulting in a security regression (one would need to dig a bit deeper to see what is possible with secretmem and which LSM/SELinux code paths would be affected).
secretmem always had S_PRIVATE set because alloc_anon_inode() clears it anyway and this patch does not change it.
I'm just thinking that it makes sense to actually allow LSM/SELinux controls that S_PRIVATE bypasses for both secretmem and guest_memfd.
Signature · 2 lines
Sincerely yours, Mike.
Paul Moore
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 3 lines · Mike Rapoport
secretmem always had
S_PRIVATEset becausealloc_anon_inode()clears it anyway and this patch does not change it.
Yes, my apologies, I didn't look closely enough at the code.
Quoted 2 lines
I'm just thinking that it makes sense to actually allow LSM/SELinux controls that
S_PRIVATEbypasses for both secretmem andguest_memfd.
It's been a while since we added the anon_inode hooks so I'd have to go dig through the old thread to understand the logic behind marking secretmem S_PRIVATE, especially when the anon_inode_make_secure_inode() function cleared it. It's entirely possible it may have just been an oversight.
Signature · 1 line
paul-moore.com
Re: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 7 lines · Paul Moore
Quoted 3 lines · Mike Rapoport
secretmem always had
S_PRIVATEset becausealloc_anon_inode()clears it anyway and this patch does not change it.Yes, my apologies, I didn't look closely enough at the code.
Quoted 8 lines
Quoted 2 lines
I'm just thinking that it makes sense to actually allow LSM/SELinux controls that
S_PRIVATEbypasses for both secretmem andguest_memfd.It's been a while since we added the
anon_inodehooks so I'd have to go dig through the old thread to understand the logic behind marking secretmemS_PRIVATE, especially when theanon_inode_make_secure_inode()function cleared it. It's entirely possible it may have just been an oversight.
I'm jumping in where I don't know what I'm talking about...
But my reading of the S_PRIVATE flag is that the memory can't be mapped by user space. So for guest_memfd() we need !S_PRIVATE because it is intended to be mapped by user space. So we want the secure checks.
I think secretmem is the same.
Do I have that right?
Ira
[snip]
Re: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 19 lines · Ira Weiny
Quoted 7 lines · Paul Moore
Quoted 3 lines · Mike Rapoport
secretmem always had
S_PRIVATEset becausealloc_anon_inode()clears it anyway and this patch does not change it.Yes, my apologies, I didn't look closely enough at the code.
Quoted 8 lines
Quoted 2 lines
I'm just thinking that it makes sense to actually allow LSM/SELinux controls that
S_PRIVATEbypasses for both secretmem andguest_memfd.It's been a while since we added the
anon_inodehooks so I'd have to go dig through the old thread to understand the logic behind marking secretmemS_PRIVATE, especially when theanon_inode_make_secure_inode()function cleared it. It's entirely possible it may have just been an oversight.I'm jumping in where I don't know what I'm talking about...
Quoted 7 lines
But my reading of the
S_PRIVATEflag is that the memory can't be mapped by user space. So forguest_memfd()we need !S_PRIVATE because it is intended to be mapped by user space. So we want the secure checks.I think secretmem is the same.
Do I have that right?
Hi Mike, Paul,
If I understand correctly,
we need to clear the S_PRIVATE flag for all secure inodes. The S_PRIVATE flag was previously set for secretmem (via alloc_anon_inode()), which caused security checks to be bypassed - this was unintentional since the original anon_inode_make_secure_inode() was already clearing it.
Both secretmem and guest_memfd create file descriptors (memfd_create/kvm_create_guest_memfd)
so they should be subject to LSM/SELinux security policies rather than bypassing them with S_PRIVATE?
static struct inode *anon_inode_make_secure_inode(struct super_block *s,
const char *name, const struct inode *context_inode)
{
...
/* Clear S_PRIVATE for all inodes*/ inode->i_flags &= ~S_PRIVATE;
...
}
Please let me know if this conclusion makes sense?
Thanks,
Shivank
Quoted 5 lines
Ira
[snip]
Mike Rapoport
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
Quoted 11 lines · Shivank Garg
Quoted 8 lines · Ira Weiny
Quoted 7 lines · Paul Moore
Quoted 3 lines · Mike Rapoport
secretmem always had
S_PRIVATEset becausealloc_anon_inode()clears it anyway and this patch does not change it.Yes, my apologies, I didn't look closely enough at the code.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
I'm just thinking that it makes sense to actually allow LSM/SELinux controls that
S_PRIVATEbypasses for both secretmem andguest_memfd.It's been a while since we added the
anon_inodehooks so I'd have to go dig through the old thread to understand the logic behind marking secretmemS_PRIVATE, especially when theanon_inode_make_secure_inode()function cleared it. It's entirely possible it may have just been an oversight.
anon_inode_make_secure_inode() was introduced when more than 10 versions of secretmem already were posted so it didn't jump at me to replace alloc_anon_inode() with anon_inode_make_secure_inode().
Quoted 7 lines
Quoted 7 lines
I'm jumping in where I don't know what I'm talking about...
But my reading of the
S_PRIVATEflag is that the memory can't be mapped by user space. So forguest_memfd()we need !S_PRIVATE because it is intended to be mapped by user space. So we want the secure checks.I think secretmem is the same.
Agree.
Quoted 19 lines
Quoted 1 line
Do I have that right?
Hi Mike, Paul,
If I understand correctly,
we need to clear theS_PRIVATEflag for all secure inodes. TheS_PRIVATEflag was previously set for secretmem (viaalloc_anon_inode()), which caused security checks to be bypassed - this was unintentional since the originalanon_inode_make_secure_inode()was already clearing it.Both secretmem and
guest_memfdcreate file descriptors (memfd_create/kvm_create_guest_memfd)
so they should be subject to LSM/SELinux security policies rather than bypassing them withS_PRIVATE?static struct inode *anon_inode_make_secure_inode(struct
super_block*s,
const char *name, const struct inode*context_inode)
{
...
Quoted 6 lines
/* Clear S_PRIVATE for all inodes*/ inode->i_flags &= ~S_PRIVATE;...
}Please let me know if this conclusion makes sense?
Yes, makes sense to me.
Quoted 2 lines
Thanks,
Shivank
Signature · 2 lines
Sincerely yours, Mike.
Christian Brauner
maintainerRe: [PATCH 1/2] fs: Provide function that allocates a secure anonymous inode
In reply to Ackerley TngQuoted 9 lines · Ackerley Tng
The new function,
alloc_anon_secure_inode(), returns an inode after running checks insecurity_inode_init_security_anon().Also refactor secretmem's file creation process to use the new function.
Suggested-by David Hildenbrand <[email protected]>Signed-off-by Ackerley Tng <[email protected]>---
Once -rc1 is out I'll pull the VFS bits and provide a branch that remains stable for the duration of v6.16 development that can be pulled.
PATCH 2/2 KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
In reply to Ackerley Tngguest_memfd's inode represents memory the guest_memfd is providing. guest_memfd's file represents a struct kvm's view of that memory.
Using a custom inode allows customization of the inode teardown process via callbacks. For example, ->evict_inode() allows customization of the truncation process on file close, and ->destroy_inode() and ->free_inode() allow customization of the inode freeing process.
Customizing the truncation process allows flexibility in management of guest_memfd memory and customization of the inode freeing process allows proper cleanup of memory metadata stored on the inode.
Memory metadata is more appropriately stored on the inode (as opposed to the file), since the metadata is for the memory and is not unique to a specific binding and struct kvm.
--- include/uapi/linux/magic.h | 1 + virt/kvm/guest_memfd.c | 134 +++++++++++++++++++++++++++++++------ virt/kvm/kvm_main.c | 7 +- virt/kvm/kvm_mm.h | 9 ++- 4 files changed, 125 insertions(+), 26 deletions(-)
include/uapi/linux/magic.h +1 -0
@@ -103,5 +103,6 @@#define DEVMEM_MAGIC 0x454d444d/* "DMEM" */ #define SECRETMEM_MAGIC 0x5345434d/* "SECM" */ #define PID_FS_MAGIC 0x50494446/* "PIDF" */ +#define GUEST_MEMFD_MAGIC 0x474d454d/* "GMEM" */ #endif /* __LINUX_MAGIC_H__ */
virt/kvm/guest_memfd.c +112 -22
176 lines not on this page · raw message
virt/kvm/kvm_main.c +6 -1
@@ -6420,7 +6420,9 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)if (WARN_ON_ONCE (r)) goto err_vfio; -kvm_gmem_init (module); + r =kvm_gmem_init (module); +if (r) + goto err_gmem; r =kvm_init_virtualization ();if (r)
@@ -6441,6 +6443,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) err_register:kvm_uninit_virtualization (); err_virt: +kvm_gmem_exit (); +err_gmem:kvm_vfio_ops_exit (); err_vfio:kvm_async_pf_deinit ();
@@ -6472,6 +6476,7 @@ void kvm_exit(void)for_each_possible_cpu (cpu)free_cpumask_var (per_cpu (cpu_kick_mask, cpu));kmem_cache_destroy (kvm_vcpu_cache); +kvm_gmem_exit ();kvm_vfio_ops_exit ();kvm_async_pf_deinit ();kvm_irqfd_exit ();
virt/kvm/kvm_mm.h +6 -3
@@ -68,17 +68,20 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,#endif /* HAVE_KVM_PFNCACHE */ #ifdef CONFIG_KVM_PRIVATE_MEM -void kvm_gmem_init (struct module *module); +int kvm_gmem_init (struct module *module); +void kvm_gmem_exit (void );int kvm_gmem_create (struct kvm *kvm,struct kvm_create_guest_memfd *args);int kvm_gmem_bind (struct kvm *kvm,struct kvm_memory_slot *slot,unsigned int fd,loff_t offset);void kvm_gmem_unbind (struct kvm_memory_slot *slot);#else -static inline void kvm_gmem_init (struct module *module) +static inline int kvm_gmem_init (struct module *module) { - +return 0 ; } +static inline void kvm_gmem_exit (void ) {}; +static inline int kvm_gmem_bind (struct kvm *kvm,struct kvm_memory_slot *slot,unsigned int fd,loff_t offset)
--
2.49.0.1204.g71687c7c1d-goog
Re: [PATCH 2/2] KVM: guest_memfd: Use guest mem inodes instead of anonymous inodes
Quoted 14 lines · Ackerley Tng
guest_memfd's inode represents memory the
guest_memfdis providing. guest_memfd's file represents a struct kvm's view of that memory.Using a custom inode allows customization of the inode teardown process via callbacks. For example, ->evict_inode() allows customization of the truncation process on file close, and ->destroy_inode() and ->free_inode() allow customization of the inode freeing process.
Customizing the truncation process allows flexibility in management of
guest_memfdmemory and customization of the inode freeing process allows proper cleanup of memory metadata stored on the inode.
Quoted 6 lines
Memory metadata is more appropriately stored on the inode (as opposed to the file), since the metadata is for the memory and is not unique to a specific binding and struct kvm.
Signed-off-by Ackerley Tng <[email protected]>Signed-off-by Fuad Tabba <[email protected]>
The trailing SOB from Fuag is likely wrong. Probably you wnat
Quoted 64 lines
--- include/uapi/linux/magic.h | 1 + virt/kvm/guest_memfd.c | 134 +++++++++++++++++++++++++++++++------ virt/kvm/kvm_main.c | 7 +- virt/kvm/kvm_mm.h | 9 ++- 4 files changed, 125 insertions(+), 26 deletions(-)include/uapi/linux/magic.h +1
-0@@ -103,5 +103,6 @@#define DEVMEM_MAGIC 0x454d444d/* "DMEM" */ #define SECRETMEM_MAGIC 0x5345434d/* "SECM" */ #define PID_FS_MAGIC 0x50494446/* "PIDF" */ +#define GUEST_MEMFD_MAGIC 0x474d454d/* "GMEM" */ #endif /* __LINUX_MAGIC_H__ */ virt/kvm/guest_memfd.c +24
-2@@ -1,12 +1,16 @@// SPDX-License-Identifier: GPL-2.0 +#include <linux/anon_inodes.h> #include <linux/backing-dev.h> #include <linux/falloc.h> +#include <linux/fs.h> #include <linux/kvm_host.h> +#include <linux/pseudo_fs.h> #include <linux/pagemap.h> -#include <linux/anon_inodes.h> #include "kvm_mm.h" +static struct vfsmount *kvm_gmem_mnt; +struct kvm_gmem {struct kvm *kvm;struct xarray bindings;@@ -318,9 +322,51 @@ static struct file_operations kvm_gmem_fops = { .fallocate = kvm_gmem_fallocate, }; -void kvm_gmem_init (struct module *module) +static const struct super_operations kvm_gmem_super_operations = { + .statfs = simple_statfs, +}; + +static int kvm_gmem_init_fs_context (struct fs_context *fc) +{ +struct pseudo_fs_context *ctx; + +if (!init_pseudo (fc,GUEST_MEMFD_MAGIC )) +return -ENOMEM ; + + ctx = fc->fs_private; + ctx->ops = &kvm_gmem_super_operations; + +return 0 ; +} + +static struct file_system_type kvm_gmem_fs = { + .name ="kvm_guest_memory" ,
virt/kvm/guest_memfd.c static struct file_operations kvm_gmem_fops = { · line 353
Quoted 10 lines
virt/kvm/guest_memfd.c +10
-0+ .init_fs_context = kvm_gmem_init_fs_context, + .kill_sb = kill_anon_super, +}; + +static int kvm_gmem_init_mount (void ) +{ + kvm_gmem_mnt =kern_mount (&kvm_gmem_fs); + +if (WARN_ON_ONCE (IS_ERR (kvm_gmem_mnt))) +return PTR_ERR (kvm_gmem_mnt);
Hmm, is this WARN_ON_ONCE really warrented?
Nothing else jumped at me. I hope some fs experts can take a look as well.
Signature · 3 lines
Cheers, David / dhildenb