|
Message-Id: <C3DYHECUQCQV.A48HK99GLB15@geist> Date: Wed, 10 Jun 2020 22:34:42 -0500 From: "Christopher M. Riedl" <cmr@...ormatik.wtf> To: "Christophe Leroy" <christophe.leroy@...roup.eu>, <linuxppc-dev@...ts.ozlabs.org>, <kernel-hardening@...ts.openwall.com> Subject: Re: [PATCH 1/5] powerpc/mm: Introduce temporary mm On Wed Jun 3, 2020 at 8:58 AM, Christophe Leroy wrote: > > > > > Le 03/06/2020 à 07:19, Christopher M. Riedl a écrit : > > x86 supports the notion of a temporary mm which restricts access to > > temporary PTEs to a single CPU. A temporary mm is useful for situations > > where a CPU needs to perform sensitive operations (such as patching a > > STRICT_KERNEL_RWX kernel) requiring temporary mappings without exposing > > said mappings to other CPUs. A side benefit is that other CPU TLBs do > > not need to be flushed when the temporary mm is torn down. > > > > Mappings in the temporary mm can be set in the userspace portion of the > > address-space. > > > > Interrupts must be disabled while the temporary mm is in use. HW > > breakpoints, which may have been set by userspace as watchpoints on > > addresses now within the temporary mm, are saved and disabled when > > loading the temporary mm. The HW breakpoints are restored when unloading > > the temporary mm. All HW breakpoints are indiscriminately disabled while > > the temporary mm is in use. > > > > Based on x86 implementation: > > > > commit cefa929c034e > > ("x86/mm: Introduce temporary mm structs") > > > > Signed-off-by: Christopher M. Riedl <cmr@...ormatik.wtf> > > --- > > arch/powerpc/include/asm/debug.h | 1 + > > arch/powerpc/include/asm/mmu_context.h | 64 ++++++++++++++++++++++++++ > > arch/powerpc/kernel/process.c | 5 ++ > > 3 files changed, 70 insertions(+) > > > > diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h > > index ec57daf87f40..827350c9bcf3 100644 > > --- a/arch/powerpc/include/asm/debug.h > > +++ b/arch/powerpc/include/asm/debug.h > > @@ -46,6 +46,7 @@ static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } > > #endif > > > > void __set_breakpoint(int nr, struct arch_hw_breakpoint *brk); > > +void __get_breakpoint(int nr, struct arch_hw_breakpoint *brk); > > bool ppc_breakpoint_available(void); > > #ifdef CONFIG_PPC_ADV_DEBUG_REGS > > extern void do_send_trap(struct pt_regs *regs, unsigned long address, > > diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h > > index 1a474f6b1992..9269c7c7b04e 100644 > > --- a/arch/powerpc/include/asm/mmu_context.h > > +++ b/arch/powerpc/include/asm/mmu_context.h > > @@ -10,6 +10,7 @@ > > #include <asm/mmu.h> > > #include <asm/cputable.h> > > #include <asm/cputhreads.h> > > +#include <asm/debug.h> > > > > /* > > * Most if the context management is out of line > > @@ -300,5 +301,68 @@ static inline int arch_dup_mmap(struct mm_struct *oldmm, > > return 0; > > } > > > > +struct temp_mm { > > + struct mm_struct *temp; > > + struct mm_struct *prev; > > + bool is_kernel_thread; > > + struct arch_hw_breakpoint brk[HBP_NUM_MAX]; > > +}; > > + > > +static inline void init_temp_mm(struct temp_mm *temp_mm, struct mm_struct *mm) > > +{ > > + temp_mm->temp = mm; > > + temp_mm->prev = NULL; > > + temp_mm->is_kernel_thread = false; > > + memset(&temp_mm->brk, 0, sizeof(temp_mm->brk)); > > +} > > + > > +static inline void use_temporary_mm(struct temp_mm *temp_mm) > > +{ > > + lockdep_assert_irqs_disabled(); > > + > > + temp_mm->is_kernel_thread = current->mm == NULL; > > + if (temp_mm->is_kernel_thread) > > + temp_mm->prev = current->active_mm; > > + else > > + temp_mm->prev = current->mm; > > > Is that necessary to make different for kernel threads ? When I look at > x86 implementation, they don't do such a thing. > Yup, in do_slb_fault we error out if the current->mm is NULL resulting in spectacular fails during patching w/ hash mmu. > > > + > > + /* > > + * Hash requires a non-NULL current->mm to allocate a userspace address > > + * when handling a page fault. Does not appear to hurt in Radix either. > > + */ > > + current->mm = temp_mm->temp; > > + switch_mm_irqs_off(NULL, temp_mm->temp, current); > > + > > + if (ppc_breakpoint_available()) { > > + struct arch_hw_breakpoint null_brk = {0}; > > + int i = 0; > > + > > + for (; i < nr_wp_slots(); ++i) { > > + __get_breakpoint(i, &temp_mm->brk[i]); > > + if (temp_mm->brk[i].type != 0) > > + __set_breakpoint(i, &null_brk); > > + } > > + } > > +} > > + > > +static inline void unuse_temporary_mm(struct temp_mm *temp_mm) > > +{ > > + lockdep_assert_irqs_disabled(); > > + > > + if (temp_mm->is_kernel_thread) > > + current->mm = NULL; > > + else > > + current->mm = temp_mm->prev; > > + switch_mm_irqs_off(NULL, temp_mm->prev, current); > > + > > + if (ppc_breakpoint_available()) { > > + int i = 0; > > + > > + for (; i < nr_wp_slots(); ++i) > > + if (temp_mm->brk[i].type != 0) > > + __set_breakpoint(i, &temp_mm->brk[i]); > > + } > > +} > > + > > #endif /* __KERNEL__ */ > > #endif /* __ASM_POWERPC_MMU_CONTEXT_H */ > > diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c > > index 048d64c4e115..3973144f6980 100644 > > --- a/arch/powerpc/kernel/process.c > > +++ b/arch/powerpc/kernel/process.c > > @@ -825,6 +825,11 @@ static inline int set_breakpoint_8xx(struct arch_hw_breakpoint *brk) > > return 0; > > } > > > > +void __get_breakpoint(int nr, struct arch_hw_breakpoint *brk) > > +{ > > + memcpy(brk, this_cpu_ptr(¤t_brk[nr]), sizeof(*brk)); > > +} > > + > > void __set_breakpoint(int nr, struct arch_hw_breakpoint *brk) > > { > > memcpy(this_cpu_ptr(¤t_brk[nr]), brk, sizeof(*brk)); > > > > > Christophe > > > >
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.