PT-2026-114374 · Linux · Linux
CVE-2026-98395
·
Published
2026-10-14
·
Updated
2026-10-14
None
No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
powerpc/entry: Fix irq soft mask corruption on replayed interrupt exit
When replay soft interrupts() replays a pending interrupt (e.g.
PACA IRQ DEC -> timer interrupt), it calls the handler directly with a
synthetic pt regs. The DEFINE INTERRUPT HANDLER ASYNC wrapper around
each handler calls arch interrupt async exit prepare() on the way out,
which calls arch interrupt exit prepare() -> local irq disable() ->
arch local irq disable(), which does:
irq soft mask set(IRQS DISABLED) /* 0x1 */
This unconditionally overwrites irq soft mask with IRQS DISABLED (0x1),
stripping the IRQS PMI DISABLED (0x2) bit. The result is that
irq soft mask is 0x1 instead of IRQS ALL DISABLED (0x3) when the
handler returns to replay soft interrupts().
For a normally-taken interrupt this is harmless: the next interrupt
always enters through arch interrupt enter prepare() which
unconditionally sets irq soft mask to IRQS ALL DISABLED. But during
replay, next interrupt() is called directly between replayed handlers
without going back through arch interrupt enter prepare(), so the
stripped bit is never restored. next interrupt() then fires a WARNING:
WARNING: arch/powerpc/kernel/irq 64.c:75
WARN ON(irq soft mask return() != IRQS ALL DISABLED)
The warning was observed early in boot on a POWER10 pseries guest
during kmem cache init late(), where a spinlock release triggers
interrupt replay that processes a pending timer interrupt.
Debugger state confirming the bug:
Before timer interrupt(®s):
irq soft mask = 0x3 (IRQS ALL DISABLED) correct
irq happened = 0x41 (HARD DIS|REPLAYING) correct
After timer interrupt(®s) returns:
irq soft mask = 0x1 (IRQS DISABLED) WRONG - PMI bit stripped
irq happened = 0x41 unchanged
The fix is to replace local irq disable() with hard irq disable().
hard irq disable() is the right primitive here for two reasons:
-
On PPC64 (hw irq.h:301) it calls irq soft mask set return(IRQS ALL DISABLED), setting the soft mask to 0x3 (both IRQS DISABLED and IRQS PMI DISABLED), which preserves the PMI bit and fixes the WARNING. The additional work it does ( hard irq disable(), PACA IRQ HARD DIS |=) is redundant but safe since both are already set at this point in the exit path; the trace hardirqs off() inside is guarded by if (!arch irqs disabled flags(flags)) so it will not double-fire.
-
On PPC32 (hw irq.h:467) hard irq disable() maps to arch local irq disable() -> hard irq disable(), which clears MSR[EE] in hardware. This is exactly correct: PPC32 has no soft-mask PACA mechanism, so the hardware disable is the right way to satisfy irqentry exit()'s requirement. This also fixes a build error on PPC32 where irq soft mask set() is only defined under CONFIG PPC64:arch/powerpc/include/asm/entry-common.h:273: error: implicit declaration of function 'irq soft mask set'
Using hard irq disable() requires no #ifdef and is consistent with
how the rest of the entry code (e.g. entry-common.h:463) handles the
same PPC32/PPC64 split.
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Linux