Commit d890e6af authored by Heiko Carstens's avatar Heiko Carstens
Browse files

s390/kprobes: Remove custom insn slot allocator



Since commit c98d2eca ("s390/mm: Uncouple physical vs virtual address
spaces") the kernel image and module area are within the same 4GB area.

This eliminates the need of a custom insn slot allocator for kprobes within
the kernel image, since standard module_alloc() allocated pages are
sufficient for PC relative instructions with a signed 32 bit offset.

Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent e7dec0b7
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
obj-$(CONFIG_COMPAT)		+= $(compat-obj-y)
obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
obj-$(CONFIG_KPROBES)		+= kprobes.o
obj-$(CONFIG_KPROBES)		+= kprobes_insn_page.o
obj-$(CONFIG_KPROBES)		+= mcount.o
obj-$(CONFIG_RETHOOK)		+= rethook.o
obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o
+10 −57
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@
#include <asm/set_memory.h>
#include <asm/sections.h>
#include <asm/dis.h>
#include "kprobes.h"
#include "entry.h"

DEFINE_PER_CPU(struct kprobe *, current_kprobe);
@@ -32,8 +31,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);

struct kretprobe_blackpoint kretprobe_blacklist[] = { };

static int insn_page_in_use;

void *alloc_insn_page(void)
{
	void *page;
@@ -45,26 +42,6 @@ void *alloc_insn_page(void)
	return page;
}

static void *alloc_s390_insn_page(void)
{
	if (xchg(&insn_page_in_use, 1) == 1)
		return NULL;
	return &kprobes_insn_page;
}

static void free_s390_insn_page(void *page)
{
	xchg(&insn_page_in_use, 0);
}

struct kprobe_insn_cache kprobe_s390_insn_slots = {
	.mutex = __MUTEX_INITIALIZER(kprobe_s390_insn_slots.mutex),
	.alloc = alloc_s390_insn_page,
	.free = free_s390_insn_page,
	.pages = LIST_HEAD_INIT(kprobe_s390_insn_slots.pages),
	.insn_size = MAX_INSN_SIZE,
};

static void copy_instruction(struct kprobe *p)
{
	kprobe_opcode_t insn[MAX_INSN_SIZE];
@@ -78,10 +55,10 @@ static void copy_instruction(struct kprobe *p)
	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.
		 * the RI2 displacement field. The insn slot for the to be
		 * patched instruction is within the same 4GB area like the
		 * original instruction. Therefore the new displacement will
		 * always fit.
		 */
		disp = *(s32 *)&insn[1];
		addr = (u64)(unsigned long)p->addr;
@@ -93,34 +70,6 @@ static void copy_instruction(struct kprobe *p)
}
NOKPROBE_SYMBOL(copy_instruction);

static int s390_get_insn_slot(struct kprobe *p)
{
	/*
	 * Get an insn slot that is within the same 2GB area like the original
	 * instruction. That way instructions with a 32bit signed displacement
	 * field can be patched and executed within the insn slot.
	 */
	p->ainsn.insn = NULL;
	if (is_kernel((unsigned long)p->addr))
		p->ainsn.insn = get_s390_insn_slot();
	else if (is_module_addr(p->addr))
		p->ainsn.insn = get_insn_slot();
	return p->ainsn.insn ? 0 : -ENOMEM;
}
NOKPROBE_SYMBOL(s390_get_insn_slot);

static void s390_free_insn_slot(struct kprobe *p)
{
	if (!p->ainsn.insn)
		return;
	if (is_kernel((unsigned long)p->addr))
		free_s390_insn_slot(p->ainsn.insn, 0);
	else
		free_insn_slot(p->ainsn.insn, 0);
	p->ainsn.insn = NULL;
}
NOKPROBE_SYMBOL(s390_free_insn_slot);

/* Check if paddr is at an instruction boundary */
static bool can_probe(unsigned long paddr)
{
@@ -174,7 +123,8 @@ int arch_prepare_kprobe(struct kprobe *p)
	/* Make sure the probe isn't going on a difficult instruction */
	if (probe_is_prohibited_opcode(p->addr))
		return -EINVAL;
	if (s390_get_insn_slot(p))
	p->ainsn.insn = get_insn_slot();
	if (!p->ainsn.insn)
		return -ENOMEM;
	copy_instruction(p);
	return 0;
@@ -216,7 +166,10 @@ NOKPROBE_SYMBOL(arch_disarm_kprobe);

void arch_remove_kprobe(struct kprobe *p)
{
	s390_free_insn_slot(p);
	if (!p->ainsn.insn)
		return;
	free_insn_slot(p->ainsn.insn, 0);
	p->ainsn.insn = NULL;
}
NOKPROBE_SYMBOL(arch_remove_kprobe);

arch/s390/kernel/kprobes.h

deleted100644 → 0
+0 −9
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef _ARCH_S390_KPROBES_H
#define _ARCH_S390_KPROBES_H

#include <linux/kprobes.h>

DEFINE_INSN_CACHE_OPS(s390_insn);

#endif
+0 −22
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"
	.balign 4096
SYM_CODE_START(kprobes_insn_page)
	.rept 2048
	.word 0x07fe
	.endr
SYM_CODE_END(kprobes_insn_page)
	.previous