From: Masami Hiramatsu mhiramat@kernel.org
[ Upstream commit d0381c81c2f782fa2131178d11e0cfb23d50d631 ]
Set the pages which is used for kprobes' singlestep buffer and optprobe's trampoline instruction buffer to readonly. This can prevent unexpected (or unintended) instruction modification.
This also passes rodata_test as below.
Without this patch, rodata_test shows a warning:
WARNING: CPU: 0 PID: 1 at arch/x86/mm/dump_pagetables.c:235 note_page+0x7a9/0xa20 x86/mm: Found insecure W+X mapping at address ffffffffa0000000/0xffffffffa0000000
With this fix, no W+X pages are found:
x86/mm: Checked W+X mappings: passed, no W+X pages found. rodata_test: all tests were successful
Reported-by: Andrey Ryabinin aryabinin@virtuozzo.com Signed-off-by: Masami Hiramatsu mhiramat@kernel.org Cc: Ananth N Mavinakayanahalli ananth@linux.vnet.ibm.com Cc: Anil S Keshavamurthy anil.s.keshavamurthy@intel.com Cc: Borislav Petkov bp@alien8.de Cc: Brian Gerst brgerst@gmail.com Cc: David S . Miller davem@davemloft.net Cc: Denys Vlasenko dvlasenk@redhat.com Cc: H. Peter Anvin hpa@zytor.com Cc: Josh Poimboeuf jpoimboe@redhat.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Peter Zijlstra peterz@infradead.org Cc: Thomas Gleixner tglx@linutronix.de Cc: Ye Xiaolong xiaolong.ye@intel.com Link: http://lkml.kernel.org/r/149076375592.22469.14174394514338612247.stgit@devbo... Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Sasha Levin alexander.levin@microsoft.com --- arch/x86/kernel/kprobes/core.c | 4 ++++ arch/x86/kernel/kprobes/opt.c | 3 +++ 2 files changed, 7 insertions(+)
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 5d11d01f75de..565e24e9ddf2 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -406,6 +406,8 @@ static int arch_copy_kprobe(struct kprobe *p) { int ret;
+ set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Copy an instruction with recovering if other optprobe modifies it.*/ ret = __copy_instruction(p->ainsn.insn, p->addr); if (!ret) @@ -420,6 +422,8 @@ static int arch_copy_kprobe(struct kprobe *p) else p->ainsn.boostable = -1;
+ set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Check whether the instruction modifies Interrupt Flag or not */ p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn);
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index ea8e2b846101..7aba9d6475a5 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -370,6 +370,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, }
buf = (u8 *)op->optinsn.insn; + set_memory_rw((unsigned long)buf & PAGE_MASK, 1);
/* Copy instructions into the out-of-line buffer */ ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr); @@ -392,6 +393,8 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size, (u8 *)op->kp.addr + op->optinsn.size);
+ set_memory_ro((unsigned long)buf & PAGE_MASK, 1); + flush_icache_range((unsigned long) buf, (unsigned long) buf + TMPL_END_IDX + op->optinsn.size + RELATIVEJUMP_SIZE);