From: Greg Kroah-Hartman Date: Thu, 13 Aug 2026 12:25:08 +0000 (+0900) Subject: 6.18-stable patches X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7be6335d64e5b2a4430891d685674f399935319c;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches added patches: input-evdev-fix-information-leak-in-evdev_pass_values.patch mm-vmalloc-acquire-init_mm-lock-on-huge-vmap-to-avoid-ptdump-uaf.patch --- diff --git a/queue-6.18/input-evdev-fix-information-leak-in-evdev_pass_values.patch b/queue-6.18/input-evdev-fix-information-leak-in-evdev_pass_values.patch new file mode 100644 index 0000000000..ad9b9ba85c --- /dev/null +++ b/queue-6.18/input-evdev-fix-information-leak-in-evdev_pass_values.patch @@ -0,0 +1,88 @@ +From 90f305f2c7a30257c683e13f4bf7c798eea992a0 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Wed, 29 Jul 2026 11:30:45 -0700 +Subject: Input: evdev - fix information leak in evdev_pass_values() + +From: Dmitry Torokhov + +commit 90f305f2c7a30257c683e13f4bf7c798eea992a0 upstream. + +In evdev_pass_values(), the input_event structure is allocated on the +kernel stack and populated field-by-field. However, it is never fully +initialized. On architectures where struct input_event contains explicit +or implicit padding (such as the 32-bit __pad field on SPARC64), these +padding bytes are left uninitialized. + +When this event structure is subsequently passed to the client buffer +and later copied to userspace, the uninitialized padding bytes leak +kernel stack memory, potentially exposing sensitive information. + +Similar issues exist in __evdev_queue_syn_dropped and __pass_event. + +Fix this by explicitly zeroing the entire event structure with memset() +before populating its fields. This ensures all padding bytes are cleared +before the data crosses the security boundary. + +Reported-by: sashiko-bot@kernel.org +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/ampGGKo4UMKru6f5@google.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman +--- + drivers/input/evdev.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +--- a/drivers/input/evdev.c ++++ b/drivers/input/evdev.c +@@ -149,11 +149,11 @@ static void __evdev_queue_syn_dropped(st + struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]); + struct input_event ev; + ++ memset(&ev, 0, sizeof(ev)); + ev.input_event_sec = ts.tv_sec; + ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; + ev.type = EV_SYN; + ev.code = SYN_DROPPED; +- ev.value = 0; + + client->buffer[client->head++] = ev; + client->head &= client->bufsize - 1; +@@ -221,20 +221,20 @@ static void __pass_event(struct evdev_cl + client->head &= client->bufsize - 1; + + if (unlikely(client->head == client->tail)) { ++ struct input_event ev; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ev.input_event_sec = event->input_event_sec; ++ ev.input_event_usec = event->input_event_usec; ++ ev.type = EV_SYN; ++ ev.code = SYN_DROPPED; ++ + /* + * This effectively "drops" all unconsumed events, leaving + * EV_SYN/SYN_DROPPED plus the newest event in the queue. + */ + client->tail = (client->head - 2) & (client->bufsize - 1); +- +- client->buffer[client->tail] = (struct input_event) { +- .input_event_sec = event->input_event_sec, +- .input_event_usec = event->input_event_usec, +- .type = EV_SYN, +- .code = SYN_DROPPED, +- .value = 0, +- }; +- ++ client->buffer[client->tail] = ev; + client->packet_head = client->tail; + } + +@@ -256,6 +256,8 @@ static void evdev_pass_values(struct evd + if (client->revoked) + return; + ++ memset(&event, 0, sizeof(event)); ++ + ts = ktime_to_timespec64(ev_time[client->clk_type]); + event.input_event_sec = ts.tv_sec; + event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; diff --git a/queue-6.18/mm-vmalloc-acquire-init_mm-lock-on-huge-vmap-to-avoid-ptdump-uaf.patch b/queue-6.18/mm-vmalloc-acquire-init_mm-lock-on-huge-vmap-to-avoid-ptdump-uaf.patch new file mode 100644 index 0000000000..bbd56e8efc --- /dev/null +++ b/queue-6.18/mm-vmalloc-acquire-init_mm-lock-on-huge-vmap-to-avoid-ptdump-uaf.patch @@ -0,0 +1,341 @@ +From 26444eb71465c9934d9d418ef69c43f61185329b Mon Sep 17 00:00:00 2001 +From: "Lorenzo Stoakes (ARM)" +Date: Thu, 23 Jul 2026 16:16:31 +0100 +Subject: mm/vmalloc: acquire init_mm lock on huge vmap to avoid ptdump UAF + +From: Lorenzo Stoakes (ARM) + +commit 26444eb71465c9934d9d418ef69c43f61185329b upstream. + +Patch series "mm: fix UAF caused by race between ptdump and vmap pgtable +freeing", v6. + +Kernel page table walkers fall into two broad categories - those ranges +where no exclusion is required via walk_kernel_page_table_range_lockless() +and those where exclusion is required via walk_kernel_page_table_range() +or walk_page_range_debug(). + +The former category is used only by arm64 arch code operating on ranges it +both wholly owns and does not concurrently write. + +The latter category consists of kernel page table walkers operating on +ranges that are wholly owned (but which need exclusion against concurrent +writers). + +The lock used for exclusion is the mmap lock, and for kernel ranges this +is the mmap lock on init_mm. + +ptdump is a special case being both the only user of +walk_page_range_debug(), and the only case in which it walks ranges it +does not own. + +This presents a problem, as page tables may be freed under ptdump. And +indeed there is a use-after-free bug in the kernel as a result, which this +series addresses. + +vmap promotes page tables to huge leaf entries where possible, freeing the +lower page table when it does. It does this with no meaningful locks held +against concurrent ptdump walks. + +As a result, use-after-free can currently occur. This series addresses +the issue by having the vmap huge promotion logic acquire the mmap read +lock while both setting the huge page table entry and freeing the prior +leaf page table. + +The ptdump code already acquires the mmap write lock, so by doing so we +ensure that the ptdump walker only ever observes either the huge page +table entry or the existing page table entry, and nothing is freed +underneath it. + +A mitigation for this issue was already applied for arm64 in commit +fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump"), which this series +has to deal with carefully. + +This mitigation resolves the issue by acquiring the mmap read lock on +init_mm on vmap page table free if a ptdump is in progress. + +However the fix in this series would cause a deadlock if we were to simply +apply it for arm64 without also reverting the change. + +This is because vmap may acquire the read lock before ptdump attempts to +acquire the write lock, which then gets queued, and rwsem starvation rules +mean that the (unacknowledged) nested mmap read lock in the arm64 code +would also block, meaning the original read lock is never released and +thus deadlock. + +This series works around this by #ifndef CONFIG_ARM64'ing the mmap read +lock in vmap logic, then partially reverting commit fa93b45fd397 ("arm64: +Enable vmalloc-huge with ptdump"), keeping the enablement of huge vmap +support, and removing the ifdeffery with the partial revert patch. + +There are related issues that are also addressed in this series: + +* x86 page attribute logic, specifically Change Page Attributes (CPA), + implements a feature whereby huge ranges can be collapsed into huge leaf + entries. This can similarly cause a UAF when done in parallel with a + ptdump walk, so similarly acquire the init_mm mmap lock to avoid this. + +* The CPA logic allows concurrent page table manipulation and CPA + collapse, meaning the former risks accessing a page table the latter + frees. Fix this by acquiring mmap write lock on init_mm across the + whole CPA collapse operation and read lock on the page table + manipulation. + +* x86 and arm64 permit walks of non-kernel mm's (both allowing efi mm + walks, and in x86's case arbitrary mm's), so we ensure kernel mappings + remain stable by locking the init_mm as well as the mm being walked. + +The ordering of patches is established for both strict dependencies (the +arm64 partial revert in particular has to be done after the vmap changes) +and logical ones (the non-kernel mm fix only makes sense once the vmap/CPA +fixes are in place). + + +This patch (of 3): + +Currently there is a nasty race between ptdump and vmap when attempting to +map a huge P4D, PUD or PMD entry: + +* ptdump walks kernel page table ranges it doesn't own. + +* When vmap maps ranges it tries to promotes existing ones to huge page + tables in vmap_try_huge_[p4d,pud,pmd]() at P4D, PUD and PMD level, + freeing the lower page table in [p4d,pud,pmd]_free_[pud,pmd,pte]_page() + when it succeeds. + +Both of these things can happen at the same time and as a result ptdump +can access a freed page table, resulting in a use-after-free and memory +corruption. + +This is possible because while ptdump_walk_pgd() holds both the mem +hotplug lock and the mmap write lock before invoking +walk_page_range_debug(), vmap takes no relevant locks at all. + +Fix this by holding the mmap read lock in vmap_try_huge_*() when freeing +page tables. + +The read lock is sufficient: ptdump is the only walker that must be +excluded and it holds the mmap write lock. Other holders of the read lock +may run concurrently, but each exclusively owns the range it operates on +and cannot reach the page tables freed here. + +We also hold the lock while assigning the huge page table entry, which +means page table walkers observe only the huge or non-huge page table +entry. + +We use a trylock to prevent ptdump from blocking vmap making forward +progress. This is fine because it's an optimisation in any case, and thus +the vmap can safely proceed regardless. + +All other kernel page table walkers that touch vmalloc ranges either +exclusively own the memory walked or acquire the mmap lock, so this +correctly excludes those walkers. + +One wrinkle here is commit fa93b45fd397 ("arm64: Enable vmalloc-huge with +ptdump"), which addresses the issue for arm64 only by explicitly acquiring +the mmap read lock on kernel page table freeing should a concurrent ptdump +be in progress. + +This is problematic as vmap may acquire the mmap read lock prior to ptdump +attempting to acquire an mmap write lock, leading to a deadlock when the +mmap read lock is slept upon on page table freeing due to rwsem +anti-starvation. + +We work around this by predicating the mmap lock being taken on +!CONFIG_ARM64 for the time being. + +With this patch applied, a follow up will partially revert commit +fa93b45fd397 ("arm64: Enable vmalloc-huge with ptdump") and at that stage +remove the arm64 ifdeffery. + +We also update walk_page_range_debug() to assert the mmap write lock +unconditionally and update the comment here to reflect this change. + +The issue has existed as long as ptdump was available and vmap freed page +tables when promoting to a huge leaf entry, that is, since commit +b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table") +for huge ioremap, and commit 121e6f3258fe ("mm/vmalloc: hugepage vmalloc +mappings") for huge vmalloc. + +Since the former is the earlier of the two we choose that for our Fixes +tag. + +We also define a guard class for mmap_read_trylock() so we can use +cleanup.h to make the scope handling cleaner in the implementation. + +This patch is based on work by David Carlier (linked), with gratitude! + +Link: https://lore.kernel.org/20260723-series-vmap-race-fix-v6-0-8cc77dcc0018@kernel.org +Link: https://lore.kernel.org/20260723-series-vmap-race-fix-v6-1-8cc77dcc0018@kernel.org +Fixes: b6bdb7517c3d ("mm/vmalloc: add interfaces to free unmapped page table") +Signed-off-by: Lorenzo Stoakes (ARM) +Reported-by: syzbot+fd95a72470f5a44e464c@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a287988.39669fcc.33b062.00a0.GAE@google.com/T/ +Link: https://lore.kernel.org/linux-mm/20260706203128.162335-1-devnexen@gmail.com/ +Reviewed-by: Mike Rapoport (Microsoft) +Reviewed-by: Dev Jain +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Kiryl Shutsemau +Cc: +Cc: Andy Lutomirski +Cc: "Borah, Chaitanya Kumar" +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: "H. Peter Anvin" +Cc: Ingo Molnar +Cc: Liam R. Howlett +Cc: Michal Hocko +Cc: Peter Zijlstra +Cc: Ryan Roberts +Cc: Shakeel Butt +Cc: Suren Baghdasaryan +Cc: Toshi Kani +Cc: "Uladzislau Rezki (Sony)" +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mmap_lock.h | 1 + mm/pagewalk.c | 22 +++++++++++--------- + mm/vmalloc.c | 49 +++++++++++++++++++++++++++++++++++++--------- + 3 files changed, 53 insertions(+), 19 deletions(-) + +--- a/include/linux/mmap_lock.h ++++ b/include/linux/mmap_lock.h +@@ -397,6 +397,7 @@ static inline void mmap_read_unlock(stru + + DEFINE_GUARD(mmap_read_lock, struct mm_struct *, + mmap_read_lock(_T), mmap_read_unlock(_T)) ++DEFINE_GUARD_COND(mmap_read_lock, _try, mmap_read_trylock(_T)) + + static inline void mmap_read_unlock_non_owner(struct mm_struct *mm) + { +--- a/mm/pagewalk.c ++++ b/mm/pagewalk.c +@@ -678,6 +678,8 @@ int walk_kernel_page_table_range_lockles + * will also not lock the PTEs for the pte_entry() callback. + * + * This is for debugging purposes ONLY. ++ * ++ * The mmap write lock must be held. + */ + int walk_page_range_debug(struct mm_struct *mm, unsigned long start, + unsigned long end, const struct mm_walk_ops *ops, +@@ -691,6 +693,16 @@ int walk_page_range_debug(struct mm_stru + .no_vma = true + }; + ++ /* ++ * When walking userland page tables, an mmap write lock must be held to ++ * account for munmap() downgrading to an mmap read lock when tearing ++ * down page tables. ++ * ++ * When walking kernel page tables, an mmap write lock must also be held ++ * to account for page table freeing on vmap huge page mapping. ++ */ ++ mmap_assert_write_locked(mm); ++ + /* For convenience, we allow traversal of kernel mappings. */ + if (mm == &init_mm) + return walk_kernel_page_table_range(start, end, ops, +@@ -700,16 +712,6 @@ int walk_page_range_debug(struct mm_stru + if (!check_ops_valid(ops)) + return -EINVAL; + +- /* +- * The mmap lock protects the page walker from changes to the page +- * tables during the walk. However a read lock is insufficient to +- * protect those areas which don't have a VMA as munmap() detaches +- * the VMAs before downgrading to a read lock and actually tearing +- * down PTEs/page tables. In which case, the mmap write lock should +- * be held. +- */ +- mmap_assert_write_locked(mm); +- + return walk_pgd_range(start, end, &walk); + } + +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #define CREATE_TRACE_POINTS + #include +@@ -155,10 +156,24 @@ static int vmap_try_huge_pmd(pmd_t *pmd, + if (!IS_ALIGNED(phys_addr, PMD_SIZE)) + return 0; + +- if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr)) +- return 0; ++ if (!pmd_present(*pmd)) ++ return pmd_set_huge(pmd, phys_addr, prot); + +- return pmd_set_huge(pmd, phys_addr, prot); ++ /* ++ * Acquire the mmap read lock to exclude ptdump, which walks ++ * kernel page tables it does not own under the mmap write lock. ++ * ++ * Concurrent read lock holders are safe: each exclusively owns ++ * the range it operates on and cannot reach this page table. ++ */ ++#ifndef CONFIG_ARM64 ++ scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) ++#endif ++ { ++ if (!pmd_free_pte_page(pmd, addr)) ++ return 0; ++ return pmd_set_huge(pmd, phys_addr, prot); ++ } + } + + static int vmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, +@@ -205,10 +220,18 @@ static int vmap_try_huge_pud(pud_t *pud, + if (!IS_ALIGNED(phys_addr, PUD_SIZE)) + return 0; + +- if (pud_present(*pud) && !pud_free_pmd_page(pud, addr)) +- return 0; ++ if (!pud_present(*pud)) ++ return pud_set_huge(pud, phys_addr, prot); + +- return pud_set_huge(pud, phys_addr, prot); ++ /* See comment in vmap_try_huge_pmd(). */ ++#ifndef CONFIG_ARM64 ++ scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) ++#endif ++ { ++ if (!pud_free_pmd_page(pud, addr)) ++ return 0; ++ return pud_set_huge(pud, phys_addr, prot); ++ } + } + + static int vmap_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end, +@@ -256,10 +279,18 @@ static int vmap_try_huge_p4d(p4d_t *p4d, + if (!IS_ALIGNED(phys_addr, P4D_SIZE)) + return 0; + +- if (p4d_present(*p4d) && !p4d_free_pud_page(p4d, addr)) +- return 0; ++ if (!p4d_present(*p4d)) ++ return p4d_set_huge(p4d, phys_addr, prot); + +- return p4d_set_huge(p4d, phys_addr, prot); ++ /* See comment in vmap_try_huge_pmd(). */ ++#ifndef CONFIG_ARM64 ++ scoped_cond_guard(mmap_read_lock_try, return 0, &init_mm) ++#endif ++ { ++ if (!p4d_free_pud_page(p4d, addr)) ++ return 0; ++ return p4d_set_huge(p4d, phys_addr, prot); ++ } + } + + static int vmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end, diff --git a/queue-6.18/series b/queue-6.18/series index 8fdaaf1fd9..9e5693f393 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -122,3 +122,5 @@ net-usb-ax88179_178a-fix-skb-leak-in-ax88179_tx_fixup.patch net-usb-ipheth-fix-carrier_work-uaf-on-disconnect.patch vt-add-permission-check-for-kdskbmeta-ioctl.patch vt-stabilize-tty-reference-in-kbd_keycode-with-tty_port_tty_get.patch +input-evdev-fix-information-leak-in-evdev_pass_values.patch +mm-vmalloc-acquire-init_mm-lock-on-huge-vmap-to-avoid-ptdump-uaf.patch