> On Nov 7, 2019, at 10:40 PM, Alexei Starovoitov <ast@xxxxxxxxxx> wrote: > > Add bpf_arch_text_poke() helper that is used by BPF trampoline logic to patch > nops/calls in kernel text into calls into BPF trampoline and to patch > calls/nops inside BPF programs too. > > Signed-off-by: Alexei Starovoitov <ast@xxxxxxxxxx> Acked-by: Song Liu <songliubraving@xxxxxx> > --- > arch/x86/net/bpf_jit_comp.c | 51 +++++++++++++++++++++++++++++++++++++ > include/linux/bpf.h | 8 ++++++ > kernel/bpf/core.c | 6 +++++ > 3 files changed, 65 insertions(+) > > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c > index 0399b1f83c23..bb8467fd6715 100644 > --- a/arch/x86/net/bpf_jit_comp.c > +++ b/arch/x86/net/bpf_jit_comp.c > @@ -9,9 +9,11 @@ > #include <linux/filter.h> > #include <linux/if_vlan.h> > #include <linux/bpf.h> > +#include <linux/memory.h> > #include <asm/extable.h> > #include <asm/set_memory.h> > #include <asm/nospec-branch.h> > +#include <asm/text-patching.h> > > static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) > { > @@ -487,6 +489,55 @@ static int emit_call(u8 **pprog, void *func, void *ip) > return 0; > } > > +int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, > + void *old_addr, void *new_addr) > +{ > + u8 old_insn[X86_CALL_SIZE] = {}; > + u8 new_insn[X86_CALL_SIZE] = {}; > + u8 *prog; > + int ret; > + > + if (!is_kernel_text((long)ip)) > + /* BPF trampoline in modules is not supported */ > + return -EINVAL; > + > + if (old_addr) { > + prog = old_insn; > + ret = emit_call(&prog, old_addr, (void *)ip); > + if (ret) > + return ret; > + } > + if (new_addr) { > + prog = new_insn; > + ret = emit_call(&prog, new_addr, (void *)ip); > + if (ret) > + return ret; > + } > + ret = -EBUSY; > + mutex_lock(&text_mutex); > + switch (t) { > + case BPF_MOD_NOP_TO_CALL: > + if (memcmp(ip, ideal_nops[NOP_ATOMIC5], X86_CALL_SIZE)) > + goto out; > + text_poke(ip, new_insn, X86_CALL_SIZE); > + break; > + case BPF_MOD_CALL_TO_CALL: > + if (memcmp(ip, old_insn, X86_CALL_SIZE)) > + goto out; > + text_poke(ip, new_insn, X86_CALL_SIZE); > + break; > + case BPF_MOD_CALL_TO_NOP: > + if (memcmp(ip, old_insn, X86_CALL_SIZE)) > + goto out; > + text_poke(ip, ideal_nops[NOP_ATOMIC5], X86_CALL_SIZE); > + break; > + } > + ret = 0; > +out: > + mutex_unlock(&text_mutex); > + return ret; > +} > + > static bool ex_handler_bpf(const struct exception_table_entry *x, > struct pt_regs *regs, int trapnr, > unsigned long error_code, unsigned long fault_addr) > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 7c7f518811a6..8b90db25348a 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1157,4 +1157,12 @@ static inline u32 bpf_xdp_sock_convert_ctx_access(enum bpf_access_type type, > } > #endif /* CONFIG_INET */ > > +enum bpf_text_poke_type { > + BPF_MOD_NOP_TO_CALL, > + BPF_MOD_CALL_TO_CALL, > + BPF_MOD_CALL_TO_NOP, > +}; > +int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, > + void *addr1, void *addr2); > + > #endif /* _LINUX_BPF_H */ > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index c1fde0303280..c4bcec1014a9 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -2140,6 +2140,12 @@ int __weak skb_copy_bits(const struct sk_buff *skb, int offset, void *to, > return -EFAULT; > } > > +int __weak bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, > + void *addr1, void *addr2) > +{ > + return -ENOTSUPP; > +} > + > DEFINE_STATIC_KEY_FALSE(bpf_stats_enabled_key); > EXPORT_SYMBOL(bpf_stats_enabled_key); > > -- > 2.23.0 >