hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/784 CVE: CVE-2025-21696 -------------------------------- The struct userfaultfd_ctx was previously defined in the public header include/linux/userfaultfd_k.h. This header is included by several exported interfaces, making any change to the structure a potential kABI breakage for out‑of‑tree modules. To reduce the exposure of the structure’s internal layout, move its definition into a new internal header: include/linux/userfaultfd_k_ext.h. This header is now directly included only by the source files that actually need to access the fields of struct userfaultfd_ctx (e.g., fs/userfaultfd.c, mm/huge_memory.c, etc.). Consequently, modifications to the structure will only affect those specific files, significantly narrowing the kABI surface. Additionally, the inline helper vma_has_uffd_without_event_remap, which relies on the structure, is also relocated to the new header. All affected source files are updated to include userfaultfd_k_ext.h explicitly: - fs/userfaultfd.c - mm/huge_memory.c - mm/hugetlb.c - mm/mremap.c This change is purely organizational and introduces no functional alterations. Fixes: f91e6b41dd11 ("userfaultfd: move userfaultfd_ctx struct to header file.") Signed-off-by: Ze Zuo <zuoze1@huawei.com> --- fs/userfaultfd.c | 1 + include/linux/userfaultfd_k.h | 51 ------------------------- include/linux/userfaultfd_k_ext.h | 62 +++++++++++++++++++++++++++++++ mm/huge_memory.c | 1 + mm/hugetlb.c | 1 + mm/mremap.c | 1 + 6 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 include/linux/userfaultfd_k_ext.h diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 67902e073f060..7330d84ba56ad 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -25,6 +25,7 @@ #include <linux/anon_inodes.h> #include <linux/syscalls.h> #include <linux/userfaultfd_k.h> +#include <linux/userfaultfd_k_ext.h> #include <linux/mempolicy.h> #include <linux/ioctl.h> #include <linux/security.h> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index 791af86a89ccd..aa8e3725f1034 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -36,45 +36,6 @@ #define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) #define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS) -/* - * Start with fault_pending_wqh and fault_wqh so they're more likely - * to be in the same cacheline. - * - * Locking order: - * fd_wqh.lock - * fault_pending_wqh.lock - * fault_wqh.lock - * event_wqh.lock - * - * To avoid deadlocks, IRQs must be disabled when taking any of the above locks, - * since fd_wqh.lock is taken by aio_poll() while it's holding a lock that's - * also taken in IRQ context. - */ -struct userfaultfd_ctx { - /* waitqueue head for the pending (i.e. not read) userfaults */ - wait_queue_head_t fault_pending_wqh; - /* waitqueue head for the userfaults */ - wait_queue_head_t fault_wqh; - /* waitqueue head for the pseudo fd to wakeup poll/read */ - wait_queue_head_t fd_wqh; - /* waitqueue head for events */ - wait_queue_head_t event_wqh; - /* a refile sequence protected by fault_pending_wqh lock */ - seqcount_spinlock_t refile_seq; - /* pseudo fd refcounting */ - refcount_t refcount; - /* userfaultfd syscall flags */ - unsigned int flags; - /* features requested from the userspace */ - unsigned int features; - /* released */ - bool released; - /* memory mappings are changing because of non-cooperative event */ - atomic_t mmap_changing; - /* mm with one ore more vmas attached to this userfaultfd_ctx */ - struct mm_struct *mm; -}; - extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason); /* A combined operation mode + behavior flags. */ @@ -223,13 +184,6 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma, vma_is_shmem(vma); } -static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma) -{ - struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx; - - return uffd_ctx && (uffd_ctx->features & UFFD_FEATURE_EVENT_REMAP) == 0; -} - extern int dup_userfaultfd(struct vm_area_struct *, struct list_head *); extern void dup_userfaultfd_complete(struct list_head *); void dup_userfaultfd_fail(struct list_head *); @@ -353,11 +307,6 @@ static inline bool userfaultfd_wp_unpopulated(struct vm_area_struct *vma) return false; } -static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma) -{ - return false; -} - #endif /* CONFIG_USERFAULTFD */ static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma) diff --git a/include/linux/userfaultfd_k_ext.h b/include/linux/userfaultfd_k_ext.h new file mode 100644 index 0000000000000..08d6c68933104 --- /dev/null +++ b/include/linux/userfaultfd_k_ext.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _LINUX_USERFAULTFD_K_EXT_H +#define _LINUX_USERFAULTFD_K_EXT_H + +#ifdef CONFIG_USERFAULTFD +/* + * Start with fault_pending_wqh and fault_wqh so they're more likely + * to be in the same cacheline. + * + * Locking order: + * fd_wqh.lock + * fault_pending_wqh.lock + * fault_wqh.lock + * event_wqh.lock + * + * To avoid deadlocks, IRQs must be disabled when taking any of the above locks, + * since fd_wqh.lock is taken by aio_poll() while it's holding a lock that's + * also taken in IRQ context. + */ +struct userfaultfd_ctx { + /* waitqueue head for the pending (i.e. not read) userfaults */ + wait_queue_head_t fault_pending_wqh; + /* waitqueue head for the userfaults */ + wait_queue_head_t fault_wqh; + /* waitqueue head for the pseudo fd to wakeup poll/read */ + wait_queue_head_t fd_wqh; + /* waitqueue head for events */ + wait_queue_head_t event_wqh; + /* a refile sequence protected by fault_pending_wqh lock */ + seqcount_spinlock_t refile_seq; + /* pseudo fd refcounting */ + refcount_t refcount; + /* userfaultfd syscall flags */ + unsigned int flags; + /* features requested from the userspace */ + unsigned int features; + /* released */ + bool released; + /* memory mappings are changing because of non-cooperative event */ + atomic_t mmap_changing; + /* mm with one ore more vmas attached to this userfaultfd_ctx */ + struct mm_struct *mm; +}; + +static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma) +{ + struct userfaultfd_ctx *uffd_ctx = vma->vm_userfaultfd_ctx.ctx; + + return uffd_ctx && (uffd_ctx->features & UFFD_FEATURE_EVENT_REMAP) == 0; +} + +#else /* CONFIG_USERFAULTFD */ + +static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma) +{ + return false; +} + +#endif /* CONFIG_USERFAULTFD */ + +#endif /* __LINUX_USERFAULTFD_K_EXT_H */ diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1573e640dc663..f5673a3b9e77d 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -31,6 +31,7 @@ #include <linux/migrate.h> #include <linux/hashtable.h> #include <linux/userfaultfd_k.h> +#include <linux/userfaultfd_k_ext.h> #include <linux/page_idle.h> #include <linux/shmem_fs.h> #include <linux/oom.h> diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 1901599d597e8..e5cf950e71ccf 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -40,6 +40,7 @@ #ifndef __GENKSYMS__ #include <trace/events/kmem.h> #endif +#include <linux/userfaultfd_k_ext.h> #include <asm/page.h> #include <asm/pgalloc.h> diff --git a/mm/mremap.c b/mm/mremap.c index 36ead7184d8ec..caf34ba2c4ec5 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -24,6 +24,7 @@ #include <linux/mmu_notifier.h> #include <linux/uaccess.h> #include <linux/userfaultfd_k.h> +#include <linux/userfaultfd_k_ext.h> #include <linux/mempolicy.h> #include <linux/share_pool.h> #include <linux/userswap.h> -- 2.25.1