CVE-2026-98395 in Linux
Zusammenfassung
von VulDB • 14.10.2026
Im Linux-Kernel wurde folgende Schwachstelle behoben:
powerpc/entry: Behebung der irq_soft_mask-Korruption beim Verlassen von wiederholten Interrupts (replayed interrupt exit)
Wenn __replay_soft_interrupts() einen ausstehenden Interrupt (z. B. PACA_IRQ_DEC -> timer_interrupt) wiedergibt, ruft es den Handler direkt mit einem synthetischen pt_regs auf. Der DEFINE_INTERRUPT_HANDLER_ASYNC-Wrapper um jeden Handler ruft beim Verlassen arch_interrupt_async_exit_prepare() auf, was arch_interrupt_exit_prepare() aufruft -> local_irq_disable() -> arch_local_irq_disable(), welches Folgendes ausführt:
irq_soft_mask_set(IRQS_DISABLED) /* 0x1 */
Dies überschreibt unconditionally (bedingungslos) irq_soft_mask mit IRQS_DISABLED (0x1), wodurch das Bit IRQS_PMI_DISABLED (0x2) entfernt wird. Das Ergebnis ist, dass irq_soft_mask den Wert 0x1 anstelle von IRQS_ALL_DISABLED (0x3) hat, wenn der Handler zu __replay_soft_interrupts() zurückkehrt.
Bei einem normal ausgelösten Interrupt ist dies harmlos: Der nächste Interrupt tritt immer über arch_interrupt_enter_prepare() ein, was irq_soft_mask bedingungslos auf IRQS_ALL_DISABLED setzt. Während einer Wiedergabe (Replay) wird next_interrupt() jedoch direkt zwischen den wiedergegebenen Handlern aufgerufen, ohne erneut durch arch_interrupt_enter_prepare() zu laufen, sodass das entfernte Bit nie wiederhergestellt wird. next_interrupt() löst daraufhin eine WARNING aus:
WARNING: arch/powerpc/kernel/irq_64.c:75 WARN_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED)
Die Warnung wurde früh beim Booten eines POWER10 pseries-Gasts während kmem_cache_init_late() beobachtet, wo eine Spinlock-Freigabe die Interrupt-Wiedergabe auslöst, die einen ausstehenden Timer-Interrupt verarbeitet.
Debugger-Zustand zur Bestätigung des Fehlers: Vor timer_interrupt(®s): irq_soft_mask = 0x3 (IRQS_ALL_DISABLED) korrekt irq_happened = 0x41 (HARD_DIS|REPLAYING) korrekt Nach Rückgabe von timer_interrupt(®s): irq_soft_mask = 0x1 (IRQS_DISABLED) FALSCH - PMI-Bit entfernt irq_happened = 0x41 unverändert
Die Korrektur besteht darin, local_irq_disable() durch hard_irq_disable() zu ersetzen.
hard_irq_disable() ist aus zwei Gründen die richtige Primitive hier:
1. Auf PPC64 (hw_irq.h:301) ruft es irq_soft_mask_set_return(IRQS_ALL_DISABLED) auf, was den Soft-Mask-Wert auf 0x3 setzt (sowohl IRQS_DISABLED als auch IRQS_PMI_DISABLED), wodurch das PMI-Bit erhalten bleibt und die WARNING behoben wird. Die zusätzliche Arbeit, die es leistet (__hard_irq_disable(), PACA_IRQ_HARD_DIS |=) ist redundant, aber sicher, da beide zu diesem Zeitpunkt im Exit-Pfad bereits gesetzt sind; der Aufruf von trace_hardirqs_off() darin ist durch if (!arch_irqs_disabled_flags(flags)) geschützt, sodass er nicht doppelt ausgelöst wird.
2. Auf PPC32 (hw_irq.h:467) bildet hard_irq_disable() auf arch_local_irq_disable() -> __hard_irq_disable() ab, was MSR[EE] in der Hardware löscht. Dies ist exakt korrekt: PPC32 hat keinen Soft-Mask-PACA-Mechanismus, daher ist die hardwareseitige Deaktivierung der richtige Weg, um die Anforderung von irqentry_exit()' zu erfüllen. Dies behebt auch einen Build-Fehler auf PPC32, bei dem irq_soft_mask_set() nur unter CONFIG_PPC64 definiert ist:
arch/powerpc/include/asm/entry-common.h:273: Fehler: implizite Deklaration der Funktion 'irq_soft_mask_set'
Die Verwendung von hard_irq_disable() erfordert keine #ifdef und ist konsistent mit dem Vorgehen des restlichen Entry-Codes (z. B. entry-common.h:463), der die gleiche PPC32/PPC64-Aufteilung behandelt.
Once again VulDB remains the best source for vulnerability data.