[PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state
Pratyush Yadav
pratyush at kernel.org
Tue Oct 27 07:41:34 PDT 2026
Hi David,
On Tue, Oct 27 2026, David Hildenbrand (Arm) wrote:
> shmem_file() only checks a file's backing mapping. That mapping can belong
> to another file, as with a Coda file backed by a tmpfs container after
> mmap(). It does not establish that file_inode(file) is a shmem inode.
>
> Seal handling and memfd preservation use this check before accessing
> shmem inode state, so they can access an inode of the wrong type.
>
> Add file_inode_is_shmem() to check the inode's file operations in both
> paths. This identifies regular shmem inodes, including those used by
> memfds and ordinary tmpfs files, independently of wrapper file operations.
Why not update shmem_file() to do this check instead? Having a
shmem_file() that might not always return the right result on a file
seems like a landmine.
For example, you missed check_memfd_seals() in udmabuf or
memfd_pin_folios() in gup. Plus, someone later down the line might use
shmem_file() without knowing this subtle problem, and we probably would
miss it in review.
For callers that only care about the mapping should then use
shmem_mapping(). Perhaps that would be collapse_file() but TBH I don't
really understand khugepaged all that much. All other callers of
shmem_file() seem to care about the actual inode.
>
> Fixes: c49fcfcda8b5 ("mm/shmem: update file sealing comments and file checking")
> Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd")
> Cc: stable at vger.kernel.org
> Reported-by: Chris Mason <mason at kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david at kernel.org>
> ---
> include/linux/shmem_fs.h | 6 ++++++
> mm/memfd.c | 8 +++++---
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 5 +++++
> 4 files changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index a7c7a96a7cbf9..2ceca7993e4f5 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -117,8 +117,14 @@ extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
> unsigned long len, unsigned long pgoff, unsigned long flags);
> extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
> #ifdef CONFIG_SHMEM
> +bool file_inode_is_shmem(const struct inode *inode);
> bool shmem_mapping(const struct address_space *mapping);
> #else
> +static inline bool file_inode_is_shmem(const struct inode *inode)
> +{
> + return false;
> +}
> +
> static inline bool shmem_mapping(const struct address_space *mapping)
> {
> return false;
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 0f6fff004f5e4..7d2da23157003 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -211,12 +211,14 @@ static int memfd_wait_for_pins(struct address_space *mapping)
>
> static unsigned int *memfd_file_seals_ptr(struct file *file)
> {
> - if (shmem_file(file))
> - return &SHMEM_I(file_inode(file))->seals;
> + struct inode *inode = file_inode(file);
> +
> + if (file_inode_is_shmem(inode))
> + return &SHMEM_I(inode)->seals;
>
> #ifdef CONFIG_HUGETLBFS
> if (is_file_hugepages(file))
> - return &HUGETLBFS_I(file_inode(file))->seals;
> + return &HUGETLBFS_I(inode)->seals;
> #endif
>
> return NULL;
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index 59de210bee5f9..c0811407ce397 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -582,7 +582,7 @@ static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
> {
> struct inode *inode = file_inode(file);
>
> - return shmem_file(file) && !inode->i_nlink;
> + return file_inode_is_shmem(inode) && !inode->i_nlink;
> }
>
> static unsigned long memfd_luo_get_id(struct file *file)
> diff --git a/mm/shmem.c b/mm/shmem.c
> index fadf23f9e21ed..0d41aac125df9 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -275,6 +275,11 @@ static const struct vm_operations_struct shmem_vm_ops;
> static const struct vm_operations_struct shmem_anon_vm_ops;
> static struct file_system_type shmem_fs_type;
>
> +bool file_inode_is_shmem(const struct inode *inode)
> +{
> + return inode->i_fop == &shmem_file_operations;
> +}
> +
> bool shmem_mapping(const struct address_space *mapping)
> {
> return mapping->a_ops == &shmem_aops;
--
Regards,
Pratyush Yadav
More information about the kexec
mailing list