| @@ -9,9 +9,11 @@ · 8 unmodified lines |
| 9 | 9 | #include <linux/filter.h> |
| 10 | 10 | #include <linux/if_vlan.h> |
| 11 | 11 | #include <linux/bpf.h> |
| 12 | +#include <linux/memory.h> |
| 12 | 13 | #include <asm/extable.h> |
| 13 | 14 | #include <asm/set_memory.h> |
| 14 | 15 | #include <asm/nospec-branch.h> |
| 16 | +#include <asm/text-patching.h> |
| 15 | 17 | |
| 16 | 18 | static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) |
| 17 | 19 | { |
| @@ -486,6 +488,55 @@ static int emit_call(u8 **pprog, void *func, void *ip) · 468 unmodified lines |
| 486 | 488 | return 0; |
| 487 | 489 | } |
| 488 | 490 | |
| 491 | +int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t, |
| 492 | + void *old_addr, void *new_addr) |
| 493 | +{ |
| 494 | + u8 old_insn[X86_CALL_SIZE] = {}; |
| 495 | + u8 new_insn[X86_CALL_SIZE] = {}; |
| 496 | + u8 *prog; |
| 497 | + int ret; |
| 498 | + |
| 499 | + if (!is_kernel_text((long)ip)) |
| 500 | + /* BPF trampoline in modules is not supported */ |
| 501 | + return -EINVAL; |
| 502 | + |
| 503 | + if (old_addr) { |
| 504 | + prog = old_insn; |
| 505 | + ret = emit_call(&prog, old_addr, (void *)ip); |
| 506 | + if (ret) |
| 507 | + return ret; |
| 508 | + } |
| 509 | + if (new_addr) { |
| 510 | + prog = new_insn; |
| 511 | + ret = emit_call(&prog, new_addr, (void *)ip); |
| 512 | + if (ret) |
| 513 | + return ret; |
| 514 | + } |
| 515 | + ret = -EBUSY; |
| 516 | + mutex_lock(&text_mutex); |
| 517 | + switch (t) { |
| 518 | + case BPF_MOD_NOP_TO_CALL: |
| 519 | + if (memcmp(ip, ideal_nops[NOP_ATOMIC5], X86_CALL_SIZE)) |
| 520 | + goto out; |
| 521 | + text_poke_bp(ip, new_insn, X86_CALL_SIZE, NULL); |
| 522 | + break; |
| 523 | + case BPF_MOD_CALL_TO_CALL: |
| 524 | + if (memcmp(ip, old_insn, X86_CALL_SIZE)) |
| 525 | + goto out; |
| 526 | + text_poke_bp(ip, new_insn, X86_CALL_SIZE, NULL); |
| 527 | + break; |
| 528 | + case BPF_MOD_CALL_TO_NOP: |
| 529 | + if (memcmp(ip, old_insn, X86_CALL_SIZE)) |
| 530 | + goto out; |
| 531 | + text_poke_bp(ip, ideal_nops[NOP_ATOMIC5], X86_CALL_SIZE, NULL); |
| 532 | + break; |
| 533 | + } |
| 534 | + ret = 0; |
| 535 | +out: |
| 536 | + mutex_unlock(&text_mutex); |
| 537 | + return ret; |
| 538 | +} |
| 539 | + |
| 489 | 540 | static bool ex_handler_bpf(const struct exception_table_entry *x, |
| 490 | 541 | struct pt_regs *regs, int trapnr, |
| 491 | 542 | unsigned long error_code, unsigned long fault_addr) |