Merged today for the Linux 6.19 Git kernel and then in turn for back-porting to prior Linux kernel series is making the x86 page fault handling code disable interrupts properly. Since 2020 it turns out the handling was subtly wrong but now corrected by Intel.
Cedric Xing of Intel tracked down the issue and fix to the page fault handling code for properly disabling interrupts. Cedric explained in the now-merged patch:
“There’s a big comment in the x86 do_page_fault() about our interrupt disabling code:
* User address page fault handling might have reenabled
* interrupts. Fixing up all potential exit points of
* do_user_addr_fault() and its leaf functions is just not
* doable w/o creating an unholy mess or turning the code
* upside down.but it turns out that comment is subtly wrong, and the code as a result is also wrong.
Because it’s certainly true that we may have re-enabled interrupts when handling user page faults. And it’s most certainly true that we don’t want to bother fixing up all the cases.
But what isn’t true is that it’s limited to user address page faults.
The confusion stems from the fact that we have logic here that depends on the address range of the access, but other code then depends on the _context_ the access was done in. The two are not related, even though both of them are about user-vs-kernel.
In other words, both user and kernel addresses can cause interrupts to have been enabled (eg when __bad_area_nosemaphore() gets called for user accesses to kernel addresses). As a result we should make sure to disable interrupts again regardless of the address range before returning to the low-level fault handling code.
The __bad_area_nosemaphore() code actually did disable interrupts again after enabling them, just not consistently. Ironically, as noted in the original comment, fixing up all the cases is just not worth it, when the simple solution is to just do it unconditionally in one single place.
So remove the incomplete case that unsuccessfully tried to do what the comment said was “not doable” in commit ca4c6a9858c2 (“x86/traps: Make interrupt enable/disable symmetric in C code”), and just make it do the simple and straightforward thing.”
The problematic code had been around going back to the Linux 5.8 merge window in 2020.
