* [PATCH 0/2] x86/fred: Fix stack depot exhaustion on FRED systems
@ 2026-08-27 15:00 Yuanhe Shu
2026-08-27 15:00 ` [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook Yuanhe Shu
2026-08-27 15:00 ` [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks Yuanhe Shu
0 siblings, 2 replies; 7+ messages in thread
From: Yuanhe Shu @ 2026-08-27 15:00 UTC (permalink / raw)
To: tglx, mingo, bp, dave.hansen, x86
Cc: hpa, xin, luto, jpoimboe, peterz, rostedt, akpm, rdunlap, elver,
andreyknvl, glider, gor, kasan-dev, linux-kernel, Yuanhe Shu
FRED replaces the IDT event entry stubs with asm_fred_entrypoint_user and
asm_fred_entrypoint_kernel, which live in .noinstr.text. The IDT stubs
are the only code covered by __irqentry_text_start..__irqentry_text_end,
which in_irqentry_text() uses to find where an event entered the kernel.
With FRED the detection fails, filter_irq_stacks() no longer truncates
event stacks, and every trace saved from interrupt or exception context
by stack depot users (KASAN alloc/free tracking, SLUB object tracking,
...) becomes a unique combination of "event path x arbitrarily
interrupted context". The depot grows without bound until it is
exhausted.
What we saw: a FRED-capable dual-socket system with KASAN (generic,
inline) and SLUB object tracking enabled hit the limit on both sockets
roughly 80 minutes after boot,
Stack depot reached limit capacity
WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170
after which KASAN and SLUB stack tracking silently stop recording (new
traces get handle 0) until reboot. The recorded traces confirmed the
mechanism: interrupt side traces ran through asm_fred_entrypoint_kernel
and continued into the frames of the interrupted task.
Patch 1 adds an optional arch_in_irqentry_text() hook to the generic
in_irqentry_text() check; no behavior change by itself. Patch 2
implements it for x86 by bracketing the FRED entry text with
__fred_entry_text_start/end, the same way the IDT stubs are bracketed,
and makes X86_FRED select the new Kconfig symbol.
Unlike arm64 and s390, which hit the same symptom and could fix it by
placing their interrupt entry code in .irqentry.text, x86 has no such
section: it emits the markers as labels around the sequentially laid out
IDT stubs and defines __irq_entry to __invalid_section so that nothing
can land in that section. The FRED entry points therefore cannot be
brought inside the existing range, and a second one has to be reported;
see patch 2 for the details.
Testing:
- Build-tested on mainline: full vmlinux builds and link with
CONFIG_X86_FRED=y, CONFIG_X86_KERNEL_IBT=y and KASAN (generic,
inline), with and without CONFIG_KVM_INTEL=y; objtool link stage
clean.
- Runtime-tested by backporting both patches to the affected kernel (a
6.6 based debug build) and rebooting that system with an unchanged
command line: traces recorded from FRED event context now end at
asm_fred_entrypoint_kernel instead of continuing into the
interrupted task, and the pool count levels off at ~1230 pools
within minutes of boot instead of reaching the 8192 pool limit.
Reproducing on current upstream:
- On FRED hardware, any KASAN or SLUB_DEBUG kernel; on v6.17 and
later, boot with stack_depot_max_pools=1024 to bring the
exhaustion warning up in minutes instead of hours, and watch the
pool count in /sys/kernel/debug/stackdepot/stats grow
monotonically without the fix and converge with it.
- Without FRED hardware, the KVM VMX interrupt forwarding path
(CONFIG_X86_FRED=y + CONFIG_KVM_INTEL) exercises the new filtering
as well, see patch 2.
Both patches are Cc'ed to stable and 2/2 depends on 1/2, so please pick
them up as a pair. Patch 1 touches kernel/stacktrace.c and lib/Kconfig;
routing the series through tip:x86/entry with an Acked-by from Andrew
for 1/2 is probably the smoothest path.
Yuanhe Shu (2):
stacktrace: Provide arch_in_irqentry_text() hook
x86/fred: Fix stack depot filtering of FRED event stacks
arch/x86/Kconfig | 1 +
arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++
arch/x86/include/asm/sections.h | 1 +
arch/x86/kernel/stacktrace.c | 13 +++++++++++++
include/linux/stacktrace.h | 16 ++++++++++++++++
kernel/stacktrace.c | 3 ++-
lib/Kconfig | 3 +++
7 files changed, 50 insertions(+), 1 deletion(-)
base-commit: 45c13f3f9e3bb15fd89ff2864c6f627a3b4b4229
--
2.43.5
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook 2026-08-27 15:00 [PATCH 0/2] x86/fred: Fix stack depot exhaustion on FRED systems Yuanhe Shu @ 2026-08-27 15:00 ` Yuanhe Shu 2026-08-27 17:04 ` Bradley Morgan 2026-08-27 23:06 ` Andrew Morton 2026-08-27 15:00 ` [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks Yuanhe Shu 1 sibling, 2 replies; 7+ messages in thread From: Yuanhe Shu @ 2026-08-27 15:00 UTC (permalink / raw) To: tglx, mingo, bp, dave.hansen, x86 Cc: hpa, xin, luto, jpoimboe, peterz, rostedt, akpm, rdunlap, elver, andreyknvl, glider, gor, kasan-dev, linux-kernel, Yuanhe Shu, stable in_irqentry_text() decides whether a stack address belongs to interrupt entry code by checking the .irqentry.text and .softirqentry.text section ranges. filter_irq_stacks() uses it to truncate interrupt stacks at the entry point, which stack depot depends on to deduplicate them: traces that continue past the interrupt entry lead to unbounded depot growth, see commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks() in stack_depot_save()"). An architecture may deliver interrupts through entry code that cannot be placed in .irqentry.text. in_irqentry_text() then never recognizes the entry point and the truncation silently stops happening. The markers are meant to cover all interrupt entry functions; when they do not, the depot ends up holding essentially random stacks: https://lore.kernel.org/all/CACT4Y+aReMGLYua2rCLHgFpS9io5cZC04Q8GLs-uNmrn1ezxYQ@mail.gmail.com/ Add an optional arch_in_irqentry_text() hook, consulted in addition to the section range checks, gated on a new ARCH_HAS_IN_IRQENTRY_TEXT symbol. Gating keeps the default a static inline returning false, which folds away entirely on every architecture that does not opt in, instead of a __weak stub that every architecture would have to call. This mirrors the existing ARCH_HAS_* hooks in lib/Kconfig such as ARCH_HAS_COPY_MC. No functional change on its own. The first user is the FRED fix in the follow-up patch, which carries a Fixes: tag and is Cc'ed to stable; tag this prerequisite for stable too, so the two are picked up as a pair. Cc: stable@vger.kernel.org Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com> --- include/linux/stacktrace.h | 16 ++++++++++++++++ kernel/stacktrace.c | 3 ++- lib/Kconfig | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 525cf60673fe..e933ce86447f 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h @@ -62,6 +62,22 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, const struct pt_regs *regs); #endif /* CONFIG_ARCH_STACKWALK */ +/* + * Optional arch provided check for additional IRQ entry text, called + * in addition to the .irqentry.text and .softirqentry.text range + * checks in in_irqentry_text(). Implement this if the architecture + * delivers interrupts or exceptions through entry code which cannot + * reside in those sections. + */ +#ifdef CONFIG_ARCH_HAS_IN_IRQENTRY_TEXT +bool arch_in_irqentry_text(unsigned long addr); +#else +static inline bool arch_in_irqentry_text(unsigned long addr) +{ + return false; +} +#endif + #ifdef CONFIG_STACKTRACE void stack_trace_print(const unsigned long *trace, unsigned int nr_entries, int spaces); diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c index afb3c116da91..9e85ac900889 100644 --- a/kernel/stacktrace.c +++ b/kernel/stacktrace.c @@ -379,7 +379,8 @@ static inline bool in_irqentry_text(unsigned long ptr) return (ptr >= (unsigned long)&__irqentry_text_start && ptr < (unsigned long)&__irqentry_text_end) || (ptr >= (unsigned long)&__softirqentry_text_start && - ptr < (unsigned long)&__softirqentry_text_end); + ptr < (unsigned long)&__softirqentry_text_end) || + arch_in_irqentry_text(ptr); } /** diff --git a/lib/Kconfig b/lib/Kconfig index 4e6b34c3346d..45ff30d0a995 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -551,6 +551,9 @@ config ARCH_HAS_COPY_MC config ARCH_STACKWALK bool +config ARCH_HAS_IN_IRQENTRY_TEXT + bool + config STACKDEPOT bool select STACKTRACE -- 2.43.5 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook 2026-08-27 15:00 ` [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook Yuanhe Shu @ 2026-08-27 17:04 ` Bradley Morgan 2026-08-27 23:06 ` Andrew Morton 1 sibling, 0 replies; 7+ messages in thread From: Bradley Morgan @ 2026-08-27 17:04 UTC (permalink / raw) To: xiangzao Cc: akpm, andreyknvl, bp, dave.hansen, elver, glider, gor, hpa, jpoimboe, kasan-dev, linux-kernel, luto, mingo, peterz, rdunlap, rostedt, stable, tglx, x86, xin On 27 August 2026 16:00:21 BST, Yuanhe Shu <xiangzao@linux.alibaba.com> wrote: >in_irqentry_text() decides whether a stack address belongs to interrupt >entry code by checking the .irqentry.text and .softirqentry.text section >ranges. filter_irq_stacks() uses it to truncate interrupt stacks at the >entry point, which stack depot depends on to deduplicate them: traces >that continue past the interrupt entry lead to unbounded depot growth, >see commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks() >in stack_depot_save()"). > >An architecture may deliver interrupts through entry code that cannot be >placed in .irqentry.text. in_irqentry_text() then never recognizes the >entry point and the truncation silently stops happening. The markers are >meant to cover all interrupt entry functions; when they do not, the depot >ends up holding essentially random stacks: > > https://lore.kernel.org/all/CACT4Y+aReMGLYua2rCLHgFpS9io5cZC04Q8GLs-uNmrn1ezxYQ@mail.gmail.com/ > >Add an optional arch_in_irqentry_text() hook, consulted in addition to >the section range checks, gated on a new ARCH_HAS_IN_IRQENTRY_TEXT >symbol. Gating keeps the default a static inline returning false, which >folds away entirely on every architecture that does not opt in, instead >of a __weak stub that every architecture would have to call. This >mirrors the existing ARCH_HAS_* hooks in lib/Kconfig such as >ARCH_HAS_COPY_MC. > >No functional change on its own. > >The first user is the FRED fix in the follow-up patch, which carries a >Fixes: tag and is Cc'ed to stable; tag this prerequisite for stable too, >so the two are picked up as a pair. > >Cc: stable@vger.kernel.org LGTM, thanks Reviewed-by: Bradley Morgan <brads@mainlining.org> >Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com> >--- > include/linux/stacktrace.h | 16 ++++++++++++++++ > kernel/stacktrace.c | 3 ++- > lib/Kconfig | 3 +++ > 3 files changed, 21 insertions(+), 1 deletion(-) > >diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h >index 525cf60673fe..e933ce86447f 100644 >--- a/include/linux/stacktrace.h >+++ b/include/linux/stacktrace.h >@@ -62,6 +62,22 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, > const struct pt_regs *regs); > #endif /* CONFIG_ARCH_STACKWALK */ > >+/* >+ * Optional arch provided check for additional IRQ entry text, called >+ * in addition to the .irqentry.text and .softirqentry.text range >+ * checks in in_irqentry_text(). Implement this if the architecture >+ * delivers interrupts or exceptions through entry code which cannot >+ * reside in those sections. >+ */ >+#ifdef CONFIG_ARCH_HAS_IN_IRQENTRY_TEXT >+bool arch_in_irqentry_text(unsigned long addr); >+#else >+static inline bool arch_in_irqentry_text(unsigned long addr) >+{ >+ return false; >+} >+#endif >+ > #ifdef CONFIG_STACKTRACE > void stack_trace_print(const unsigned long *trace, unsigned int > nr_entries, > int spaces); >diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c >index afb3c116da91..9e85ac900889 100644 >--- a/kernel/stacktrace.c >+++ b/kernel/stacktrace.c >@@ -379,7 +379,8 @@ static inline bool in_irqentry_text(unsigned long ptr) > return (ptr >= (unsigned long)&__irqentry_text_start && > ptr < (unsigned long)&__irqentry_text_end) || > (ptr >= (unsigned long)&__softirqentry_text_start && >- ptr < (unsigned long)&__softirqentry_text_end); >+ ptr < (unsigned long)&__softirqentry_text_end) || >+ arch_in_irqentry_text(ptr); > } > > /** >diff --git a/lib/Kconfig b/lib/Kconfig >index 4e6b34c3346d..45ff30d0a995 100644 >--- a/lib/Kconfig >+++ b/lib/Kconfig >@@ -551,6 +551,9 @@ config ARCH_HAS_COPY_MC > config ARCH_STACKWALK > bool > >+config ARCH_HAS_IN_IRQENTRY_TEXT >+ bool >+ > config STACKDEPOT > bool > select STACKTRACE > --- Thanks! https://lore.kernel.org/all/EE579805-42F2-4C58-B752-F28779EEB717@grrlz.net/ ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook 2026-08-27 15:00 ` [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook Yuanhe Shu 2026-08-27 17:04 ` Bradley Morgan @ 2026-08-27 23:06 ` Andrew Morton 1 sibling, 0 replies; 7+ messages in thread From: Andrew Morton @ 2026-08-27 23:06 UTC (permalink / raw) To: Yuanhe Shu Cc: tglx, mingo, bp, dave.hansen, x86, hpa, xin, luto, jpoimboe, peterz, rostedt, rdunlap, elver, andreyknvl, glider, gor, kasan-dev, linux-kernel, stable On Thu, 27 Aug 2026 23:00:21 +0800 Yuanhe Shu <xiangzao@linux.alibaba.com> wrote: > in_irqentry_text() decides whether a stack address belongs to interrupt > entry code by checking the .irqentry.text and .softirqentry.text section > ranges. filter_irq_stacks() uses it to truncate interrupt stacks at the > entry point, which stack depot depends on to deduplicate them: traces > that continue past the interrupt entry lead to unbounded depot growth, > see commit e94006608949 ("lib/stackdepot: always do filter_irq_stacks() > in stack_depot_save()"). > > An architecture may deliver interrupts through entry code that cannot be > placed in .irqentry.text. in_irqentry_text() then never recognizes the > entry point and the truncation silently stops happening. The markers are > meant to cover all interrupt entry functions; when they do not, the depot > ends up holding essentially random stacks: > > https://lore.kernel.org/all/CACT4Y+aReMGLYua2rCLHgFpS9io5cZC04Q8GLs-uNmrn1ezxYQ@mail.gmail.com/ > > Add an optional arch_in_irqentry_text() hook, consulted in addition to > the section range checks, gated on a new ARCH_HAS_IN_IRQENTRY_TEXT > symbol. Gating keeps the default a static inline returning false, which > folds away entirely on every architecture that does not opt in, instead > of a __weak stub that every architecture would have to call. This > mirrors the existing ARCH_HAS_* hooks in lib/Kconfig such as > ARCH_HAS_COPY_MC. > > No functional change on its own. > > The first user is the FRED fix in the follow-up patch, which carries a > Fixes: tag and is Cc'ed to stable; tag this prerequisite for stable too, > so the two are picked up as a pair. Good call. I suggest that the same Fixes: be attached to this patch also, to help ensure that everything lands in the correct place. I'll assume that both patches will be handled by the x86 maintainers. ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks 2026-08-27 15:00 [PATCH 0/2] x86/fred: Fix stack depot exhaustion on FRED systems Yuanhe Shu 2026-08-27 15:00 ` [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook Yuanhe Shu @ 2026-08-27 15:00 ` Yuanhe Shu 2026-08-27 21:26 ` H. Peter Anvin 2026-08-29 9:42 ` Peter Zijlstra 1 sibling, 2 replies; 7+ messages in thread From: Yuanhe Shu @ 2026-08-27 15:00 UTC (permalink / raw) To: tglx, mingo, bp, dave.hansen, x86 Cc: hpa, xin, luto, jpoimboe, peterz, rostedt, akpm, rdunlap, elver, andreyknvl, glider, gor, kasan-dev, linux-kernel, Yuanhe Shu, stable With FRED, events are delivered to asm_fred_entrypoint_user and asm_fred_entrypoint_kernel in .noinstr.text, not to the IDT stubs, which are the only code covered by __irqentry_text_start..__irqentry_text_end. in_irqentry_text() therefore never recognizes the event entry point and filter_irq_stacks() does not truncate FRED event stacks: every trace saved from interrupt or exception context by stack depot users such as KASAN alloc/free tracking or SLUB object tracking combines the event path with the arbitrarily interrupted context. The number of unique stacks grows with the product of both and the depot is exhausted. Observed on a dual-socket FRED-capable system with KASAN (generic, inline) and SLUB object tracking enabled, on both sockets roughly 80 minutes after boot, once the depot had reached its maximum of 8192 pools (128 MiB): Stack depot reached limit capacity WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170 The traces had the expected shape: an interrupt side trace ran through asm_fred_entrypoint_kernel into the frames of the task it had interrupted. New traces are dropped (handle 0) from then on and the depot never shrinks, so tracking stays dead until reboot. (Splat from a 6.6 based kernel; filter_irq_stacks() and the FRED entry layout are unchanged in mainline.) The entry points cannot be brought inside that range. x86 has no .irqentry.text: commit f0178fc01fe4 ("x86/entry: Unbreak __irqentry_text_start/end magic") dropped it from the linker script and emits the markers as labels around the sequentially laid out IDT stubs instead, exactly because the entry rework had moved that code into .noinstr.text and broken the function graph tracer and filter_irq_stacks(); __irq_entry has been __invalid_section since. Those labels live inside entry_64.S and wrap the IDT stubs which asm/idtentry.h emits into .entry.text, so the linker cannot place another translation unit between them, and the FRED entry points cannot join that block without leaving .noinstr.text. Architectures which do have the section fixed the same symptom locally, e.g. commit f6794950f0e5 ("arm64: set __exception_irq_entry with __irq_entry as a default") and commit 45c9f2b856a0 ("s390/entry: Mark IRQ entries to fix stack depot warnings"). Every FRED event leaves a return address in the FRED entry text: the return address of the call to fred_entry_from_user/kernel, or a frame of asm_fred_entry_from_kvm(), which the core entry code uses to forward VMX interrupts and NMIs acknowledged as part of the VM-Exit; see commit 0701c9e17bd9 ("x86/kvm/vmx: Move IRQ/NMI dispatch from KVM into x86 core"). So bracket it with __fred_entry_text_start/end, the same way the IDT stubs are bracketed, and report that range from arch_in_irqentry_text(). Verified on that system with the fix backported: traces from FRED event context now end at asm_fred_entrypoint_kernel (/sys/kernel/debug/slab/*/alloc_traces) and the pool count levels off a few minutes after boot instead of climbing to the limit. Truncating synchronous exception stacks only restores parity with the IDT range, which has always covered the exception stubs too. Syscalls enter through asm_fred_entrypoint_user as well, but there the entry frame is already the last trace entry, so filter_irq_stacks() returns the full trace unchanged. The function graph tracer uses the same markers and has the same gap; it can be converted separately. This is not limited to FRED hardware: with CONFIG_X86_FRED=y the KVM forwarding path above runs the FRED dispatch code even when the kernel itself uses the IDT, so KVM host stacks take the same untruncated path on non-FRED systems, albeit from a mostly fixed vcpu_run chain. Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code") Cc: stable@vger.kernel.org # v6.9+ Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com> --- Build tested with CONFIG_X86_FRED=y and CONFIG_X86_KERNEL_IBT=y, with and without CONFIG_KVM_INTEL: __fred_entry_text_start lands on the 4K-aligned asm_fred_entrypoint_user and the new range stays inside .noinstr.text. Note for stable: depends on patch 1/2. arch/x86/Kconfig | 1 + arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++ arch/x86/include/asm/sections.h | 1 + arch/x86/kernel/stacktrace.c | 13 +++++++++++++ 4 files changed, 29 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 15fd9ec5ecac..78b8eb4a925f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -555,6 +555,7 @@ config X86_CPU_RESCTRL_INTEL_AET config X86_FRED bool "Flexible Return and Event Delivery" depends on X86_64 + select ARCH_HAS_IN_IRQENTRY_TEXT help When enabled, use Flexible Return and Event Delivery instead of the legacy SYSCALL/SYSENTER/IDT architecture for diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S index b98f8945dfff..620def9039a3 100644 --- a/arch/x86/entry/entry_64_fred.S +++ b/arch/x86/entry/entry_64_fred.S @@ -36,6 +36,17 @@ */ .align 4096 +/* + * Bounds of the FRED event entry text. Every event delivered by FRED + * enters here, including events which the core entry code forwards + * through asm_fred_entry_from_kvm(). This is the FRED counterpart of + * __irqentry_text_start..__irqentry_text_end and lets + * in_irqentry_text() find the event entry point of a stack, see + * arch_in_irqentry_text(). + */ + .globl __fred_entry_text_start +__fred_entry_text_start: + SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user) FRED_ENTER call fred_entry_from_user @@ -150,3 +161,6 @@ SYM_FUNC_START(asm_fred_entry_from_kvm) SYM_FUNC_END(asm_fred_entry_from_kvm) #endif + + .globl __fred_entry_text_end +__fred_entry_text_end: diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 30e8ee7006f9..1b52239fcefd 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -5,6 +5,7 @@ #include <asm-generic/sections.h> #include <asm/extable.h> +extern char __fred_entry_text_start[], __fred_entry_text_end[]; extern char __relocate_kernel_start[], __relocate_kernel_end[]; extern char __brk_base[], __brk_limit[]; extern char __end_rodata_aligned[]; diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index ee117fcf46ed..4af7e52d9d97 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -9,6 +9,7 @@ #include <linux/stacktrace.h> #include <linux/export.h> #include <linux/uaccess.h> +#include <asm/sections.h> #include <asm/stacktrace.h> #include <asm/unwind.h> @@ -128,3 +129,15 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, } } +#ifdef CONFIG_X86_FRED +bool arch_in_irqentry_text(unsigned long addr) +{ + /* + * FRED delivers events to entry points in .noinstr.text, which + * __irqentry_text_start..__irqentry_text_end does not cover. See + * __fred_entry_text_start in entry_64_fred.S. + */ + return addr >= (unsigned long)__fred_entry_text_start && + addr < (unsigned long)__fred_entry_text_end; +} +#endif -- 2.43.5 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks 2026-08-27 15:00 ` [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks Yuanhe Shu @ 2026-08-27 21:26 ` H. Peter Anvin 2026-08-29 9:42 ` Peter Zijlstra 1 sibling, 0 replies; 7+ messages in thread From: H. Peter Anvin @ 2026-08-27 21:26 UTC (permalink / raw) To: Yuanhe Shu, tglx, mingo, bp, dave.hansen, x86 Cc: xin, luto, jpoimboe, peterz, rostedt, akpm, rdunlap, elver, andreyknvl, glider, gor, kasan-dev, linux-kernel, stable This all makes sense to me. I would in fact like to see the IDT-only code isolated so it can be poisoned if not used. The FRED code probably should be as well, although it is also used by KVM -- and potentially by other auxiliary users in the future -- so it might not make as much sense there. -hpa On 2026-08-27 08:00, Yuanhe Shu wrote: > With FRED, events are delivered to asm_fred_entrypoint_user and > asm_fred_entrypoint_kernel in .noinstr.text, not to the IDT stubs, which > are the only code covered by __irqentry_text_start..__irqentry_text_end. > in_irqentry_text() therefore never recognizes the event entry point and > filter_irq_stacks() does not truncate FRED event stacks: every trace > saved from interrupt or exception context by stack depot users such as > KASAN alloc/free tracking or SLUB object tracking combines the event path > with the arbitrarily interrupted context. The number of unique stacks > grows with the product of both and the depot is exhausted. > > Observed on a dual-socket FRED-capable system with KASAN (generic, > inline) and SLUB object tracking enabled, on both sockets roughly 80 > minutes after boot, once the depot had reached its maximum of 8192 pools > (128 MiB): > > Stack depot reached limit capacity > WARNING: CPU: 286 PID: 128614 at lib/stackdepot.c:271 depot_alloc_stack+0x158/0x170 > > The traces had the expected shape: an interrupt side trace ran through > asm_fred_entrypoint_kernel into the frames of the task it had > interrupted. New traces are dropped (handle 0) from then on and the > depot never shrinks, so tracking stays dead until reboot. (Splat from a > 6.6 based kernel; filter_irq_stacks() and the FRED entry layout are > unchanged in mainline.) > > The entry points cannot be brought inside that range. x86 has no > .irqentry.text: commit f0178fc01fe4 ("x86/entry: Unbreak > __irqentry_text_start/end magic") dropped it from the linker script and > emits the markers as labels around the sequentially laid out IDT stubs > instead, exactly because the entry rework had moved that code into > .noinstr.text and broken the function graph tracer and > filter_irq_stacks(); __irq_entry has been __invalid_section since. > Those labels live inside entry_64.S and wrap the IDT stubs which > asm/idtentry.h emits into .entry.text, so the linker cannot place > another translation unit between them, and the FRED entry points cannot > join that block without leaving .noinstr.text. Architectures which do > have the section fixed the same symptom locally, e.g. > commit f6794950f0e5 ("arm64: set __exception_irq_entry with __irq_entry > as a default") and commit 45c9f2b856a0 ("s390/entry: Mark IRQ entries > to fix stack depot warnings"). > > Every FRED event leaves a return address in the FRED entry text: the > return address of the call to fred_entry_from_user/kernel, or a frame of > asm_fred_entry_from_kvm(), which the core entry code uses to forward VMX > interrupts and NMIs acknowledged as part of the VM-Exit; see > commit 0701c9e17bd9 ("x86/kvm/vmx: Move IRQ/NMI dispatch from KVM > into x86 core"). So bracket it with __fred_entry_text_start/end, the > same way the IDT stubs are bracketed, and report that range from > arch_in_irqentry_text(). Verified on that system with the fix > backported: traces from FRED event context now end at > asm_fred_entrypoint_kernel (/sys/kernel/debug/slab/*/alloc_traces) and > the pool count levels off a few minutes after boot instead of climbing > to the limit. > > Truncating synchronous exception stacks only restores parity with the IDT > range, which has always covered the exception stubs too. Syscalls enter > through asm_fred_entrypoint_user as well, but there the entry frame is > already the last trace entry, so filter_irq_stacks() returns the full > trace unchanged. The function graph tracer uses the same markers and has > the same gap; it can be converted separately. > > This is not limited to FRED hardware: with CONFIG_X86_FRED=y the KVM > forwarding path above runs the FRED dispatch code even when the kernel > itself uses the IDT, so KVM host stacks take the same untruncated path > on non-FRED systems, albeit from a mostly fixed vcpu_run chain. > > Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code") > Cc: stable@vger.kernel.org # v6.9+ > Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com> > --- > Build tested with CONFIG_X86_FRED=y and CONFIG_X86_KERNEL_IBT=y, with > and without CONFIG_KVM_INTEL: __fred_entry_text_start lands on the > 4K-aligned asm_fred_entrypoint_user and the new range stays inside > .noinstr.text. > > Note for stable: depends on patch 1/2. > > arch/x86/Kconfig | 1 + > arch/x86/entry/entry_64_fred.S | 14 ++++++++++++++ > arch/x86/include/asm/sections.h | 1 + > arch/x86/kernel/stacktrace.c | 13 +++++++++++++ > 4 files changed, 29 insertions(+) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index 15fd9ec5ecac..78b8eb4a925f 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -555,6 +555,7 @@ config X86_CPU_RESCTRL_INTEL_AET > config X86_FRED > bool "Flexible Return and Event Delivery" > depends on X86_64 > + select ARCH_HAS_IN_IRQENTRY_TEXT > help > When enabled, use Flexible Return and Event Delivery > instead of the legacy SYSCALL/SYSENTER/IDT architecture for > diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S > index b98f8945dfff..620def9039a3 100644 > --- a/arch/x86/entry/entry_64_fred.S > +++ b/arch/x86/entry/entry_64_fred.S > @@ -36,6 +36,17 @@ > */ > .align 4096 > > +/* > + * Bounds of the FRED event entry text. Every event delivered by FRED > + * enters here, including events which the core entry code forwards > + * through asm_fred_entry_from_kvm(). This is the FRED counterpart of > + * __irqentry_text_start..__irqentry_text_end and lets > + * in_irqentry_text() find the event entry point of a stack, see > + * arch_in_irqentry_text(). > + */ > + .globl __fred_entry_text_start > +__fred_entry_text_start: > + > SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user) > FRED_ENTER > call fred_entry_from_user > @@ -150,3 +161,6 @@ SYM_FUNC_START(asm_fred_entry_from_kvm) > > SYM_FUNC_END(asm_fred_entry_from_kvm) > #endif > + > + .globl __fred_entry_text_end > +__fred_entry_text_end: > diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h > index 30e8ee7006f9..1b52239fcefd 100644 > --- a/arch/x86/include/asm/sections.h > +++ b/arch/x86/include/asm/sections.h > @@ -5,6 +5,7 @@ > #include <asm-generic/sections.h> > #include <asm/extable.h> > > +extern char __fred_entry_text_start[], __fred_entry_text_end[]; > extern char __relocate_kernel_start[], __relocate_kernel_end[]; > extern char __brk_base[], __brk_limit[]; > extern char __end_rodata_aligned[]; > diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c > index ee117fcf46ed..4af7e52d9d97 100644 > --- a/arch/x86/kernel/stacktrace.c > +++ b/arch/x86/kernel/stacktrace.c > @@ -9,6 +9,7 @@ > #include <linux/stacktrace.h> > #include <linux/export.h> > #include <linux/uaccess.h> > +#include <asm/sections.h> > #include <asm/stacktrace.h> > #include <asm/unwind.h> > > @@ -128,3 +129,15 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, > } > } > > +#ifdef CONFIG_X86_FRED > +bool arch_in_irqentry_text(unsigned long addr) > +{ > + /* > + * FRED delivers events to entry points in .noinstr.text, which > + * __irqentry_text_start..__irqentry_text_end does not cover. See > + * __fred_entry_text_start in entry_64_fred.S. > + */ > + return addr >= (unsigned long)__fred_entry_text_start && > + addr < (unsigned long)__fred_entry_text_end; > +} > +#endif ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks 2026-08-27 15:00 ` [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks Yuanhe Shu 2026-08-27 21:26 ` H. Peter Anvin @ 2026-08-29 9:42 ` Peter Zijlstra 1 sibling, 0 replies; 7+ messages in thread From: Peter Zijlstra @ 2026-08-29 9:42 UTC (permalink / raw) To: Yuanhe Shu Cc: tglx, mingo, bp, dave.hansen, x86, hpa, xin, luto, jpoimboe, rostedt, akpm, rdunlap, elver, andreyknvl, glider, gor, kasan-dev, linux-kernel, stable On Thu, Aug 27, 2026 at 11:00:22PM +0800, Yuanhe Shu wrote: > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index 15fd9ec5ecac..78b8eb4a925f 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -555,6 +555,7 @@ config X86_CPU_RESCTRL_INTEL_AET > config X86_FRED > bool "Flexible Return and Event Delivery" > depends on X86_64 > + select ARCH_HAS_IN_IRQENTRY_TEXT > help > When enabled, use Flexible Return and Event Delivery > instead of the legacy SYSCALL/SYSENTER/IDT architecture for I'm not sold on this being a CONFIG symbol, we have far too many of those. We have many other patterns that might work here. A common one for example is: #ifndef arch_in_irqentry_text static inline bool arch_in_irqentry_text(unsigned long addr) { return false; } #endif And then have the arch/x86/include/asm/ header do: #define arch_in_irqentry_text arch_in_irqentry_text. > diff --git a/arch/x86/entry/entry_64_fred.S b/arch/x86/entry/entry_64_fred.S > index b98f8945dfff..620def9039a3 100644 > --- a/arch/x86/entry/entry_64_fred.S > +++ b/arch/x86/entry/entry_64_fred.S > @@ -36,6 +36,17 @@ > */ > .align 4096 > > +/* > + * Bounds of the FRED event entry text. Every event delivered by FRED > + * enters here, including events which the core entry code forwards > + * through asm_fred_entry_from_kvm(). This is the FRED counterpart of > + * __irqentry_text_start..__irqentry_text_end and lets > + * in_irqentry_text() find the event entry point of a stack, see > + * arch_in_irqentry_text(). > + */ > + .globl __fred_entry_text_start > +__fred_entry_text_start: > + > SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user) > FRED_ENTER > call fred_entry_from_user > @@ -150,3 +161,6 @@ SYM_FUNC_START(asm_fred_entry_from_kvm) > > SYM_FUNC_END(asm_fred_entry_from_kvm) > #endif > + > + .globl __fred_entry_text_end > +__fred_entry_text_end: > diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h > index 30e8ee7006f9..1b52239fcefd 100644 > --- a/arch/x86/include/asm/sections.h > +++ b/arch/x86/include/asm/sections.h > @@ -5,6 +5,7 @@ > #include <asm-generic/sections.h> > #include <asm/extable.h> > > +extern char __fred_entry_text_start[], __fred_entry_text_end[]; > extern char __relocate_kernel_start[], __relocate_kernel_end[]; > extern char __brk_base[], __brk_limit[]; > extern char __end_rodata_aligned[]; > diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c > index ee117fcf46ed..4af7e52d9d97 100644 > --- a/arch/x86/kernel/stacktrace.c > +++ b/arch/x86/kernel/stacktrace.c > @@ -9,6 +9,7 @@ > #include <linux/stacktrace.h> > #include <linux/export.h> > #include <linux/uaccess.h> > +#include <asm/sections.h> > #include <asm/stacktrace.h> > #include <asm/unwind.h> > > @@ -128,3 +129,15 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, > } > } > > +#ifdef CONFIG_X86_FRED > +bool arch_in_irqentry_text(unsigned long addr) > +{ > + /* > + * FRED delivers events to entry points in .noinstr.text, which > + * __irqentry_text_start..__irqentry_text_end does not cover. See > + * __fred_entry_text_start in entry_64_fred.S. > + */ > + return addr >= (unsigned long)__fred_entry_text_start && > + addr < (unsigned long)__fred_entry_text_end; > +} > +#endif This is all confusing at best. __fred_entry_text covers all entries, it cannot distinguish between irqentry and syscall. Why is that not a problem? ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-29 9:42 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-08-27 15:00 [PATCH 0/2] x86/fred: Fix stack depot exhaustion on FRED systems Yuanhe Shu 2026-08-27 15:00 ` [PATCH 1/2] stacktrace: Provide arch_in_irqentry_text() hook Yuanhe Shu 2026-08-27 17:04 ` Bradley Morgan 2026-08-27 23:06 ` Andrew Morton 2026-08-27 15:00 ` [PATCH 2/2] x86/fred: Fix stack depot filtering of FRED event stacks Yuanhe Shu 2026-08-27 21:26 ` H. Peter Anvin 2026-08-29 9:42 ` Peter Zijlstra
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®