> On Nov 6, 2019, at 9:46 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> > --- > 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..8631d3bd637f 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[NOP_ATOMIC5] = {}; > + u8 new_insn[NOP_ATOMIC5] = {}; > + 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 (old_addr) { ^ should be new_addr? > + prog = new_insn; > + ret = emit_call(&prog, old_addr, (void *)ip); ^^^ and here? > + if (ret) > + return ret; > + } > + ret = -EBUSY; > + mutex_lock(&text_mutex); > + switch (t) { > + case BPF_MOD_NOP_TO_CALL: > + if (memcmp(ip, ideal_nops, 5)) Maybe use X86_CALL_SIZE instead of 5? And the five more "5" below? > + goto out; > + text_poke(ip, new_insn, 5); > + break; > + case BPF_MOD_CALL_TO_CALL: > + if (memcmp(ip, old_insn, 5)) > + goto out; > + text_poke(ip, new_insn, 5); > + break; > + case BPF_MOD_CALL_TO_NOP: > + if (memcmp(ip, old_insn, 5)) > + goto out; > + text_poke(ip, ideal_nops, 5); > + 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 97e37d82a1cc..856564e97943 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 >