Commit b61e1f32 authored by Heiko Carstens's avatar Heiko Carstens Committed by Vasily Gorbik
Browse files

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: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent eefc69a0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <asm/set_memory.h>
#include <asm/sections.h>
#include <asm/dis.h>
#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);
}

+22 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */

#include <linux/linkage.h>

/*
 * 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