diff options
Diffstat (limited to 'arch/arm64/net/bpf_jit_comp.c')
-rw-r--r-- | arch/arm64/net/bpf_jit_comp.c | 84 |
1 files changed, 74 insertions, 10 deletions
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7ae33545535b..41f1e3e2ea24 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c | |||
@@ -19,12 +19,13 @@ | |||
19 | #define pr_fmt(fmt) "bpf_jit: " fmt | 19 | #define pr_fmt(fmt) "bpf_jit: " fmt |
20 | 20 | ||
21 | #include <linux/filter.h> | 21 | #include <linux/filter.h> |
22 | #include <linux/moduleloader.h> | ||
23 | #include <linux/printk.h> | 22 | #include <linux/printk.h> |
24 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | |||
26 | #include <asm/byteorder.h> | 26 | #include <asm/byteorder.h> |
27 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
28 | #include <asm/debug-monitors.h> | ||
28 | 29 | ||
29 | #include "bpf_jit.h" | 30 | #include "bpf_jit.h" |
30 | 31 | ||
@@ -119,6 +120,14 @@ static inline int bpf2a64_offset(int bpf_to, int bpf_from, | |||
119 | return to - from; | 120 | return to - from; |
120 | } | 121 | } |
121 | 122 | ||
123 | static void jit_fill_hole(void *area, unsigned int size) | ||
124 | { | ||
125 | u32 *ptr; | ||
126 | /* We are guaranteed to have aligned memory. */ | ||
127 | for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) | ||
128 | *ptr++ = cpu_to_le32(AARCH64_BREAK_FAULT); | ||
129 | } | ||
130 | |||
122 | static inline int epilogue_offset(const struct jit_ctx *ctx) | 131 | static inline int epilogue_offset(const struct jit_ctx *ctx) |
123 | { | 132 | { |
124 | int to = ctx->offset[ctx->prog->len - 1]; | 133 | int to = ctx->offset[ctx->prog->len - 1]; |
@@ -196,6 +205,12 @@ static void build_epilogue(struct jit_ctx *ctx) | |||
196 | emit(A64_RET(A64_LR), ctx); | 205 | emit(A64_RET(A64_LR), ctx); |
197 | } | 206 | } |
198 | 207 | ||
208 | /* JITs an eBPF instruction. | ||
209 | * Returns: | ||
210 | * 0 - successfully JITed an 8-byte eBPF instruction. | ||
211 | * >0 - successfully JITed a 16-byte eBPF instruction. | ||
212 | * <0 - failed to JIT. | ||
213 | */ | ||
199 | static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | 214 | static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) |
200 | { | 215 | { |
201 | const u8 code = insn->code; | 216 | const u8 code = insn->code; |
@@ -252,6 +267,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) | |||
252 | emit(A64_MUL(is64, tmp, tmp, src), ctx); | 267 | emit(A64_MUL(is64, tmp, tmp, src), ctx); |
253 | emit(A64_SUB(is64, dst, dst, tmp), ctx); | 268 | emit(A64_SUB(is64, dst, dst, tmp), ctx); |
254 | break; | 269 | break; |
270 | case BPF_ALU | BPF_LSH | BPF_X: | ||
271 | case BPF_ALU64 | BPF_LSH | BPF_X: | ||
272 | emit(A64_LSLV(is64, dst, dst, src), ctx); | ||
273 | break; | ||
274 | case BPF_ALU | BPF_RSH | BPF_X: | ||
275 | case BPF_ALU64 | BPF_RSH | BPF_X: | ||
276 | emit(A64_LSRV(is64, dst, dst, src), ctx); | ||
277 | break; | ||
278 | case BPF_ALU | BPF_ARSH | BPF_X: | ||
279 | case BPF_ALU64 | BPF_ARSH | BPF_X: | ||
280 | emit(A64_ASRV(is64, dst, dst, src), ctx); | ||
281 | break; | ||
255 | /* dst = -dst */ | 282 | /* dst = -dst */ |
256 | case BPF_ALU | BPF_NEG: | 283 | case BPF_ALU | BPF_NEG: |
257 | case BPF_ALU64 | BPF_NEG: | 284 | case BPF_ALU64 | BPF_NEG: |
@@ -443,6 +470,27 @@ emit_cond_jmp: | |||
443 | emit(A64_B(jmp_offset), ctx); | 470 | emit(A64_B(jmp_offset), ctx); |
444 | break; | 471 | break; |
445 | 472 | ||
473 | /* dst = imm64 */ | ||
474 | case BPF_LD | BPF_IMM | BPF_DW: | ||
475 | { | ||
476 | const struct bpf_insn insn1 = insn[1]; | ||
477 | u64 imm64; | ||
478 | |||
479 | if (insn1.code != 0 || insn1.src_reg != 0 || | ||
480 | insn1.dst_reg != 0 || insn1.off != 0) { | ||
481 | /* Note: verifier in BPF core must catch invalid | ||
482 | * instructions. | ||
483 | */ | ||
484 | pr_err_once("Invalid BPF_LD_IMM64 instruction\n"); | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | |||
488 | imm64 = (u64)insn1.imm << 32 | imm; | ||
489 | emit_a64_mov_i64(dst, imm64, ctx); | ||
490 | |||
491 | return 1; | ||
492 | } | ||
493 | |||
446 | /* LDX: dst = *(size *)(src + off) */ | 494 | /* LDX: dst = *(size *)(src + off) */ |
447 | case BPF_LDX | BPF_MEM | BPF_W: | 495 | case BPF_LDX | BPF_MEM | BPF_W: |
448 | case BPF_LDX | BPF_MEM | BPF_H: | 496 | case BPF_LDX | BPF_MEM | BPF_H: |
@@ -594,6 +642,10 @@ static int build_body(struct jit_ctx *ctx) | |||
594 | ctx->offset[i] = ctx->idx; | 642 | ctx->offset[i] = ctx->idx; |
595 | 643 | ||
596 | ret = build_insn(insn, ctx); | 644 | ret = build_insn(insn, ctx); |
645 | if (ret > 0) { | ||
646 | i++; | ||
647 | continue; | ||
648 | } | ||
597 | if (ret) | 649 | if (ret) |
598 | return ret; | 650 | return ret; |
599 | } | 651 | } |
@@ -613,8 +665,10 @@ void bpf_jit_compile(struct bpf_prog *prog) | |||
613 | 665 | ||
614 | void bpf_int_jit_compile(struct bpf_prog *prog) | 666 | void bpf_int_jit_compile(struct bpf_prog *prog) |
615 | { | 667 | { |
668 | struct bpf_binary_header *header; | ||
616 | struct jit_ctx ctx; | 669 | struct jit_ctx ctx; |
617 | int image_size; | 670 | int image_size; |
671 | u8 *image_ptr; | ||
618 | 672 | ||
619 | if (!bpf_jit_enable) | 673 | if (!bpf_jit_enable) |
620 | return; | 674 | return; |
@@ -636,23 +690,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) | |||
636 | goto out; | 690 | goto out; |
637 | 691 | ||
638 | build_prologue(&ctx); | 692 | build_prologue(&ctx); |
639 | |||
640 | build_epilogue(&ctx); | 693 | build_epilogue(&ctx); |
641 | 694 | ||
642 | /* Now we know the actual image size. */ | 695 | /* Now we know the actual image size. */ |
643 | image_size = sizeof(u32) * ctx.idx; | 696 | image_size = sizeof(u32) * ctx.idx; |
644 | ctx.image = module_alloc(image_size); | 697 | header = bpf_jit_binary_alloc(image_size, &image_ptr, |
645 | if (unlikely(ctx.image == NULL)) | 698 | sizeof(u32), jit_fill_hole); |
699 | if (header == NULL) | ||
646 | goto out; | 700 | goto out; |
647 | 701 | ||
648 | /* 2. Now, the actual pass. */ | 702 | /* 2. Now, the actual pass. */ |
649 | 703 | ||
704 | ctx.image = (u32 *)image_ptr; | ||
650 | ctx.idx = 0; | 705 | ctx.idx = 0; |
706 | |||
651 | build_prologue(&ctx); | 707 | build_prologue(&ctx); |
652 | 708 | ||
653 | ctx.body_offset = ctx.idx; | 709 | ctx.body_offset = ctx.idx; |
654 | if (build_body(&ctx)) { | 710 | if (build_body(&ctx)) { |
655 | module_free(NULL, ctx.image); | 711 | bpf_jit_binary_free(header); |
656 | goto out; | 712 | goto out; |
657 | } | 713 | } |
658 | 714 | ||
@@ -663,17 +719,25 @@ void bpf_int_jit_compile(struct bpf_prog *prog) | |||
663 | bpf_jit_dump(prog->len, image_size, 2, ctx.image); | 719 | bpf_jit_dump(prog->len, image_size, 2, ctx.image); |
664 | 720 | ||
665 | bpf_flush_icache(ctx.image, ctx.image + ctx.idx); | 721 | bpf_flush_icache(ctx.image, ctx.image + ctx.idx); |
666 | prog->bpf_func = (void *)ctx.image; | ||
667 | prog->jited = 1; | ||
668 | 722 | ||
723 | set_memory_ro((unsigned long)header, header->pages); | ||
724 | prog->bpf_func = (void *)ctx.image; | ||
725 | prog->jited = true; | ||
669 | out: | 726 | out: |
670 | kfree(ctx.offset); | 727 | kfree(ctx.offset); |
671 | } | 728 | } |
672 | 729 | ||
673 | void bpf_jit_free(struct bpf_prog *prog) | 730 | void bpf_jit_free(struct bpf_prog *prog) |
674 | { | 731 | { |
675 | if (prog->jited) | 732 | unsigned long addr = (unsigned long)prog->bpf_func & PAGE_MASK; |
676 | module_free(NULL, prog->bpf_func); | 733 | struct bpf_binary_header *header = (void *)addr; |
734 | |||
735 | if (!prog->jited) | ||
736 | goto free_filter; | ||
737 | |||
738 | set_memory_rw(addr, header->pages); | ||
739 | bpf_jit_binary_free(header); | ||
677 | 740 | ||
678 | kfree(prog); | 741 | free_filter: |
742 | bpf_prog_unlock_free(prog); | ||
679 | } | 743 | } |