Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9802d865 authored by Josef Bacik's avatar Josef Bacik Committed by Alexei Starovoitov
Browse files

bpf: add a bpf_override_function helper



Error injection is sloppy and very ad-hoc.  BPF could fill this niche
perfectly with it's kprobe functionality.  We could make sure errors are
only triggered in specific call chains that we care about with very
specific situations.  Accomplish this with the bpf_override_funciton
helper.  This will modify the probe'd callers return value to the
specified value and set the PC to an override function that simply
returns, bypassing the originally probed function.  This gives us a nice
clean way to implement systematic error injection for all of our code
paths.

Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarJosef Bacik <jbacik@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 8556e509
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -196,6 +196,9 @@ config HAVE_OPTPROBES
config HAVE_KPROBES_ON_FTRACE
	bool

config HAVE_KPROBE_OVERRIDE
	bool

config HAVE_NMI
	bool

+1 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ config X86
	select HAVE_KERNEL_XZ
	select HAVE_KPROBES
	select HAVE_KPROBES_ON_FTRACE
	select HAVE_KPROBE_OVERRIDE
	select HAVE_KRETPROBES
	select HAVE_KVM
	select HAVE_LIVEPATCH			if X86_64
+4 −0
Original line number Diff line number Diff line
@@ -67,6 +67,10 @@ extern const int kretprobe_blacklist_size;
void arch_remove_kprobe(struct kprobe *p);
asmlinkage void kretprobe_trampoline(void);

#ifdef CONFIG_KPROBES_ON_FTRACE
extern void arch_ftrace_kprobe_override_function(struct pt_regs *regs);
#endif

/* Architecture specific copy of original instruction*/
struct arch_specific_insn {
	/* copy of the original instruction */
+5 −0
Original line number Diff line number Diff line
@@ -109,6 +109,11 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
	return regs->ax;
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->ax = rc;
}

/*
 * user_mode(regs) determines whether a register set came from user
 * mode.  On x86_32, this is true if V8086 mode was enabled OR if the
+14 −0
Original line number Diff line number Diff line
@@ -97,3 +97,17 @@ int arch_prepare_kprobe_ftrace(struct kprobe *p)
	p->ainsn.boostable = false;
	return 0;
}

asmlinkage void override_func(void);
asm(
	".type override_func, @function\n"
	"override_func:\n"
	"	ret\n"
	".size override_func, .-override_func\n"
);

void arch_ftrace_kprobe_override_function(struct pt_regs *regs)
{
	regs->ip = (unsigned long)&override_func;
}
NOKPROBE_SYMBOL(arch_ftrace_kprobe_override_function);
Loading