mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-24 02:42:50 -04:00
x86/mm: Make use_/unuse_temporary_mm() non-static
This prepares them for use outside of the alternative machinery. The code is unchanged. Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Cc: Rik van Riel <riel@surriel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> Link: https://lore.kernel.org/r/20250402094540.3586683-4-mingo@kernel.org
This commit is contained in:
committed by
Ingo Molnar
parent
81e3cbdef2
commit
d376972c98
@@ -272,4 +272,7 @@ unsigned long __get_current_cr3_fast(void);
|
||||
|
||||
#include <asm-generic/mmu_context.h>
|
||||
|
||||
extern struct mm_struct *use_temporary_mm(struct mm_struct *temp_mm);
|
||||
extern void unuse_temporary_mm(struct mm_struct *mm, struct mm_struct *prev_mm);
|
||||
|
||||
#endif /* _ASM_X86_MMU_CONTEXT_H */
|
||||
|
||||
@@ -2111,73 +2111,9 @@ void __init_or_module text_poke_early(void *addr, const void *opcode,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Using a temporary mm allows to set temporary mappings that are not accessible
|
||||
* by other CPUs. Such mappings are needed to perform sensitive memory writes
|
||||
* that override the kernel memory protections (e.g., W^X), without exposing the
|
||||
* temporary page-table mappings that are required for these write operations to
|
||||
* other CPUs. Using a temporary mm also allows to avoid TLB shootdowns when the
|
||||
* mapping is torn down.
|
||||
*
|
||||
* Context: The temporary mm needs to be used exclusively by a single core. To
|
||||
* harden security IRQs must be disabled while the temporary mm is
|
||||
* loaded, thereby preventing interrupt handler bugs from overriding
|
||||
* the kernel memory protection.
|
||||
*/
|
||||
static inline struct mm_struct *use_temporary_mm(struct mm_struct *temp_mm)
|
||||
{
|
||||
struct mm_struct *prev_mm;
|
||||
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
/*
|
||||
* Make sure not to be in TLB lazy mode, as otherwise we'll end up
|
||||
* with a stale address space WITHOUT being in lazy mode after
|
||||
* restoring the previous mm.
|
||||
*/
|
||||
if (this_cpu_read(cpu_tlbstate_shared.is_lazy))
|
||||
leave_mm();
|
||||
|
||||
prev_mm = this_cpu_read(cpu_tlbstate.loaded_mm);
|
||||
switch_mm_irqs_off(NULL, temp_mm, current);
|
||||
|
||||
/*
|
||||
* If breakpoints are enabled, disable them while the temporary mm is
|
||||
* used. Userspace might set up watchpoints on addresses that are used
|
||||
* in the temporary mm, which would lead to wrong signals being sent or
|
||||
* crashes.
|
||||
*
|
||||
* Note that breakpoints are not disabled selectively, which also causes
|
||||
* kernel breakpoints (e.g., perf's) to be disabled. This might be
|
||||
* undesirable, but still seems reasonable as the code that runs in the
|
||||
* temporary mm should be short.
|
||||
*/
|
||||
if (hw_breakpoint_active())
|
||||
hw_breakpoint_disable();
|
||||
|
||||
return prev_mm;
|
||||
}
|
||||
|
||||
__ro_after_init struct mm_struct *text_poke_mm;
|
||||
__ro_after_init unsigned long text_poke_mm_addr;
|
||||
|
||||
static inline void unuse_temporary_mm(struct mm_struct *mm, struct mm_struct *prev_mm)
|
||||
{
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
switch_mm_irqs_off(NULL, prev_mm, current);
|
||||
|
||||
/* Clear the cpumask, to indicate no TLB flushing is needed anywhere */
|
||||
cpumask_clear_cpu(raw_smp_processor_id(), mm_cpumask(mm));
|
||||
|
||||
/*
|
||||
* Restore the breakpoints if they were disabled before the temporary mm
|
||||
* was loaded.
|
||||
*/
|
||||
if (hw_breakpoint_active())
|
||||
hw_breakpoint_restore();
|
||||
}
|
||||
|
||||
static void text_poke_memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
memcpy(dst, src, len);
|
||||
|
||||
@@ -971,6 +971,70 @@ void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
|
||||
this_cpu_write(cpu_tlbstate_shared.is_lazy, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Using a temporary mm allows to set temporary mappings that are not accessible
|
||||
* by other CPUs. Such mappings are needed to perform sensitive memory writes
|
||||
* that override the kernel memory protections (e.g., W^X), without exposing the
|
||||
* temporary page-table mappings that are required for these write operations to
|
||||
* other CPUs. Using a temporary mm also allows to avoid TLB shootdowns when the
|
||||
* mapping is torn down.
|
||||
*
|
||||
* Context: The temporary mm needs to be used exclusively by a single core. To
|
||||
* harden security IRQs must be disabled while the temporary mm is
|
||||
* loaded, thereby preventing interrupt handler bugs from overriding
|
||||
* the kernel memory protection.
|
||||
*/
|
||||
struct mm_struct *use_temporary_mm(struct mm_struct *temp_mm)
|
||||
{
|
||||
struct mm_struct *prev_mm;
|
||||
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
/*
|
||||
* Make sure not to be in TLB lazy mode, as otherwise we'll end up
|
||||
* with a stale address space WITHOUT being in lazy mode after
|
||||
* restoring the previous mm.
|
||||
*/
|
||||
if (this_cpu_read(cpu_tlbstate_shared.is_lazy))
|
||||
leave_mm();
|
||||
|
||||
prev_mm = this_cpu_read(cpu_tlbstate.loaded_mm);
|
||||
switch_mm_irqs_off(NULL, temp_mm, current);
|
||||
|
||||
/*
|
||||
* If breakpoints are enabled, disable them while the temporary mm is
|
||||
* used. Userspace might set up watchpoints on addresses that are used
|
||||
* in the temporary mm, which would lead to wrong signals being sent or
|
||||
* crashes.
|
||||
*
|
||||
* Note that breakpoints are not disabled selectively, which also causes
|
||||
* kernel breakpoints (e.g., perf's) to be disabled. This might be
|
||||
* undesirable, but still seems reasonable as the code that runs in the
|
||||
* temporary mm should be short.
|
||||
*/
|
||||
if (hw_breakpoint_active())
|
||||
hw_breakpoint_disable();
|
||||
|
||||
return prev_mm;
|
||||
}
|
||||
|
||||
void unuse_temporary_mm(struct mm_struct *mm, struct mm_struct *prev_mm)
|
||||
{
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
switch_mm_irqs_off(NULL, prev_mm, current);
|
||||
|
||||
/* Clear the cpumask, to indicate no TLB flushing is needed anywhere */
|
||||
cpumask_clear_cpu(raw_smp_processor_id(), mm_cpumask(mm));
|
||||
|
||||
/*
|
||||
* Restore the breakpoints if they were disabled before the temporary mm
|
||||
* was loaded.
|
||||
*/
|
||||
if (hw_breakpoint_active())
|
||||
hw_breakpoint_restore();
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this when reinitializing a CPU. It fixes the following potential
|
||||
* problems:
|
||||
|
||||
Reference in New Issue
Block a user