.. | .. |
---|
| 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 | +} |
---|