Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'bpf-jit-cleanups'

Daniel Borkmann says:

====================
This series follows up mostly with with some minor cleanups on top
of 'Move ld_abs/ld_ind to native BPF' as well as implements better
32/64 bit immediate load into register and saves tail call init on
cBPF for the arm64 JIT. Last but not least we add a couple of test
cases. For details please see individual patches. Thanks!

v1 -> v2:
- Minor fix in i64_i16_blocks() to remove 24 shift.
- Added last two patches.
- Added Acks from prior round.
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+229 -99
+3 -10
arch/arm/net/bpf_jit_32.c
··· 234 234 #define SCRATCH_SIZE 80 235 235 236 236 /* total stack size used in JITed code */ 237 - #define _STACK_SIZE \ 238 - (ctx->prog->aux->stack_depth + \ 239 - + SCRATCH_SIZE + \ 240 - + 4 /* extra for skb_copy_bits buffer */) 241 - 242 - #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT) 237 + #define _STACK_SIZE (ctx->prog->aux->stack_depth + SCRATCH_SIZE) 238 + #define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT) 243 239 244 240 /* Get the offset of eBPF REGISTERs stored on scratch space. */ 245 - #define STACK_VAR(off) (STACK_SIZE-off-4) 246 - 247 - /* Offset of skb_copy_bits buffer */ 248 - #define SKB_BUFFER STACK_VAR(SCRATCH_SIZE) 241 + #define STACK_VAR(off) (STACK_SIZE - off) 249 242 250 243 #if __LINUX_ARM_ARCH__ < 7 251 244
+70 -47
arch/arm64/net/bpf_jit_comp.c
··· 21 21 #include <linux/bpf.h> 22 22 #include <linux/filter.h> 23 23 #include <linux/printk.h> 24 - #include <linux/skbuff.h> 25 24 #include <linux/slab.h> 26 25 27 26 #include <asm/byteorder.h> ··· 79 80 ctx->idx++; 80 81 } 81 82 82 - static inline void emit_a64_mov_i64(const int reg, const u64 val, 83 - struct jit_ctx *ctx) 84 - { 85 - u64 tmp = val; 86 - int shift = 0; 87 - 88 - emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx); 89 - tmp >>= 16; 90 - shift += 16; 91 - while (tmp) { 92 - if (tmp & 0xffff) 93 - emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx); 94 - tmp >>= 16; 95 - shift += 16; 96 - } 97 - } 98 - 99 - static inline void emit_addr_mov_i64(const int reg, const u64 val, 100 - struct jit_ctx *ctx) 101 - { 102 - u64 tmp = val; 103 - int shift = 0; 104 - 105 - emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx); 106 - for (;shift < 48;) { 107 - tmp >>= 16; 108 - shift += 16; 109 - emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx); 110 - } 111 - } 112 - 113 83 static inline void emit_a64_mov_i(const int is64, const int reg, 114 84 const s32 val, struct jit_ctx *ctx) 115 85 { ··· 90 122 emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx); 91 123 } else { 92 124 emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx); 93 - emit(A64_MOVK(is64, reg, lo, 0), ctx); 125 + if (lo != 0xffff) 126 + emit(A64_MOVK(is64, reg, lo, 0), ctx); 94 127 } 95 128 } else { 96 129 emit(A64_MOVZ(is64, reg, lo, 0), ctx); 97 130 if (hi) 98 131 emit(A64_MOVK(is64, reg, hi, 16), ctx); 132 + } 133 + } 134 + 135 + static int i64_i16_blocks(const u64 val, bool inverse) 136 + { 137 + return (((val >> 0) & 0xffff) != (inverse ? 0xffff : 0x0000)) + 138 + (((val >> 16) & 0xffff) != (inverse ? 0xffff : 0x0000)) + 139 + (((val >> 32) & 0xffff) != (inverse ? 0xffff : 0x0000)) + 140 + (((val >> 48) & 0xffff) != (inverse ? 0xffff : 0x0000)); 141 + } 142 + 143 + static inline void emit_a64_mov_i64(const int reg, const u64 val, 144 + struct jit_ctx *ctx) 145 + { 146 + u64 nrm_tmp = val, rev_tmp = ~val; 147 + bool inverse; 148 + int shift; 149 + 150 + if (!(nrm_tmp >> 32)) 151 + return emit_a64_mov_i(0, reg, (u32)val, ctx); 152 + 153 + inverse = i64_i16_blocks(nrm_tmp, true) < i64_i16_blocks(nrm_tmp, false); 154 + shift = max(round_down((inverse ? (fls64(rev_tmp) - 1) : 155 + (fls64(nrm_tmp) - 1)), 16), 0); 156 + if (inverse) 157 + emit(A64_MOVN(1, reg, (rev_tmp >> shift) & 0xffff, shift), ctx); 158 + else 159 + emit(A64_MOVZ(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx); 160 + shift -= 16; 161 + while (shift >= 0) { 162 + if (((nrm_tmp >> shift) & 0xffff) != (inverse ? 0xffff : 0x0000)) 163 + emit(A64_MOVK(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx); 164 + shift -= 16; 165 + } 166 + } 167 + 168 + /* 169 + * This is an unoptimized 64 immediate emission used for BPF to BPF call 170 + * addresses. It will always do a full 64 bit decomposition as otherwise 171 + * more complexity in the last extra pass is required since we previously 172 + * reserved 4 instructions for the address. 173 + */ 174 + static inline void emit_addr_mov_i64(const int reg, const u64 val, 175 + struct jit_ctx *ctx) 176 + { 177 + u64 tmp = val; 178 + int shift = 0; 179 + 180 + emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx); 181 + for (;shift < 48;) { 182 + tmp >>= 16; 183 + shift += 16; 184 + emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx); 99 185 } 100 186 } 101 187 ··· 185 163 /* Tail call offset to jump into */ 186 164 #define PROLOGUE_OFFSET 7 187 165 188 - static int build_prologue(struct jit_ctx *ctx) 166 + static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) 189 167 { 190 168 const struct bpf_prog *prog = ctx->prog; 191 169 const u8 r6 = bpf2a64[BPF_REG_6]; ··· 210 188 * | ... | BPF prog stack 211 189 * | | 212 190 * +-----+ <= (BPF_FP - prog->aux->stack_depth) 213 - * |RSVD | JIT scratchpad 191 + * |RSVD | padding 214 192 * current A64_SP => +-----+ <= (BPF_FP - ctx->stack_size) 215 193 * | | 216 194 * | ... | Function call stack ··· 232 210 /* Set up BPF prog stack base register */ 233 211 emit(A64_MOV(1, fp, A64_SP), ctx); 234 212 235 - /* Initialize tail_call_cnt */ 236 - emit(A64_MOVZ(1, tcc, 0, 0), ctx); 213 + if (!ebpf_from_cbpf) { 214 + /* Initialize tail_call_cnt */ 215 + emit(A64_MOVZ(1, tcc, 0, 0), ctx); 237 216 238 - cur_offset = ctx->idx - idx0; 239 - if (cur_offset != PROLOGUE_OFFSET) { 240 - pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n", 241 - cur_offset, PROLOGUE_OFFSET); 242 - return -1; 217 + cur_offset = ctx->idx - idx0; 218 + if (cur_offset != PROLOGUE_OFFSET) { 219 + pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n", 220 + cur_offset, PROLOGUE_OFFSET); 221 + return -1; 222 + } 243 223 } 244 224 245 - /* 4 byte extra for skb_copy_bits buffer */ 246 - ctx->stack_size = prog->aux->stack_depth + 4; 247 - ctx->stack_size = STACK_ALIGN(ctx->stack_size); 225 + ctx->stack_size = STACK_ALIGN(prog->aux->stack_depth); 248 226 249 227 /* Set up function call stack */ 250 228 emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); ··· 808 786 struct bpf_prog *tmp, *orig_prog = prog; 809 787 struct bpf_binary_header *header; 810 788 struct arm64_jit_data *jit_data; 789 + bool was_classic = bpf_prog_was_classic(prog); 811 790 bool tmp_blinded = false; 812 791 bool extra_pass = false; 813 792 struct jit_ctx ctx; ··· 863 840 goto out_off; 864 841 } 865 842 866 - if (build_prologue(&ctx)) { 843 + if (build_prologue(&ctx, was_classic)) { 867 844 prog = orig_prog; 868 845 goto out_off; 869 846 } ··· 886 863 skip_init_ctx: 887 864 ctx.idx = 0; 888 865 889 - build_prologue(&ctx); 866 + build_prologue(&ctx, was_classic); 890 867 891 868 if (build_body(&ctx)) { 892 869 bpf_jit_binary_free(header);
-26
arch/mips/net/ebpf_jit.c
··· 95 95 * struct jit_ctx - JIT context 96 96 * @skf: The sk_filter 97 97 * @stack_size: eBPF stack size 98 - * @tmp_offset: eBPF $sp offset to 8-byte temporary memory 99 98 * @idx: Instruction index 100 99 * @flags: JIT flags 101 100 * @offsets: Instruction offsets ··· 104 105 struct jit_ctx { 105 106 const struct bpf_prog *skf; 106 107 int stack_size; 107 - int tmp_offset; 108 108 u32 idx; 109 109 u32 flags; 110 110 u32 *offsets; ··· 291 293 locals_size = (ctx->flags & EBPF_SEEN_FP) ? MAX_BPF_STACK : 0; 292 294 293 295 stack_adjust += locals_size; 294 - ctx->tmp_offset = locals_size; 295 296 296 297 ctx->stack_size = stack_adjust; 297 298 ··· 396 399 emit_instr(ctx, lui, reg, upper >> 16); 397 400 emit_instr(ctx, addiu, reg, reg, lower); 398 401 } 399 - 400 402 } 401 403 402 404 static int gen_imm_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, ··· 540 544 } 541 545 } 542 546 543 - return 0; 544 - } 545 - 546 - static void * __must_check 547 - ool_skb_header_pointer(const struct sk_buff *skb, int offset, 548 - int len, void *buffer) 549 - { 550 - return skb_header_pointer(skb, offset, len, buffer); 551 - } 552 - 553 - static int size_to_len(const struct bpf_insn *insn) 554 - { 555 - switch (BPF_SIZE(insn->code)) { 556 - case BPF_B: 557 - return 1; 558 - case BPF_H: 559 - return 2; 560 - case BPF_W: 561 - return 4; 562 - case BPF_DW: 563 - return 8; 564 - } 565 547 return 0; 566 548 } 567 549
-1
arch/sparc/net/bpf_jit_comp_64.c
··· 894 894 const int i = insn - ctx->prog->insnsi; 895 895 const s16 off = insn->off; 896 896 const s32 imm = insn->imm; 897 - u32 *func; 898 897 899 898 if (insn->src_reg == BPF_REG_FP) 900 899 ctx->saw_frame_pointer = true;
+14 -15
arch/x86/include/asm/nospec-branch.h
··· 301 301 * jmp *%edx for x86_32 302 302 */ 303 303 #ifdef CONFIG_RETPOLINE 304 - #ifdef CONFIG_X86_64 305 - # define RETPOLINE_RAX_BPF_JIT_SIZE 17 306 - # define RETPOLINE_RAX_BPF_JIT() \ 304 + # ifdef CONFIG_X86_64 305 + # define RETPOLINE_RAX_BPF_JIT_SIZE 17 306 + # define RETPOLINE_RAX_BPF_JIT() \ 307 307 do { \ 308 308 EMIT1_off32(0xE8, 7); /* callq do_rop */ \ 309 309 /* spec_trap: */ \ ··· 314 314 EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \ 315 315 EMIT1(0xC3); /* retq */ \ 316 316 } while (0) 317 - #else 318 - # define RETPOLINE_EDX_BPF_JIT() \ 317 + # else /* !CONFIG_X86_64 */ 318 + # define RETPOLINE_EDX_BPF_JIT() \ 319 319 do { \ 320 320 EMIT1_off32(0xE8, 7); /* call do_rop */ \ 321 321 /* spec_trap: */ \ ··· 326 326 EMIT3(0x89, 0x14, 0x24); /* mov %edx,(%esp) */ \ 327 327 EMIT1(0xC3); /* ret */ \ 328 328 } while (0) 329 - #endif 329 + # endif 330 330 #else /* !CONFIG_RETPOLINE */ 331 - 332 - #ifdef CONFIG_X86_64 333 - # define RETPOLINE_RAX_BPF_JIT_SIZE 2 334 - # define RETPOLINE_RAX_BPF_JIT() \ 335 - EMIT2(0xFF, 0xE0); /* jmp *%rax */ 336 - #else 337 - # define RETPOLINE_EDX_BPF_JIT() \ 338 - EMIT2(0xFF, 0xE2) /* jmp *%edx */ 339 - #endif 331 + # ifdef CONFIG_X86_64 332 + # define RETPOLINE_RAX_BPF_JIT_SIZE 2 333 + # define RETPOLINE_RAX_BPF_JIT() \ 334 + EMIT2(0xFF, 0xE0); /* jmp *%rax */ 335 + # else /* !CONFIG_X86_64 */ 336 + # define RETPOLINE_EDX_BPF_JIT() \ 337 + EMIT2(0xFF, 0xE2) /* jmp *%edx */ 338 + # endif 340 339 #endif 341 340 342 341 #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
+80
tools/testing/selftests/bpf/bpf_rand.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __BPF_RAND__ 3 + #define __BPF_RAND__ 4 + 5 + #include <stdint.h> 6 + #include <stdlib.h> 7 + #include <time.h> 8 + 9 + static inline uint64_t bpf_rand_mask(uint64_t mask) 10 + { 11 + return (((uint64_t)(uint32_t)rand()) | 12 + ((uint64_t)(uint32_t)rand() << 32)) & mask; 13 + } 14 + 15 + #define bpf_rand_ux(x, m) \ 16 + static inline uint64_t bpf_rand_u##x(int shift) \ 17 + { \ 18 + return bpf_rand_mask((m)) << shift; \ 19 + } 20 + 21 + bpf_rand_ux( 8, 0xffULL) 22 + bpf_rand_ux(16, 0xffffULL) 23 + bpf_rand_ux(24, 0xffffffULL) 24 + bpf_rand_ux(32, 0xffffffffULL) 25 + bpf_rand_ux(40, 0xffffffffffULL) 26 + bpf_rand_ux(48, 0xffffffffffffULL) 27 + bpf_rand_ux(56, 0xffffffffffffffULL) 28 + bpf_rand_ux(64, 0xffffffffffffffffULL) 29 + 30 + static inline void bpf_semi_rand_init(void) 31 + { 32 + srand(time(NULL)); 33 + } 34 + 35 + static inline uint64_t bpf_semi_rand_get(void) 36 + { 37 + switch (rand() % 39) { 38 + case 0: return 0x000000ff00000000ULL | bpf_rand_u8(0); 39 + case 1: return 0xffffffff00000000ULL | bpf_rand_u16(0); 40 + case 2: return 0x00000000ffff0000ULL | bpf_rand_u16(0); 41 + case 3: return 0x8000000000000000ULL | bpf_rand_u32(0); 42 + case 4: return 0x00000000f0000000ULL | bpf_rand_u32(0); 43 + case 5: return 0x0000000100000000ULL | bpf_rand_u24(0); 44 + case 6: return 0x800ff00000000000ULL | bpf_rand_u32(0); 45 + case 7: return 0x7fffffff00000000ULL | bpf_rand_u32(0); 46 + case 8: return 0xffffffffffffff00ULL ^ bpf_rand_u32(24); 47 + case 9: return 0xffffffffffffff00ULL | bpf_rand_u8(0); 48 + case 10: return 0x0000000010000000ULL | bpf_rand_u32(0); 49 + case 11: return 0xf000000000000000ULL | bpf_rand_u8(0); 50 + case 12: return 0x0000f00000000000ULL | bpf_rand_u8(8); 51 + case 13: return 0x000000000f000000ULL | bpf_rand_u8(16); 52 + case 14: return 0x0000000000000f00ULL | bpf_rand_u8(32); 53 + case 15: return 0x00fff00000000f00ULL | bpf_rand_u8(48); 54 + case 16: return 0x00007fffffffffffULL ^ bpf_rand_u32(1); 55 + case 17: return 0xffff800000000000ULL | bpf_rand_u8(4); 56 + case 18: return 0xffff800000000000ULL | bpf_rand_u8(20); 57 + case 19: return (0xffffffc000000000ULL + 0x80000ULL) | bpf_rand_u32(0); 58 + case 20: return (0xffffffc000000000ULL - 0x04000000ULL) | bpf_rand_u32(0); 59 + case 21: return 0x0000000000000000ULL | bpf_rand_u8(55) | bpf_rand_u32(20); 60 + case 22: return 0xffffffffffffffffULL ^ bpf_rand_u8(3) ^ bpf_rand_u32(40); 61 + case 23: return 0x0000000000000000ULL | bpf_rand_u8(bpf_rand_u8(0) % 64); 62 + case 24: return 0x0000000000000000ULL | bpf_rand_u16(bpf_rand_u8(0) % 64); 63 + case 25: return 0xffffffffffffffffULL ^ bpf_rand_u8(bpf_rand_u8(0) % 64); 64 + case 26: return 0xffffffffffffffffULL ^ bpf_rand_u40(bpf_rand_u8(0) % 64); 65 + case 27: return 0x0000800000000000ULL; 66 + case 28: return 0x8000000000000000ULL; 67 + case 29: return 0x0000000000000000ULL; 68 + case 30: return 0xffffffffffffffffULL; 69 + case 31: return bpf_rand_u16(bpf_rand_u8(0) % 64); 70 + case 32: return bpf_rand_u24(bpf_rand_u8(0) % 64); 71 + case 33: return bpf_rand_u32(bpf_rand_u8(0) % 64); 72 + case 34: return bpf_rand_u40(bpf_rand_u8(0) % 64); 73 + case 35: return bpf_rand_u48(bpf_rand_u8(0) % 64); 74 + case 36: return bpf_rand_u56(bpf_rand_u8(0) % 64); 75 + case 37: return bpf_rand_u64(bpf_rand_u8(0) % 64); 76 + default: return bpf_rand_u64(0); 77 + } 78 + } 79 + 80 + #endif /* __BPF_RAND__ */
+62
tools/testing/selftests/bpf/test_verifier.c
··· 41 41 # endif 42 42 #endif 43 43 #include "bpf_rlimit.h" 44 + #include "bpf_rand.h" 44 45 #include "../../../include/linux/filter.h" 45 46 46 47 #ifndef ARRAY_SIZE ··· 151 150 while (i < len - 1) 152 151 insn[i++] = BPF_LD_ABS(BPF_B, 1); 153 152 insn[i] = BPF_EXIT_INSN(); 153 + } 154 + 155 + static void bpf_fill_rand_ld_dw(struct bpf_test *self) 156 + { 157 + struct bpf_insn *insn = self->insns; 158 + uint64_t res = 0; 159 + int i = 0; 160 + 161 + insn[i++] = BPF_MOV32_IMM(BPF_REG_0, 0); 162 + while (i < self->retval) { 163 + uint64_t val = bpf_semi_rand_get(); 164 + struct bpf_insn tmp[2] = { BPF_LD_IMM64(BPF_REG_1, val) }; 165 + 166 + res ^= val; 167 + insn[i++] = tmp[0]; 168 + insn[i++] = tmp[1]; 169 + insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1); 170 + } 171 + insn[i++] = BPF_MOV64_REG(BPF_REG_1, BPF_REG_0); 172 + insn[i++] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32); 173 + insn[i++] = BPF_ALU64_REG(BPF_XOR, BPF_REG_0, BPF_REG_1); 174 + insn[i] = BPF_EXIT_INSN(); 175 + res ^= (res >> 32); 176 + self->retval = (uint32_t)res; 154 177 } 155 178 156 179 static struct bpf_test tests[] = { ··· 11999 11974 .result = ACCEPT, 12000 11975 .retval = 10, 12001 11976 }, 11977 + { 11978 + "ld_dw: xor semi-random 64 bit imms, test 1", 11979 + .insns = { }, 11980 + .data = { }, 11981 + .fill_helper = bpf_fill_rand_ld_dw, 11982 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 11983 + .result = ACCEPT, 11984 + .retval = 4090, 11985 + }, 11986 + { 11987 + "ld_dw: xor semi-random 64 bit imms, test 2", 11988 + .insns = { }, 11989 + .data = { }, 11990 + .fill_helper = bpf_fill_rand_ld_dw, 11991 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 11992 + .result = ACCEPT, 11993 + .retval = 2047, 11994 + }, 11995 + { 11996 + "ld_dw: xor semi-random 64 bit imms, test 3", 11997 + .insns = { }, 11998 + .data = { }, 11999 + .fill_helper = bpf_fill_rand_ld_dw, 12000 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 12001 + .result = ACCEPT, 12002 + .retval = 511, 12003 + }, 12004 + { 12005 + "ld_dw: xor semi-random 64 bit imms, test 4", 12006 + .insns = { }, 12007 + .data = { }, 12008 + .fill_helper = bpf_fill_rand_ld_dw, 12009 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 12010 + .result = ACCEPT, 12011 + .retval = 5, 12012 + }, 12002 12013 }; 12003 12014 12004 12015 static int probe_filter_length(const struct bpf_insn *fp) ··· 12407 12346 return EXIT_FAILURE; 12408 12347 } 12409 12348 12349 + bpf_semi_rand_init(); 12410 12350 return do_test(unpriv, from, to); 12411 12351 }