FAILED: patch "[PATCH] MIPS: math-emu: Write-protect delay slot emulation pages" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From adcc81f148d733b7e8e641300c5590a2cdc13bf3 Mon Sep 17 00:00:00 2001
From: Paul Burton <[email protected]>
Date: Thu, 20 Dec 2018 17:45:43 +0000
Subject: [PATCH] MIPS: math-emu: Write-protect delay slot emulation pages
Mapping the delay slot emulation page as both writeable & executable presents a security risk, in that if an exploit can write to & jump into the page then it can be used as an easy way to execute arbitrary code.
Prevent this by mapping the page read-only for userland, and using access_process_vm() with the FOLL_FORCE flag to write to it from mips_dsemul().
This will likely be less efficient due to copy_to_user_page() performing cache maintenance on a whole page, rather than a single line as in the previous use of flush_cache_sigtramp(). However this delay slot emulation code ought not to be running in any performance critical paths anyway so this isn't really a problem, and we can probably do better in copy_to_user_page() anyway in future.
A major advantage of this approach is that the fix is small & simple to backport to stable kernels.
arch/mips/kernel/vdso.c +2 -2
@@ -126,8 +126,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)/* Map delay slot emulation page */ base =mmap_region (NULL ,STACK_TOP ,PAGE_SIZE , -VM_READ |VM_WRITE |VM_EXEC | -VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC , +VM_READ |VM_EXEC | +VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ,0 ,NULL );if (IS_ERR_VALUE (base)) { ret = base;
arch/mips/math-emu/dsemul.c +20 -18
@@ -214,8 +214,9 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, {int isa16 =get_isa16_mode (regs->cp0_epc);mips_instruction break_math; -struct emuframe __user *fr; -int err, fr_idx; +unsigned long fr_uaddr; +struct emuframe fr; +int fr_idx, ret;/* NOP is easy */ if (ir ==0 )
@@ -250,27 +251,31 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, fr_idx =alloc_emuframe ();if (fr_idx ==BD_EMUFRAME_NONE )return SIGBUS ; - fr = &dsemul_page ()[fr_idx];/* Retrieve the appropriately encoded break instruction */ break_math =BREAK_MATH (isa16);/* Write the instructions to the frame */ if (isa16) { - err =__put_user (ir >>16 , - (u16 __user *)(&fr->emul)); - err |=__put_user (ir &0xffff , - (u16 __user *)((long )(&fr->emul) +2 )); - err |=__put_user (break_math >>16 , - (u16 __user *)(&fr->badinst)); - err |=__put_user (break_math &0xffff , - (u16 __user *)((long )(&fr->badinst) +2 )); +union mips_instruction _emul = { + .halfword = { ir >>16 , ir } + }; +union mips_instruction _badinst = { + .halfword = { break_math >>16 , break_math } + }; + + fr.emul = _emul.word; + fr.badinst = _badinst.word; }else { - err =__put_user (ir, &fr->emul); - err |=__put_user (break_math, &fr->badinst); + fr.emul = ir; + fr.badinst = break_math; } -if (unlikely (err)) { +/* Write the frame to user memory */ + fr_uaddr = (unsigned long )&dsemul_page ()[fr_idx]; + ret =access_process_vm (current, fr_uaddr, &fr,sizeof (fr), +FOLL_FORCE |FOLL_WRITE ); +if (unlikely (ret !=sizeof (fr))) {MIPS_FPU_EMU_INC_STATS (errors);free_emuframe (fr_idx, current->mm);return SIGBUS ;
@@ -282,10 +287,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir,atomic_set (¤t->thread.bd_emu_frame, fr_idx);/* Change user register context to execute the frame */ - regs->cp0_epc = (unsigned long )&fr->emul | isa16; - -/* Ensure the icache observes our newly written frame */ -flush_cache_sigtramp ((unsigned long )&fr->emul); + regs->cp0_epc = fr_uaddr | isa16;return 0 ; }
PATCH 1/1 MIPS: math-emu: Write-protect delay slot emulation pages
commit adcc81f148d733b7e8e641300c5590a2cdc13bf3 upstream.
Mapping the delay slot emulation page as both writeable & executable presents a security risk, in that if an exploit can write to & jump into the page then it can be used as an easy way to execute arbitrary code.
Prevent this by mapping the page read-only for userland, and using access_process_vm() with the FOLL_FORCE flag to write to it from mips_dsemul().
This will likely be less efficient due to copy_to_user_page() performing cache maintenance on a whole page, rather than a single line as in the previous use of flush_cache_sigtramp(). However this delay slot emulation code ought not to be running in any performance critical paths anyway so this isn't really a problem, and we can probably do better in copy_to_user_page() anyway in future.
A major advantage of this approach is that the fix is small & simple to backport to stable kernels.
--- arch/mips/kernel/vdso.c | 4 ++-- arch/mips/math-emu/dsemul.c | 38 +++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 20 deletions(-)
arch/mips/kernel/vdso.c +2 -2
@@ -111,8 +111,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)/* Map delay slot emulation page */ base =mmap_region (NULL ,STACK_TOP ,PAGE_SIZE , -VM_READ |VM_WRITE |VM_EXEC | -VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC , +VM_READ |VM_EXEC | +VM_MAYREAD |VM_MAYWRITE |VM_MAYEXEC ,0 );if (IS_ERR_VALUE (base)) { ret = base;
arch/mips/math-emu/dsemul.c +20 -18
@@ -211,8 +211,9 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, {int isa16 =get_isa16_mode (regs->cp0_epc);mips_instruction break_math; -struct emuframe __user *fr; -int err, fr_idx; +unsigned long fr_uaddr; +struct emuframe fr; +int fr_idx, ret;/* NOP is easy */ if (ir ==0 )
@@ -247,27 +248,31 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, fr_idx =alloc_emuframe ();if (fr_idx ==BD_EMUFRAME_NONE )return SIGBUS ; - fr = &dsemul_page ()[fr_idx];/* Retrieve the appropriately encoded break instruction */ break_math =BREAK_MATH (isa16);/* Write the instructions to the frame */ if (isa16) { - err =__put_user (ir >>16 , - (u16 __user *)(&fr->emul)); - err |=__put_user (ir &0xffff , - (u16 __user *)((long )(&fr->emul) +2 )); - err |=__put_user (break_math >>16 , - (u16 __user *)(&fr->badinst)); - err |=__put_user (break_math &0xffff , - (u16 __user *)((long )(&fr->badinst) +2 )); +union mips_instruction _emul = { + .halfword = { ir >>16 , ir } + }; +union mips_instruction _badinst = { + .halfword = { break_math >>16 , break_math } + }; + + fr.emul = _emul.word; + fr.badinst = _badinst.word; }else { - err =__put_user (ir, &fr->emul); - err |=__put_user (break_math, &fr->badinst); + fr.emul = ir; + fr.badinst = break_math; } -if (unlikely (err)) { +/* Write the frame to user memory */ + fr_uaddr = (unsigned long )&dsemul_page ()[fr_idx]; + ret =access_process_vm (current, fr_uaddr, &fr,sizeof (fr), +FOLL_FORCE |FOLL_WRITE ); +if (unlikely (ret !=sizeof (fr))) {MIPS_FPU_EMU_INC_STATS (errors);free_emuframe (fr_idx, current->mm);return SIGBUS ;
@@ -279,10 +284,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir,atomic_set (¤t->thread.bd_emu_frame, fr_idx);/* Change user register context to execute the frame */ - regs->cp0_epc = (unsigned long )&fr->emul | isa16; - -/* Ensure the icache observes our newly written frame */ -flush_cache_sigtramp ((unsigned long )&fr->emul); + regs->cp0_epc = fr_uaddr | isa16;return 0 ; }
Signature · 1 line
2.20.1
[email protected]
maintainerRe: [4.9 PATCH] MIPS: math-emu: Write-protect delay slot emulation pages
Quoted 28 lines · Paul Burton
commit
adcc81f148d733b7e8e641300c5590a2cdc13bf3upstream.Mapping the delay slot emulation page as both writeable & executable presents a security risk, in that if an exploit can write to & jump into the page then it can be used as an easy way to execute arbitrary code.
Prevent this by mapping the page read-only for userland, and using
access_process_vm()with theFOLL_FORCEflag to write to it frommips_dsemul().This will likely be less efficient due to
copy_to_user_page()performing cache maintenance on a whole page, rather than a single line as in the previous use offlush_cache_sigtramp(). However this delay slot emulation code ought not to be running in any performance critical paths anyway so this isn't really a problem, and we can probably do better incopy_to_user_page()anyway in future.A major advantage of this approach is that the fix is small & simple to backport to stable kernels.
Reported-by Andy Lutomirski <[email protected]>Signed-off-by Paul Burton <[email protected]>Fixes 432c6bacbd0c ("MIPS: Use per-mm page to execute branch delay slot instructions")Cc [email protected] # v4.8+Cc Rich Felker <[email protected]>Cc David Daney <[email protected]>
Quoted 5 lines
--- arch/mips/kernel/vdso.c | 4 ++-- arch/mips/math-emu/dsemul.c | 38 +++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 20 deletions(-)
Thanks for the backport, now queued up.
greg k-h