diff options
author | Heiko Carstens <hca@linux.ibm.com> | 2020-09-10 16:48:35 +0200 |
---|---|---|
committer | Vasily Gorbik <gor@linux.ibm.com> | 2020-09-14 11:38:35 +0200 |
commit | 6c6687a444cfa62548e080a52e6c2d5d41577a73 (patch) | |
tree | a2f17580be3e644a0f85e2065d1bbaba18ae31d2 /arch/s390/kernel | |
parent | s390/pci: remove clp_rescan_pci_devices_simple() (diff) | |
download | linux-6c6687a444cfa62548e080a52e6c2d5d41577a73.tar.xz linux-6c6687a444cfa62548e080a52e6c2d5d41577a73.zip |
s390/kprobes: make insn pages read-only
Make sure that kprobe insn pages are not writable anymore.
Tested-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/kprobes.c | 57 |
1 files changed, 39 insertions, 18 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index d2a71d872638..b34fa4eef742 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -7,6 +7,7 @@ * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com> */ +#include <linux/moduleloader.h> #include <linux/kprobes.h> #include <linux/ptrace.h> #include <linux/preempt.h> @@ -32,17 +33,33 @@ 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) +{ + void *page; + + page = module_alloc(PAGE_SIZE); + if (!page) + return NULL; + __set_memory((unsigned long) page, 1, SET_MEMORY_RO | SET_MEMORY_X); + return page; +} + +void free_insn_page(void *page) +{ + module_memfree(page); +} + static void *alloc_s390_insn_page(void) { if (xchg(&insn_page_in_use, 1) == 1) return NULL; - set_memory_x((unsigned long) &insn_page, 1); + __set_memory((unsigned long) &insn_page, 1, SET_MEMORY_RO | SET_MEMORY_X); return &insn_page; } static void free_s390_insn_page(void *page) { - set_memory_nx((unsigned long) page, 1); + __set_memory((unsigned long) page, 1, SET_MEMORY_RW | SET_MEMORY_NX); xchg(&insn_page_in_use, 0); } @@ -56,25 +73,29 @@ struct kprobe_insn_cache kprobe_s390_insn_slots = { static void copy_instruction(struct kprobe *p) { + kprobe_opcode_t insn[MAX_INSN_SIZE]; s64 disp, new_disp; u64 addr, new_addr; + unsigned int len; - memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8)); - p->opcode = p->ainsn.insn[0]; - if (!probe_is_insn_relative_long(p->ainsn.insn)) - return; - /* - * For pc-relative instructions in RIL-b or RIL-c format patch the - * RI2 displacement field. We have already made sure that the insn - * slot for the patched instruction is within the same 2GB area - * as the original instruction (either kernel image or module area). - * Therefore the new displacement will always fit. - */ - disp = *(s32 *)&p->ainsn.insn[1]; - addr = (u64)(unsigned long)p->addr; - new_addr = (u64)(unsigned long)p->ainsn.insn; - new_disp = ((addr + (disp * 2)) - new_addr) / 2; - *(s32 *)&p->ainsn.insn[1] = new_disp; + len = insn_length(*p->addr >> 8); + memcpy(&insn, p->addr, len); + p->opcode = insn[0]; + if (probe_is_insn_relative_long(&insn[0])) { + /* + * For pc-relative instructions in RIL-b or RIL-c format patch + * the RI2 displacement field. We have already made sure that + * the insn slot for the patched instruction is within the same + * 2GB area as the original instruction (either kernel image or + * module area). Therefore the new displacement will always fit. + */ + disp = *(s32 *)&insn[1]; + addr = (u64)(unsigned long)p->addr; + new_addr = (u64)(unsigned long)p->ainsn.insn; + new_disp = ((addr + (disp * 2)) - new_addr) / 2; + *(s32 *)&insn[1] = new_disp; + } + s390_kernel_write(p->ainsn.insn, &insn, len); } NOKPROBE_SYMBOL(copy_instruction); |