| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * BPF JIT compiler for ARM64 |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@gmail.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | 6 | */ |
|---|
| 18 | 7 | |
|---|
| 19 | 8 | #define pr_fmt(fmt) "bpf_jit: " fmt |
|---|
| 20 | 9 | |
|---|
| 10 | +#include <linux/bitfield.h> |
|---|
| 21 | 11 | #include <linux/bpf.h> |
|---|
| 22 | 12 | #include <linux/filter.h> |
|---|
| 23 | 13 | #include <linux/printk.h> |
|---|
| .. | .. |
|---|
| 27 | 17 | #include <asm/cacheflush.h> |
|---|
| 28 | 18 | #include <asm/debug-monitors.h> |
|---|
| 29 | 19 | #include <asm/set_memory.h> |
|---|
| 20 | +#include <trace/hooks/memory.h> |
|---|
| 30 | 21 | |
|---|
| 31 | 22 | #include "bpf_jit.h" |
|---|
| 32 | 23 | |
|---|
| .. | .. |
|---|
| 67 | 58 | int idx; |
|---|
| 68 | 59 | int epilogue_offset; |
|---|
| 69 | 60 | int *offset; |
|---|
| 61 | + int exentry_idx; |
|---|
| 70 | 62 | __le32 *image; |
|---|
| 71 | 63 | u32 stack_size; |
|---|
| 72 | 64 | }; |
|---|
| .. | .. |
|---|
| 134 | 126 | } |
|---|
| 135 | 127 | |
|---|
| 136 | 128 | /* |
|---|
| 137 | | - * This is an unoptimized 64 immediate emission used for BPF to BPF call |
|---|
| 138 | | - * addresses. It will always do a full 64 bit decomposition as otherwise |
|---|
| 139 | | - * more complexity in the last extra pass is required since we previously |
|---|
| 140 | | - * reserved 4 instructions for the address. |
|---|
| 129 | + * Kernel addresses in the vmalloc space use at most 48 bits, and the |
|---|
| 130 | + * remaining bits are guaranteed to be 0x1. So we can compose the address |
|---|
| 131 | + * with a fixed length movn/movk/movk sequence. |
|---|
| 141 | 132 | */ |
|---|
| 142 | 133 | static inline void emit_addr_mov_i64(const int reg, const u64 val, |
|---|
| 143 | 134 | struct jit_ctx *ctx) |
|---|
| .. | .. |
|---|
| 145 | 136 | u64 tmp = val; |
|---|
| 146 | 137 | int shift = 0; |
|---|
| 147 | 138 | |
|---|
| 148 | | - emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx); |
|---|
| 149 | | - for (;shift < 48;) { |
|---|
| 139 | + emit(A64_MOVN(1, reg, ~tmp & 0xffff, shift), ctx); |
|---|
| 140 | + while (shift < 32) { |
|---|
| 150 | 141 | tmp >>= 16; |
|---|
| 151 | 142 | shift += 16; |
|---|
| 152 | 143 | emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx); |
|---|
| 153 | 144 | } |
|---|
| 154 | 145 | } |
|---|
| 155 | 146 | |
|---|
| 156 | | -static inline int bpf2a64_offset(int bpf_to, int bpf_from, |
|---|
| 147 | +static inline int bpf2a64_offset(int bpf_insn, int off, |
|---|
| 157 | 148 | const struct jit_ctx *ctx) |
|---|
| 158 | 149 | { |
|---|
| 159 | | - int to = ctx->offset[bpf_to]; |
|---|
| 160 | | - /* -1 to account for the Branch instruction */ |
|---|
| 161 | | - int from = ctx->offset[bpf_from] - 1; |
|---|
| 162 | | - |
|---|
| 163 | | - return to - from; |
|---|
| 150 | + /* BPF JMP offset is relative to the next instruction */ |
|---|
| 151 | + bpf_insn++; |
|---|
| 152 | + /* |
|---|
| 153 | + * Whereas arm64 branch instructions encode the offset |
|---|
| 154 | + * from the branch itself, so we must subtract 1 from the |
|---|
| 155 | + * instruction offset. |
|---|
| 156 | + */ |
|---|
| 157 | + return ctx->offset[bpf_insn + off] - (ctx->offset[bpf_insn] - 1); |
|---|
| 164 | 158 | } |
|---|
| 165 | 159 | |
|---|
| 166 | 160 | static void jit_fill_hole(void *area, unsigned int size) |
|---|
| .. | .. |
|---|
| 179 | 173 | return to - from; |
|---|
| 180 | 174 | } |
|---|
| 181 | 175 | |
|---|
| 176 | +static bool is_addsub_imm(u32 imm) |
|---|
| 177 | +{ |
|---|
| 178 | + /* Either imm12 or shifted imm12. */ |
|---|
| 179 | + return !(imm & ~0xfff) || !(imm & ~0xfff000); |
|---|
| 180 | +} |
|---|
| 181 | + |
|---|
| 182 | 182 | /* Stack must be multiples of 16B */ |
|---|
| 183 | 183 | #define STACK_ALIGN(sz) (((sz) + 15) & ~15) |
|---|
| 184 | 184 | |
|---|
| 185 | 185 | /* Tail call offset to jump into */ |
|---|
| 186 | +#if IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) |
|---|
| 187 | +#define PROLOGUE_OFFSET 8 |
|---|
| 188 | +#else |
|---|
| 186 | 189 | #define PROLOGUE_OFFSET 7 |
|---|
| 190 | +#endif |
|---|
| 187 | 191 | |
|---|
| 188 | 192 | static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) |
|---|
| 189 | 193 | { |
|---|
| .. | .. |
|---|
| 220 | 224 | * |
|---|
| 221 | 225 | */ |
|---|
| 222 | 226 | |
|---|
| 227 | + /* BTI landing pad */ |
|---|
| 228 | + if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) |
|---|
| 229 | + emit(A64_BTI_C, ctx); |
|---|
| 230 | + |
|---|
| 223 | 231 | /* Save FP and LR registers to stay align with ARM64 AAPCS */ |
|---|
| 224 | 232 | emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); |
|---|
| 225 | 233 | emit(A64_MOV(1, A64_FP, A64_SP), ctx); |
|---|
| .. | .. |
|---|
| 242 | 250 | cur_offset, PROLOGUE_OFFSET); |
|---|
| 243 | 251 | return -1; |
|---|
| 244 | 252 | } |
|---|
| 253 | + |
|---|
| 254 | + /* BTI landing pad for the tail call, done with a BR */ |
|---|
| 255 | + if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) |
|---|
| 256 | + emit(A64_BTI_J, ctx); |
|---|
| 245 | 257 | } |
|---|
| 246 | 258 | |
|---|
| 247 | 259 | ctx->stack_size = STACK_ALIGN(prog->aux->stack_depth); |
|---|
| .. | .. |
|---|
| 345 | 357 | emit(A64_RET(A64_LR), ctx); |
|---|
| 346 | 358 | } |
|---|
| 347 | 359 | |
|---|
| 360 | +#define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0) |
|---|
| 361 | +#define BPF_FIXUP_REG_MASK GENMASK(31, 27) |
|---|
| 362 | + |
|---|
| 363 | +int arm64_bpf_fixup_exception(const struct exception_table_entry *ex, |
|---|
| 364 | + struct pt_regs *regs) |
|---|
| 365 | +{ |
|---|
| 366 | + off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup); |
|---|
| 367 | + int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup); |
|---|
| 368 | + |
|---|
| 369 | + regs->regs[dst_reg] = 0; |
|---|
| 370 | + regs->pc = (unsigned long)&ex->fixup - offset; |
|---|
| 371 | + return 1; |
|---|
| 372 | +} |
|---|
| 373 | + |
|---|
| 374 | +/* For accesses to BTF pointers, add an entry to the exception table */ |
|---|
| 375 | +static int add_exception_handler(const struct bpf_insn *insn, |
|---|
| 376 | + struct jit_ctx *ctx, |
|---|
| 377 | + int dst_reg) |
|---|
| 378 | +{ |
|---|
| 379 | + off_t offset; |
|---|
| 380 | + unsigned long pc; |
|---|
| 381 | + struct exception_table_entry *ex; |
|---|
| 382 | + |
|---|
| 383 | + if (!ctx->image) |
|---|
| 384 | + /* First pass */ |
|---|
| 385 | + return 0; |
|---|
| 386 | + |
|---|
| 387 | + if (BPF_MODE(insn->code) != BPF_PROBE_MEM) |
|---|
| 388 | + return 0; |
|---|
| 389 | + |
|---|
| 390 | + if (!ctx->prog->aux->extable || |
|---|
| 391 | + WARN_ON_ONCE(ctx->exentry_idx >= ctx->prog->aux->num_exentries)) |
|---|
| 392 | + return -EINVAL; |
|---|
| 393 | + |
|---|
| 394 | + ex = &ctx->prog->aux->extable[ctx->exentry_idx]; |
|---|
| 395 | + pc = (unsigned long)&ctx->image[ctx->idx - 1]; |
|---|
| 396 | + |
|---|
| 397 | + offset = pc - (long)&ex->insn; |
|---|
| 398 | + if (WARN_ON_ONCE(offset >= 0 || offset < INT_MIN)) |
|---|
| 399 | + return -ERANGE; |
|---|
| 400 | + ex->insn = offset; |
|---|
| 401 | + |
|---|
| 402 | + /* |
|---|
| 403 | + * Since the extable follows the program, the fixup offset is always |
|---|
| 404 | + * negative and limited to BPF_JIT_REGION_SIZE. Store a positive value |
|---|
| 405 | + * to keep things simple, and put the destination register in the upper |
|---|
| 406 | + * bits. We don't need to worry about buildtime or runtime sort |
|---|
| 407 | + * modifying the upper bits because the table is already sorted, and |
|---|
| 408 | + * isn't part of the main exception table. |
|---|
| 409 | + */ |
|---|
| 410 | + offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE); |
|---|
| 411 | + if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, offset)) |
|---|
| 412 | + return -ERANGE; |
|---|
| 413 | + |
|---|
| 414 | + ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, offset) | |
|---|
| 415 | + FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg); |
|---|
| 416 | + |
|---|
| 417 | + ctx->exentry_idx++; |
|---|
| 418 | + return 0; |
|---|
| 419 | +} |
|---|
| 420 | + |
|---|
| 348 | 421 | /* JITs an eBPF instruction. |
|---|
| 349 | 422 | * Returns: |
|---|
| 350 | 423 | * 0 - successfully JITed an 8-byte eBPF instruction. |
|---|
| 351 | 424 | * >0 - successfully JITed a 16-byte eBPF instruction. |
|---|
| 352 | 425 | * <0 - failed to JIT. |
|---|
| 353 | 426 | */ |
|---|
| 354 | | -static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) |
|---|
| 427 | +static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, |
|---|
| 428 | + bool extra_pass) |
|---|
| 355 | 429 | { |
|---|
| 356 | 430 | const u8 code = insn->code; |
|---|
| 357 | 431 | const u8 dst = bpf2a64[insn->dst_reg]; |
|---|
| .. | .. |
|---|
| 362 | 436 | const s16 off = insn->off; |
|---|
| 363 | 437 | const s32 imm = insn->imm; |
|---|
| 364 | 438 | const int i = insn - ctx->prog->insnsi; |
|---|
| 365 | | - const bool is64 = BPF_CLASS(code) == BPF_ALU64; |
|---|
| 439 | + const bool is64 = BPF_CLASS(code) == BPF_ALU64 || |
|---|
| 440 | + BPF_CLASS(code) == BPF_JMP; |
|---|
| 366 | 441 | const bool isdw = BPF_SIZE(code) == BPF_DW; |
|---|
| 367 | 442 | u8 jmp_cond, reg; |
|---|
| 368 | 443 | s32 jmp_offset; |
|---|
| 444 | + u32 a64_insn; |
|---|
| 445 | + int ret; |
|---|
| 369 | 446 | |
|---|
| 370 | 447 | #define check_imm(bits, imm) do { \ |
|---|
| 371 | 448 | if ((((imm) > 0) && ((imm) >> (bits))) || \ |
|---|
| .. | .. |
|---|
| 419 | 496 | break; |
|---|
| 420 | 497 | case BPF_MOD: |
|---|
| 421 | 498 | emit(A64_UDIV(is64, tmp, dst, src), ctx); |
|---|
| 422 | | - emit(A64_MUL(is64, tmp, tmp, src), ctx); |
|---|
| 423 | | - emit(A64_SUB(is64, dst, dst, tmp), ctx); |
|---|
| 499 | + emit(A64_MSUB(is64, dst, dst, tmp, src), ctx); |
|---|
| 424 | 500 | break; |
|---|
| 425 | 501 | } |
|---|
| 426 | 502 | break; |
|---|
| .. | .. |
|---|
| 489 | 565 | /* dst = dst OP imm */ |
|---|
| 490 | 566 | case BPF_ALU | BPF_ADD | BPF_K: |
|---|
| 491 | 567 | case BPF_ALU64 | BPF_ADD | BPF_K: |
|---|
| 492 | | - emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 493 | | - emit(A64_ADD(is64, dst, dst, tmp), ctx); |
|---|
| 568 | + if (is_addsub_imm(imm)) { |
|---|
| 569 | + emit(A64_ADD_I(is64, dst, dst, imm), ctx); |
|---|
| 570 | + } else if (is_addsub_imm(-imm)) { |
|---|
| 571 | + emit(A64_SUB_I(is64, dst, dst, -imm), ctx); |
|---|
| 572 | + } else { |
|---|
| 573 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 574 | + emit(A64_ADD(is64, dst, dst, tmp), ctx); |
|---|
| 575 | + } |
|---|
| 494 | 576 | break; |
|---|
| 495 | 577 | case BPF_ALU | BPF_SUB | BPF_K: |
|---|
| 496 | 578 | case BPF_ALU64 | BPF_SUB | BPF_K: |
|---|
| 497 | | - emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 498 | | - emit(A64_SUB(is64, dst, dst, tmp), ctx); |
|---|
| 579 | + if (is_addsub_imm(imm)) { |
|---|
| 580 | + emit(A64_SUB_I(is64, dst, dst, imm), ctx); |
|---|
| 581 | + } else if (is_addsub_imm(-imm)) { |
|---|
| 582 | + emit(A64_ADD_I(is64, dst, dst, -imm), ctx); |
|---|
| 583 | + } else { |
|---|
| 584 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 585 | + emit(A64_SUB(is64, dst, dst, tmp), ctx); |
|---|
| 586 | + } |
|---|
| 499 | 587 | break; |
|---|
| 500 | 588 | case BPF_ALU | BPF_AND | BPF_K: |
|---|
| 501 | 589 | case BPF_ALU64 | BPF_AND | BPF_K: |
|---|
| 502 | | - emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 503 | | - emit(A64_AND(is64, dst, dst, tmp), ctx); |
|---|
| 590 | + a64_insn = A64_AND_I(is64, dst, dst, imm); |
|---|
| 591 | + if (a64_insn != AARCH64_BREAK_FAULT) { |
|---|
| 592 | + emit(a64_insn, ctx); |
|---|
| 593 | + } else { |
|---|
| 594 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 595 | + emit(A64_AND(is64, dst, dst, tmp), ctx); |
|---|
| 596 | + } |
|---|
| 504 | 597 | break; |
|---|
| 505 | 598 | case BPF_ALU | BPF_OR | BPF_K: |
|---|
| 506 | 599 | case BPF_ALU64 | BPF_OR | BPF_K: |
|---|
| 507 | | - emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 508 | | - emit(A64_ORR(is64, dst, dst, tmp), ctx); |
|---|
| 600 | + a64_insn = A64_ORR_I(is64, dst, dst, imm); |
|---|
| 601 | + if (a64_insn != AARCH64_BREAK_FAULT) { |
|---|
| 602 | + emit(a64_insn, ctx); |
|---|
| 603 | + } else { |
|---|
| 604 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 605 | + emit(A64_ORR(is64, dst, dst, tmp), ctx); |
|---|
| 606 | + } |
|---|
| 509 | 607 | break; |
|---|
| 510 | 608 | case BPF_ALU | BPF_XOR | BPF_K: |
|---|
| 511 | 609 | case BPF_ALU64 | BPF_XOR | BPF_K: |
|---|
| 512 | | - emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 513 | | - emit(A64_EOR(is64, dst, dst, tmp), ctx); |
|---|
| 610 | + a64_insn = A64_EOR_I(is64, dst, dst, imm); |
|---|
| 611 | + if (a64_insn != AARCH64_BREAK_FAULT) { |
|---|
| 612 | + emit(a64_insn, ctx); |
|---|
| 613 | + } else { |
|---|
| 614 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 615 | + emit(A64_EOR(is64, dst, dst, tmp), ctx); |
|---|
| 616 | + } |
|---|
| 514 | 617 | break; |
|---|
| 515 | 618 | case BPF_ALU | BPF_MUL | BPF_K: |
|---|
| 516 | 619 | case BPF_ALU64 | BPF_MUL | BPF_K: |
|---|
| .. | .. |
|---|
| 526 | 629 | case BPF_ALU64 | BPF_MOD | BPF_K: |
|---|
| 527 | 630 | emit_a64_mov_i(is64, tmp2, imm, ctx); |
|---|
| 528 | 631 | emit(A64_UDIV(is64, tmp, dst, tmp2), ctx); |
|---|
| 529 | | - emit(A64_MUL(is64, tmp, tmp, tmp2), ctx); |
|---|
| 530 | | - emit(A64_SUB(is64, dst, dst, tmp), ctx); |
|---|
| 632 | + emit(A64_MSUB(is64, dst, dst, tmp, tmp2), ctx); |
|---|
| 531 | 633 | break; |
|---|
| 532 | 634 | case BPF_ALU | BPF_LSH | BPF_K: |
|---|
| 533 | 635 | case BPF_ALU64 | BPF_LSH | BPF_K: |
|---|
| .. | .. |
|---|
| 544 | 646 | |
|---|
| 545 | 647 | /* JUMP off */ |
|---|
| 546 | 648 | case BPF_JMP | BPF_JA: |
|---|
| 547 | | - jmp_offset = bpf2a64_offset(i + off, i, ctx); |
|---|
| 649 | + jmp_offset = bpf2a64_offset(i, off, ctx); |
|---|
| 548 | 650 | check_imm26(jmp_offset); |
|---|
| 549 | 651 | emit(A64_B(jmp_offset), ctx); |
|---|
| 550 | 652 | break; |
|---|
| .. | .. |
|---|
| 559 | 661 | case BPF_JMP | BPF_JSLT | BPF_X: |
|---|
| 560 | 662 | case BPF_JMP | BPF_JSGE | BPF_X: |
|---|
| 561 | 663 | case BPF_JMP | BPF_JSLE | BPF_X: |
|---|
| 562 | | - emit(A64_CMP(1, dst, src), ctx); |
|---|
| 664 | + case BPF_JMP32 | BPF_JEQ | BPF_X: |
|---|
| 665 | + case BPF_JMP32 | BPF_JGT | BPF_X: |
|---|
| 666 | + case BPF_JMP32 | BPF_JLT | BPF_X: |
|---|
| 667 | + case BPF_JMP32 | BPF_JGE | BPF_X: |
|---|
| 668 | + case BPF_JMP32 | BPF_JLE | BPF_X: |
|---|
| 669 | + case BPF_JMP32 | BPF_JNE | BPF_X: |
|---|
| 670 | + case BPF_JMP32 | BPF_JSGT | BPF_X: |
|---|
| 671 | + case BPF_JMP32 | BPF_JSLT | BPF_X: |
|---|
| 672 | + case BPF_JMP32 | BPF_JSGE | BPF_X: |
|---|
| 673 | + case BPF_JMP32 | BPF_JSLE | BPF_X: |
|---|
| 674 | + emit(A64_CMP(is64, dst, src), ctx); |
|---|
| 563 | 675 | emit_cond_jmp: |
|---|
| 564 | | - jmp_offset = bpf2a64_offset(i + off, i, ctx); |
|---|
| 676 | + jmp_offset = bpf2a64_offset(i, off, ctx); |
|---|
| 565 | 677 | check_imm19(jmp_offset); |
|---|
| 566 | 678 | switch (BPF_OP(code)) { |
|---|
| 567 | 679 | case BPF_JEQ: |
|---|
| .. | .. |
|---|
| 601 | 713 | emit(A64_B_(jmp_cond, jmp_offset), ctx); |
|---|
| 602 | 714 | break; |
|---|
| 603 | 715 | case BPF_JMP | BPF_JSET | BPF_X: |
|---|
| 604 | | - emit(A64_TST(1, dst, src), ctx); |
|---|
| 716 | + case BPF_JMP32 | BPF_JSET | BPF_X: |
|---|
| 717 | + emit(A64_TST(is64, dst, src), ctx); |
|---|
| 605 | 718 | goto emit_cond_jmp; |
|---|
| 606 | 719 | /* IF (dst COND imm) JUMP off */ |
|---|
| 607 | 720 | case BPF_JMP | BPF_JEQ | BPF_K: |
|---|
| .. | .. |
|---|
| 614 | 727 | case BPF_JMP | BPF_JSLT | BPF_K: |
|---|
| 615 | 728 | case BPF_JMP | BPF_JSGE | BPF_K: |
|---|
| 616 | 729 | case BPF_JMP | BPF_JSLE | BPF_K: |
|---|
| 617 | | - emit_a64_mov_i(1, tmp, imm, ctx); |
|---|
| 618 | | - emit(A64_CMP(1, dst, tmp), ctx); |
|---|
| 730 | + case BPF_JMP32 | BPF_JEQ | BPF_K: |
|---|
| 731 | + case BPF_JMP32 | BPF_JGT | BPF_K: |
|---|
| 732 | + case BPF_JMP32 | BPF_JLT | BPF_K: |
|---|
| 733 | + case BPF_JMP32 | BPF_JGE | BPF_K: |
|---|
| 734 | + case BPF_JMP32 | BPF_JLE | BPF_K: |
|---|
| 735 | + case BPF_JMP32 | BPF_JNE | BPF_K: |
|---|
| 736 | + case BPF_JMP32 | BPF_JSGT | BPF_K: |
|---|
| 737 | + case BPF_JMP32 | BPF_JSLT | BPF_K: |
|---|
| 738 | + case BPF_JMP32 | BPF_JSGE | BPF_K: |
|---|
| 739 | + case BPF_JMP32 | BPF_JSLE | BPF_K: |
|---|
| 740 | + if (is_addsub_imm(imm)) { |
|---|
| 741 | + emit(A64_CMP_I(is64, dst, imm), ctx); |
|---|
| 742 | + } else if (is_addsub_imm(-imm)) { |
|---|
| 743 | + emit(A64_CMN_I(is64, dst, -imm), ctx); |
|---|
| 744 | + } else { |
|---|
| 745 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 746 | + emit(A64_CMP(is64, dst, tmp), ctx); |
|---|
| 747 | + } |
|---|
| 619 | 748 | goto emit_cond_jmp; |
|---|
| 620 | 749 | case BPF_JMP | BPF_JSET | BPF_K: |
|---|
| 621 | | - emit_a64_mov_i(1, tmp, imm, ctx); |
|---|
| 622 | | - emit(A64_TST(1, dst, tmp), ctx); |
|---|
| 750 | + case BPF_JMP32 | BPF_JSET | BPF_K: |
|---|
| 751 | + a64_insn = A64_TST_I(is64, dst, imm); |
|---|
| 752 | + if (a64_insn != AARCH64_BREAK_FAULT) { |
|---|
| 753 | + emit(a64_insn, ctx); |
|---|
| 754 | + } else { |
|---|
| 755 | + emit_a64_mov_i(is64, tmp, imm, ctx); |
|---|
| 756 | + emit(A64_TST(is64, dst, tmp), ctx); |
|---|
| 757 | + } |
|---|
| 623 | 758 | goto emit_cond_jmp; |
|---|
| 624 | 759 | /* function call */ |
|---|
| 625 | 760 | case BPF_JMP | BPF_CALL: |
|---|
| 626 | 761 | { |
|---|
| 627 | 762 | const u8 r0 = bpf2a64[BPF_REG_0]; |
|---|
| 628 | | - const u64 func = (u64)__bpf_call_base + imm; |
|---|
| 763 | + bool func_addr_fixed; |
|---|
| 764 | + u64 func_addr; |
|---|
| 629 | 765 | |
|---|
| 630 | | - if (ctx->prog->is_func) |
|---|
| 631 | | - emit_addr_mov_i64(tmp, func, ctx); |
|---|
| 632 | | - else |
|---|
| 633 | | - emit_a64_mov_i64(tmp, func, ctx); |
|---|
| 766 | + ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, |
|---|
| 767 | + &func_addr, &func_addr_fixed); |
|---|
| 768 | + if (ret < 0) |
|---|
| 769 | + return ret; |
|---|
| 770 | + emit_addr_mov_i64(tmp, func_addr, ctx); |
|---|
| 634 | 771 | emit(A64_BLR(tmp), ctx); |
|---|
| 635 | 772 | emit(A64_MOV(1, r0, A64_R(0)), ctx); |
|---|
| 636 | 773 | break; |
|---|
| .. | .. |
|---|
| 668 | 805 | case BPF_LDX | BPF_MEM | BPF_H: |
|---|
| 669 | 806 | case BPF_LDX | BPF_MEM | BPF_B: |
|---|
| 670 | 807 | case BPF_LDX | BPF_MEM | BPF_DW: |
|---|
| 808 | + case BPF_LDX | BPF_PROBE_MEM | BPF_DW: |
|---|
| 809 | + case BPF_LDX | BPF_PROBE_MEM | BPF_W: |
|---|
| 810 | + case BPF_LDX | BPF_PROBE_MEM | BPF_H: |
|---|
| 811 | + case BPF_LDX | BPF_PROBE_MEM | BPF_B: |
|---|
| 671 | 812 | emit_a64_mov_i(1, tmp, off, ctx); |
|---|
| 672 | 813 | switch (BPF_SIZE(code)) { |
|---|
| 673 | 814 | case BPF_W: |
|---|
| .. | .. |
|---|
| 683 | 824 | emit(A64_LDR64(dst, src, tmp), ctx); |
|---|
| 684 | 825 | break; |
|---|
| 685 | 826 | } |
|---|
| 827 | + |
|---|
| 828 | + ret = add_exception_handler(insn, ctx, dst); |
|---|
| 829 | + if (ret) |
|---|
| 830 | + return ret; |
|---|
| 686 | 831 | break; |
|---|
| 687 | 832 | |
|---|
| 688 | 833 | /* speculation barrier */ |
|---|
| .. | .. |
|---|
| 775 | 920 | return 0; |
|---|
| 776 | 921 | } |
|---|
| 777 | 922 | |
|---|
| 778 | | -static int build_body(struct jit_ctx *ctx) |
|---|
| 923 | +static int build_body(struct jit_ctx *ctx, bool extra_pass) |
|---|
| 779 | 924 | { |
|---|
| 780 | 925 | const struct bpf_prog *prog = ctx->prog; |
|---|
| 781 | 926 | int i; |
|---|
| 782 | 927 | |
|---|
| 928 | + /* |
|---|
| 929 | + * - offset[0] offset of the end of prologue, |
|---|
| 930 | + * start of the 1st instruction. |
|---|
| 931 | + * - offset[1] - offset of the end of 1st instruction, |
|---|
| 932 | + * start of the 2nd instruction |
|---|
| 933 | + * [....] |
|---|
| 934 | + * - offset[3] - offset of the end of 3rd instruction, |
|---|
| 935 | + * start of 4th instruction |
|---|
| 936 | + */ |
|---|
| 783 | 937 | for (i = 0; i < prog->len; i++) { |
|---|
| 784 | 938 | const struct bpf_insn *insn = &prog->insnsi[i]; |
|---|
| 785 | 939 | int ret; |
|---|
| 786 | 940 | |
|---|
| 787 | | - ret = build_insn(insn, ctx); |
|---|
| 941 | + if (ctx->image == NULL) |
|---|
| 942 | + ctx->offset[i] = ctx->idx; |
|---|
| 943 | + ret = build_insn(insn, ctx, extra_pass); |
|---|
| 788 | 944 | if (ret > 0) { |
|---|
| 789 | 945 | i++; |
|---|
| 790 | 946 | if (ctx->image == NULL) |
|---|
| 791 | 947 | ctx->offset[i] = ctx->idx; |
|---|
| 792 | 948 | continue; |
|---|
| 793 | 949 | } |
|---|
| 794 | | - if (ctx->image == NULL) |
|---|
| 795 | | - ctx->offset[i] = ctx->idx; |
|---|
| 796 | 950 | if (ret) |
|---|
| 797 | 951 | return ret; |
|---|
| 798 | 952 | } |
|---|
| 953 | + /* |
|---|
| 954 | + * offset is allocated with prog->len + 1 so fill in |
|---|
| 955 | + * the last element with the offset after the last |
|---|
| 956 | + * instruction (end of program) |
|---|
| 957 | + */ |
|---|
| 958 | + if (ctx->image == NULL) |
|---|
| 959 | + ctx->offset[i] = ctx->idx; |
|---|
| 799 | 960 | |
|---|
| 800 | 961 | return 0; |
|---|
| 801 | 962 | } |
|---|
| .. | .. |
|---|
| 810 | 971 | if (a64_insn == AARCH64_BREAK_FAULT) |
|---|
| 811 | 972 | return -1; |
|---|
| 812 | 973 | } |
|---|
| 974 | + |
|---|
| 975 | + if (WARN_ON_ONCE(ctx->exentry_idx != ctx->prog->aux->num_exentries)) |
|---|
| 976 | + return -1; |
|---|
| 813 | 977 | |
|---|
| 814 | 978 | return 0; |
|---|
| 815 | 979 | } |
|---|
| .. | .. |
|---|
| 827 | 991 | |
|---|
| 828 | 992 | struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) |
|---|
| 829 | 993 | { |
|---|
| 994 | + int image_size, prog_size, extable_size; |
|---|
| 830 | 995 | struct bpf_prog *tmp, *orig_prog = prog; |
|---|
| 831 | 996 | struct bpf_binary_header *header; |
|---|
| 832 | 997 | struct arm64_jit_data *jit_data; |
|---|
| .. | .. |
|---|
| 834 | 999 | bool tmp_blinded = false; |
|---|
| 835 | 1000 | bool extra_pass = false; |
|---|
| 836 | 1001 | struct jit_ctx ctx; |
|---|
| 837 | | - int image_size; |
|---|
| 838 | 1002 | u8 *image_ptr; |
|---|
| 839 | 1003 | |
|---|
| 840 | 1004 | if (!prog->jit_requested) |
|---|
| .. | .. |
|---|
| 865 | 1029 | image_ptr = jit_data->image; |
|---|
| 866 | 1030 | header = jit_data->header; |
|---|
| 867 | 1031 | extra_pass = true; |
|---|
| 868 | | - image_size = sizeof(u32) * ctx.idx; |
|---|
| 1032 | + prog_size = sizeof(u32) * ctx.idx; |
|---|
| 869 | 1033 | goto skip_init_ctx; |
|---|
| 870 | 1034 | } |
|---|
| 871 | 1035 | memset(&ctx, 0, sizeof(ctx)); |
|---|
| 872 | 1036 | ctx.prog = prog; |
|---|
| 873 | 1037 | |
|---|
| 874 | | - ctx.offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL); |
|---|
| 1038 | + ctx.offset = kcalloc(prog->len + 1, sizeof(int), GFP_KERNEL); |
|---|
| 875 | 1039 | if (ctx.offset == NULL) { |
|---|
| 876 | 1040 | prog = orig_prog; |
|---|
| 877 | 1041 | goto out_off; |
|---|
| 878 | 1042 | } |
|---|
| 879 | 1043 | |
|---|
| 880 | | - /* 1. Initial fake pass to compute ctx->idx. */ |
|---|
| 881 | | - |
|---|
| 882 | | - /* Fake pass to fill in ctx->offset. */ |
|---|
| 883 | | - if (build_body(&ctx)) { |
|---|
| 1044 | + /* |
|---|
| 1045 | + * 1. Initial fake pass to compute ctx->idx and ctx->offset. |
|---|
| 1046 | + * |
|---|
| 1047 | + * BPF line info needs ctx->offset[i] to be the offset of |
|---|
| 1048 | + * instruction[i] in jited image, so build prologue first. |
|---|
| 1049 | + */ |
|---|
| 1050 | + if (build_prologue(&ctx, was_classic)) { |
|---|
| 884 | 1051 | prog = orig_prog; |
|---|
| 885 | 1052 | goto out_off; |
|---|
| 886 | 1053 | } |
|---|
| 887 | 1054 | |
|---|
| 888 | | - if (build_prologue(&ctx, was_classic)) { |
|---|
| 1055 | + if (build_body(&ctx, extra_pass)) { |
|---|
| 889 | 1056 | prog = orig_prog; |
|---|
| 890 | 1057 | goto out_off; |
|---|
| 891 | 1058 | } |
|---|
| .. | .. |
|---|
| 893 | 1060 | ctx.epilogue_offset = ctx.idx; |
|---|
| 894 | 1061 | build_epilogue(&ctx); |
|---|
| 895 | 1062 | |
|---|
| 1063 | + extable_size = prog->aux->num_exentries * |
|---|
| 1064 | + sizeof(struct exception_table_entry); |
|---|
| 1065 | + |
|---|
| 896 | 1066 | /* Now we know the actual image size. */ |
|---|
| 897 | | - image_size = sizeof(u32) * ctx.idx; |
|---|
| 1067 | + prog_size = sizeof(u32) * ctx.idx; |
|---|
| 1068 | + image_size = prog_size + extable_size; |
|---|
| 898 | 1069 | header = bpf_jit_binary_alloc(image_size, &image_ptr, |
|---|
| 899 | 1070 | sizeof(u32), jit_fill_hole); |
|---|
| 900 | 1071 | if (header == NULL) { |
|---|
| .. | .. |
|---|
| 905 | 1076 | /* 2. Now, the actual pass. */ |
|---|
| 906 | 1077 | |
|---|
| 907 | 1078 | ctx.image = (__le32 *)image_ptr; |
|---|
| 1079 | + if (extable_size) |
|---|
| 1080 | + prog->aux->extable = (void *)image_ptr + prog_size; |
|---|
| 908 | 1081 | skip_init_ctx: |
|---|
| 909 | 1082 | ctx.idx = 0; |
|---|
| 1083 | + ctx.exentry_idx = 0; |
|---|
| 910 | 1084 | |
|---|
| 911 | 1085 | build_prologue(&ctx, was_classic); |
|---|
| 912 | 1086 | |
|---|
| 913 | | - if (build_body(&ctx)) { |
|---|
| 1087 | + if (build_body(&ctx, extra_pass)) { |
|---|
| 914 | 1088 | bpf_jit_binary_free(header); |
|---|
| 915 | 1089 | prog = orig_prog; |
|---|
| 916 | 1090 | goto out_off; |
|---|
| .. | .. |
|---|
| 927 | 1101 | |
|---|
| 928 | 1102 | /* And we're done. */ |
|---|
| 929 | 1103 | if (bpf_jit_enable > 1) |
|---|
| 930 | | - bpf_jit_dump(prog->len, image_size, 2, ctx.image); |
|---|
| 1104 | + bpf_jit_dump(prog->len, prog_size, 2, ctx.image); |
|---|
| 931 | 1105 | |
|---|
| 932 | 1106 | bpf_flush_icache(header, ctx.image + ctx.idx); |
|---|
| 933 | 1107 | |
|---|
| .. | .. |
|---|
| 938 | 1112 | bpf_jit_binary_free(header); |
|---|
| 939 | 1113 | prog->bpf_func = NULL; |
|---|
| 940 | 1114 | prog->jited = 0; |
|---|
| 1115 | + prog->jited_len = 0; |
|---|
| 941 | 1116 | goto out_off; |
|---|
| 942 | 1117 | } |
|---|
| 943 | 1118 | bpf_jit_binary_lock_ro(header); |
|---|
| 1119 | + trace_android_vh_set_memory_ro((unsigned long)header, header->pages); |
|---|
| 1120 | + trace_android_vh_set_memory_x((unsigned long)header, header->pages); |
|---|
| 944 | 1121 | } else { |
|---|
| 945 | 1122 | jit_data->ctx = ctx; |
|---|
| 946 | 1123 | jit_data->image = image_ptr; |
|---|
| .. | .. |
|---|
| 948 | 1125 | } |
|---|
| 949 | 1126 | prog->bpf_func = (void *)ctx.image; |
|---|
| 950 | 1127 | prog->jited = 1; |
|---|
| 951 | | - prog->jited_len = image_size; |
|---|
| 1128 | + prog->jited_len = prog_size; |
|---|
| 952 | 1129 | |
|---|
| 953 | 1130 | if (!prog->is_func || extra_pass) { |
|---|
| 1131 | + int i; |
|---|
| 1132 | + |
|---|
| 1133 | + /* offset[prog->len] is the size of program */ |
|---|
| 1134 | + for (i = 0; i <= prog->len; i++) |
|---|
| 1135 | + ctx.offset[i] *= AARCH64_INSN_SIZE; |
|---|
| 1136 | + bpf_prog_fill_jited_linfo(prog, ctx.offset + 1); |
|---|
| 954 | 1137 | out_off: |
|---|
| 955 | 1138 | kfree(ctx.offset); |
|---|
| 956 | 1139 | kfree(jit_data); |
|---|
| .. | .. |
|---|
| 963 | 1146 | return prog; |
|---|
| 964 | 1147 | } |
|---|
| 965 | 1148 | |
|---|
| 966 | | -#ifdef CONFIG_CFI_CLANG |
|---|
| 967 | | -bool arch_bpf_jit_check_func(const struct bpf_prog *prog) |
|---|
| 1149 | +u64 bpf_jit_alloc_exec_limit(void) |
|---|
| 968 | 1150 | { |
|---|
| 969 | | - const uintptr_t func = (const uintptr_t)prog->bpf_func; |
|---|
| 970 | | - |
|---|
| 971 | | - /* |
|---|
| 972 | | - * bpf_func must be correctly aligned and within the correct region. |
|---|
| 973 | | - * module_alloc places JIT code in the module region, unless |
|---|
| 974 | | - * ARM64_MODULE_PLTS is enabled, in which case we might end up using |
|---|
| 975 | | - * the vmalloc region too. |
|---|
| 976 | | - */ |
|---|
| 977 | | - if (unlikely(!IS_ALIGNED(func, sizeof(u32)))) |
|---|
| 978 | | - return false; |
|---|
| 979 | | - |
|---|
| 980 | | - if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && |
|---|
| 981 | | - is_vmalloc_addr(prog->bpf_func)) |
|---|
| 982 | | - return true; |
|---|
| 983 | | - |
|---|
| 984 | | - return (func >= MODULES_VADDR && func < MODULES_END); |
|---|
| 1151 | + return VMALLOC_END - VMALLOC_START; |
|---|
| 985 | 1152 | } |
|---|
| 986 | | -#endif |
|---|
| 1153 | + |
|---|
| 1154 | +void *bpf_jit_alloc_exec(unsigned long size) |
|---|
| 1155 | +{ |
|---|
| 1156 | + return vmalloc(size); |
|---|
| 1157 | +} |
|---|
| 1158 | + |
|---|
| 1159 | +void bpf_jit_free_exec(void *addr) |
|---|
| 1160 | +{ |
|---|
| 1161 | + return vfree(addr); |
|---|
| 1162 | +} |
|---|