memfd_luo_can_preserve() accepts any unlinked shmem file. That includes SysV SHM files, which are created with shmem_kernel_file_setup() and marked S_PRIVATE: a privileged process can obtain a file descriptor for an attached segment through /proc//map_files and hand that descriptor to LUO. The preservation path then updates SHMEM_I(inode)->flags under the inode lock when it sets SHMEM_F_MAPPING_FROZEN, while SHM_LOCK and SHM_UNLOCK update the same word through shmem_lock(), serialized by ipc_lock_object() instead. Two read-modify-write cycles on one word with no common lock can lose either the LUO frozen bit or SHMEM_F_LOCKED, so the frozen state the handler depends on may quietly not be in effect. The seal-state freeze this series adds (SHMEM_F_SEAL_STATE_FROZEN) has the same synchronization requirement. Reject S_PRIVATE shmem inodes from the memfd LUO handler. Real memfds are created with shmem_file_setup() without S_PRIVATE, while shmem_kernel_file_setup() deliberately uses the flag for kernel-private objects: SysV SHM, big_key payloads, the XFS buffer and scrub files, and the anonymous /dev/zero mapping file. Those must not be preserved as memfds, and dropping them also removes the only concurrent writer of that flags word from the handler's reach, so no shmem-wide locking change is needed here. The predicate is deliberately not narrowed to memfd_create() objects: unlinked non-private shmem files stay eligible. SHMEM_F_LOCKED is only maintained for SysV segments, so they do not share this race and keep being preserved as before. Measured with QEMU runs on this tree, with CONFIG_CHECKPOINT_RESTORE and CONFIG_SYSVIPC enabled and liveupdate=on, so that a descriptor for a segment is reachable; memfd_luo is the only file handler registered in that configuration: kernel SysV SHM fd memfd unlinked tmpfs without this patch accepted (0) accepted accepted with this patch -ENOENT (errno 2) accepted accepted The SysV descriptor came from /proc/self/map_files and reads back as "/SYSV00000000 (deleted)"; the memfd and the unlinked tmpfs file are the controls that show the ioctl path still works and that the check is limited to kernel-private objects. The SysV case is the same guarantee that the pre-existing SHMEM_F_MAPPING_FROZEN bit relies on, so the mismatch is older than this series; atomic flag updates or a shared lock would be a change across shmem and ipc, and this patch removes the handler's exposure to it instead. Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd") Reported-by: Sashiko Link: https://lore.kernel.org/all/sashiko-outbox-170776@kernel.org/ Assisted-by: Pi:glm-5.3-flash Signed-off-by: Haolong Wang <18766350203@163.com> --- mm/memfd_luo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c index 59de210bee5f..6f8b84530995 100644 --- a/mm/memfd_luo.c +++ b/mm/memfd_luo.c @@ -582,7 +582,12 @@ static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler, { struct inode *inode = file_inode(file); - return shmem_file(file) && !inode->i_nlink; + /* + * shmem_kernel_file_setup() marks kernel-private files S_PRIVATE. In + * particular, SysV SHM updates SHMEM_I(inode)->flags under its IPC lock, + * which does not serialize with the inode lock used by LUO. + */ + return shmem_file(file) && !IS_PRIVATE(inode) && !inode->i_nlink; } static unsigned long memfd_luo_get_id(struct file *file) -- 2.56.0