Skip to content

Commit 8f588af

Browse files
torvaldsIngo Molnar
authored andcommitted
x86/mm: Get rid of conditional IF flag handling in page fault path
We had this nonsensical code that would happily handle kernel page faults with interrupts disabled, which makes no sense at all. It turns out that this is legacy code that _used_ to make sense, back when we enabled IRQs as early as possible, and we used to have this code sequence essentially immediately after reading the faulting address from the %cr2 register. Back then, we could have kernel page faults to populate the vmalloc area with interrupts disabled, and they would need to stay disabled for that case. However, the code in question has been moved down in the page fault handling, and is now in the "handle faults in user addresses" section, and apparently nobody ever noticed that it no longer makes sense to handle these page faults with interrupts conditionally disabled. So replace the conditional IRQ enable: if (regs->flags & X86_EFLAGS_IF) local_irq_enable(); with an unconditional one, and add a temporary WARN_ON_ONCE() if some codepath actually does do page faults with interrupts disabled (without also doing a pagefault_disable(), of course). NOTE! We used to allow user space to disable interrupts with iopl(3). That is no longer true since commits: a24ca99 ("x86/iopl: Remove legacy IOPL option") b968e84 ("x86/iopl: Fake iopl(3) CLI/STI usage") so the WARN_ON_ONCE() is valid for both the kernel and user situation. For some of the history relevant to this code, see particularly commit 8c914cb ("x86_64: actively synchronize vmalloc area when registering certain callbacks"), which moved this below the vmalloc fault handling. Now that the user_mode() check is irrelevant, we can also move the FAULT_FLAG_USER flag setting down to where the other flag settings are done. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Uros Bizjak <ubizjak@gmail.com> Cc: Sean Christopherson <seanjc@google.com> Link: https://lore.kernel.org/r/20240125173457.1281880-1-torvalds@linux-foundation.org
1 parent 42ac0be commit 8f588af

File tree

1 file changed

+14
-13
lines changed

1 file changed

+14
-13
lines changed

arch/x86/mm/fault.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,21 +1302,14 @@ void do_user_addr_fault(struct pt_regs *regs,
13021302
return;
13031303
}
13041304

1305-
/*
1306-
* It's safe to allow irq's after cr2 has been saved and the
1307-
* vmalloc fault has been handled.
1308-
*
1309-
* User-mode registers count as a user access even for any
1310-
* potential system fault or CPU buglet:
1311-
*/
1312-
if (user_mode(regs)) {
1313-
local_irq_enable();
1314-
flags |= FAULT_FLAG_USER;
1315-
} else {
1316-
if (regs->flags & X86_EFLAGS_IF)
1317-
local_irq_enable();
1305+
/* Legacy check - remove this after verifying that it doesn't trigger */
1306+
if (WARN_ON_ONCE(!(regs->flags & X86_EFLAGS_IF))) {
1307+
bad_area_nosemaphore(regs, error_code, address);
1308+
return;
13181309
}
13191310

1311+
local_irq_enable();
1312+
13201313
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
13211314

13221315
/*
@@ -1332,6 +1325,14 @@ void do_user_addr_fault(struct pt_regs *regs,
13321325
if (error_code & X86_PF_INSTR)
13331326
flags |= FAULT_FLAG_INSTRUCTION;
13341327

1328+
/*
1329+
* We set FAULT_FLAG_USER based on the register state, not
1330+
* based on X86_PF_USER. User space accesses that cause
1331+
* system page faults are still user accesses.
1332+
*/
1333+
if (user_mode(regs))
1334+
flags |= FAULT_FLAG_USER;
1335+
13351336
#ifdef CONFIG_X86_64
13361337
/*
13371338
* Faults in the vsyscall page might need emulation. The

0 commit comments

Comments
 (0)