From b61e1f3281c5a53f24f47849873463514f58c1b8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 18 Sep 2020 10:26:19 +0200 Subject: s390/kprobes: move insn_page to text segment Move the in-kernel kprobes insn page to text segment. Rationale: having that page in rw data segment is suboptimal, since as soon as a kprobe is set, this will split the 1:1 kernel mapping for a single page which get new permissions. Note: there is always at least one kprobe present for the kretprobe trampoline; so the mapping will always be split into smaller 4k mappings because of this. Moving the kprobes insn page into text segment makes sure that the page is mapped RO/X in any case, and avoids that the 1:1 mapping is split. The kprobe insn_page is defined as a dummy function which is filled with "br %r14" instructions. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/Makefile | 1 + arch/s390/kernel/entry.h | 2 ++ arch/s390/kernel/kprobes.c | 6 ++---- arch/s390/kernel/kprobes_insn_page.S | 22 ++++++++++++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 arch/s390/kernel/kprobes_insn_page.S (limited to 'arch/s390') diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index efca70970761..dd73b7f07423 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_COMPAT) += $(compat-obj-y) obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_KPROBES) += kprobes_insn_page.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UPROBES) += uprobes.o diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 6475a885cd60..0f7e4e9176e0 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -87,4 +87,6 @@ void set_fs_fixup(void); unsigned long stack_alloc(void); void stack_free(unsigned long stack); +extern char kprobes_insn_page[]; + #endif /* _ENTRY_H */ diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index b34fa4eef742..6574774d404e 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -22,6 +22,7 @@ #include #include #include +#include "entry.h" DEFINE_PER_CPU(struct kprobe *, current_kprobe); DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); @@ -31,7 +32,6 @@ struct kretprobe_blackpoint kretprobe_blacklist[] = { }; DEFINE_INSN_CACHE_OPS(s390_insn); static int insn_page_in_use; -static char insn_page[PAGE_SIZE] __aligned(PAGE_SIZE); void *alloc_insn_page(void) { @@ -53,13 +53,11 @@ static void *alloc_s390_insn_page(void) { if (xchg(&insn_page_in_use, 1) == 1) return NULL; - __set_memory((unsigned long) &insn_page, 1, SET_MEMORY_RO | SET_MEMORY_X); - return &insn_page; + return &kprobes_insn_page; } static void free_s390_insn_page(void *page) { - __set_memory((unsigned long) page, 1, SET_MEMORY_RW | SET_MEMORY_NX); xchg(&insn_page_in_use, 0); } diff --git a/arch/s390/kernel/kprobes_insn_page.S b/arch/s390/kernel/kprobes_insn_page.S new file mode 100644 index 000000000000..f6cb022ef8c8 --- /dev/null +++ b/arch/s390/kernel/kprobes_insn_page.S @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include + +/* + * insn_page is a special 4k aligned dummy function for kprobes. + * It will contain all kprobed instructions that are out-of-line executed. + * The page must be within the kernel image to guarantee that the + * out-of-line instructions are within 2GB distance of their original + * location. Using a dummy function ensures that the insn_page is within + * the text section of the kernel and mapped read-only/executable from + * the beginning on, thus avoiding to split large mappings if the page + * would be in the data section instead. + */ + .section .kprobes.text, "ax" + .align 4096 +ENTRY(kprobes_insn_page) + .rept 2048 + .word 0x07fe + .endr +ENDPROC(kprobes_insn_page) + .previous -- cgit