In the Linux kernel, the following vulnerability has been resolved:
arm64: entry: always set GICPRIOPSRISET during entry
Zenghui reports that booting a kernel with "irqchip.gicv3pseudonmi=1" on the command line hits a warning during kernel entry, due to the way we manipulate the PMR.
Early in the entry sequence, we call lockdephardirqsoff() to inform lockdep that interrupts have been masked (as the HW sets DAIF wqhen entering an exception). Architecturally PMREL1 is not affected by exception entry, and we don't set GICPRIOPSRI_SET in the PMR early in the exception entry sequence, so early in exception entry the PMR can indicate that interrupts are unmasked even though they are masked by DAIF.
If DEBUGLOCKDEP is selected, lockdephardirqsoff() will check that interrupts are masked, before we set GICPRIOPSRISET in any of the exception entry paths, and hence lockdephardirqs_off() will WARN() that something is amiss.
We can avoid this by consistently setting GICPRIOPSRISET during exception entry so that kernel code sees a consistent environment. We must also update localdaifinherit() to undo this, as currently only touches DAIF. For other paths, localdaifrestore() will update both DAIF and the PMR. With this done, we can remove the existing special cases which set this later in the entry code.
We always use (GICPRIOIRQON | GICPRIOPSRISET) for consistency with localdaifsave(), as this will warn if it ever encounters (GICPRIOIRQOFF | GICPRIOPSRISET), and never sets this itself. This matches the gicpriokentrysetup that we have to retain for retto_user.
The original splat from Zenghui's report was:
| DEBUGLOCKSWARNON(!irqsdisabled()) | WARNING: CPU: 3 PID: 125 at kernel/locking/lockdep.c:4258 lockdephardirqsoff+0xd4/0xe8 | Modules linked in: | CPU: 3 PID: 125 Comm: modprobe Tainted: G W 5.12.0-rc8+ #463 | Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 | pstate: 604003c5 (nZCv DAIF +PAN -UAO -TCO BTYPE=--) | pc : lockdephardirqsoff+0xd4/0xe8 | lr : lockdephardirqsoff+0xd4/0xe8 | sp : ffff80002a39bad0 | pmrsave: 000000e0 | x29: ffff80002a39bad0 x28: ffff0000de214bc0 | x27: ffff0000de1c0400 x26: 000000000049b328 | x25: 0000000000406f30 x24: ffff0000de1c00a0 | x23: 0000000020400005 x22: ffff8000105f747c | x21: 0000000096000044 x20: 0000000000498ef9 | x19: ffff80002a39bc88 x18: ffffffffffffffff | x17: 0000000000000000 x16: ffff800011c61eb0 | x15: ffff800011700a88 x14: 0720072007200720 | x13: 0720072007200720 x12: 0720072007200720 | x11: 0720072007200720 x10: 0720072007200720 | x9 : ffff80002a39bad0 x8 : ffff80002a39bad0 | x7 : ffff8000119f0800 x6 : c0000000ffff7fff | x5 : ffff8000119f07a8 x4 : 0000000000000001 | x3 : 9bcdab23f2432800 x2 : ffff800011730538 | x1 : 9bcdab23f2432800 x0 : 0000000000000000 | Call trace: | lockdephardirqsoff+0xd4/0xe8 | enterfromkernelmode.isra.5+0x7c/0xa8 | el1abort+0x24/0x100 | el1synchandler+0x80/0xd0 | el1sync+0x6c/0x100 | _archclearuser+0xc/0x90 | loadelfbinary+0x9fc/0x1450 | bprmexecve+0x404/0x880 | kernelexecve+0x180/0x188 | callusermodehelperexecasync+0xdc/0x158 | retfromfork+0x10/0x18