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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Daniel Borkmann says:

====================
pull-request: bpf 2018-01-18

The following pull-request contains BPF updates for your *net* tree.

The main changes are:

1) Fix a divide by zero due to wrong if (src_reg == 0) check in
64-bit mode. Properly handle this in interpreter and mask it
also generically in verifier to guard against similar checks
in JITs, from Eric and Alexei.

2) Fix a bug in arm64 JIT when tail calls are involved and progs
have different stack sizes, from Daniel.

3) Reject stores into BPF context that are not expected BPF_STX |
BPF_MEM variant, from Daniel.

4) Mark dst reg as unknown on {s,u}bounds adjustments when the
src reg has derived bounds from dead branches, from Daniel.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+219 -25
+11 -9
arch/arm64/net/bpf_jit_comp.c
··· 148 148 /* Stack must be multiples of 16B */ 149 149 #define STACK_ALIGN(sz) (((sz) + 15) & ~15) 150 150 151 - #define PROLOGUE_OFFSET 8 151 + /* Tail call offset to jump into */ 152 + #define PROLOGUE_OFFSET 7 152 153 153 154 static int build_prologue(struct jit_ctx *ctx) 154 155 { ··· 201 200 /* Initialize tail_call_cnt */ 202 201 emit(A64_MOVZ(1, tcc, 0, 0), ctx); 203 202 204 - /* 4 byte extra for skb_copy_bits buffer */ 205 - ctx->stack_size = prog->aux->stack_depth + 4; 206 - ctx->stack_size = STACK_ALIGN(ctx->stack_size); 207 - 208 - /* Set up function call stack */ 209 - emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); 210 - 211 203 cur_offset = ctx->idx - idx0; 212 204 if (cur_offset != PROLOGUE_OFFSET) { 213 205 pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n", 214 206 cur_offset, PROLOGUE_OFFSET); 215 207 return -1; 216 208 } 209 + 210 + /* 4 byte extra for skb_copy_bits buffer */ 211 + ctx->stack_size = prog->aux->stack_depth + 4; 212 + ctx->stack_size = STACK_ALIGN(ctx->stack_size); 213 + 214 + /* Set up function call stack */ 215 + emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); 217 216 return 0; 218 217 } 219 218 ··· 261 260 emit(A64_LDR64(prg, tmp, prg), ctx); 262 261 emit(A64_CBZ(1, prg, jmp_offset), ctx); 263 262 264 - /* goto *(prog->bpf_func + prologue_size); */ 263 + /* goto *(prog->bpf_func + prologue_offset); */ 265 264 off = offsetof(struct bpf_prog, bpf_func); 266 265 emit_a64_mov_i64(tmp, off, ctx); 267 266 emit(A64_LDR64(tmp, prg, tmp), ctx); 268 267 emit(A64_ADD_I(1, tmp, tmp, sizeof(u32) * PROLOGUE_OFFSET), ctx); 268 + emit(A64_ADD_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); 269 269 emit(A64_BR(tmp), ctx); 270 270 271 271 /* out: */
+2 -2
kernel/bpf/core.c
··· 956 956 DST = tmp; 957 957 CONT; 958 958 ALU_MOD_X: 959 - if (unlikely(SRC == 0)) 959 + if (unlikely((u32)SRC == 0)) 960 960 return 0; 961 961 tmp = (u32) DST; 962 962 DST = do_div(tmp, (u32) SRC); ··· 975 975 DST = div64_u64(DST, SRC); 976 976 CONT; 977 977 ALU_DIV_X: 978 - if (unlikely(SRC == 0)) 978 + if (unlikely((u32)SRC == 0)) 979 979 return 0; 980 980 tmp = (u32) DST; 981 981 do_div(tmp, (u32) SRC);
+53 -11
kernel/bpf/verifier.c
··· 978 978 return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno); 979 979 } 980 980 981 + static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) 982 + { 983 + const struct bpf_reg_state *reg = cur_regs(env) + regno; 984 + 985 + return reg->type == PTR_TO_CTX; 986 + } 987 + 981 988 static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, 982 989 const struct bpf_reg_state *reg, 983 990 int off, int size, bool strict) ··· 1262 1255 1263 1256 if (is_pointer_value(env, insn->src_reg)) { 1264 1257 verbose(env, "R%d leaks addr into mem\n", insn->src_reg); 1258 + return -EACCES; 1259 + } 1260 + 1261 + if (is_ctx_reg(env, insn->dst_reg)) { 1262 + verbose(env, "BPF_XADD stores into R%d context is not allowed\n", 1263 + insn->dst_reg); 1265 1264 return -EACCES; 1266 1265 } 1267 1266 ··· 1895 1882 1896 1883 dst_reg = &regs[dst]; 1897 1884 1898 - if (WARN_ON_ONCE(known && (smin_val != smax_val))) { 1899 - print_verifier_state(env, env->cur_state); 1900 - verbose(env, 1901 - "verifier internal error: known but bad sbounds\n"); 1902 - return -EINVAL; 1903 - } 1904 - if (WARN_ON_ONCE(known && (umin_val != umax_val))) { 1905 - print_verifier_state(env, env->cur_state); 1906 - verbose(env, 1907 - "verifier internal error: known but bad ubounds\n"); 1908 - return -EINVAL; 1885 + if ((known && (smin_val != smax_val || umin_val != umax_val)) || 1886 + smin_val > smax_val || umin_val > umax_val) { 1887 + /* Taint dst register if offset had invalid bounds derived from 1888 + * e.g. dead branches. 1889 + */ 1890 + __mark_reg_unknown(dst_reg); 1891 + return 0; 1909 1892 } 1910 1893 1911 1894 if (BPF_CLASS(insn->code) != BPF_ALU64) { ··· 2092 2083 umax_val = src_reg.umax_value; 2093 2084 src_known = tnum_is_const(src_reg.var_off); 2094 2085 dst_known = tnum_is_const(dst_reg->var_off); 2086 + 2087 + if ((src_known && (smin_val != smax_val || umin_val != umax_val)) || 2088 + smin_val > smax_val || umin_val > umax_val) { 2089 + /* Taint dst register if offset had invalid bounds derived from 2090 + * e.g. dead branches. 2091 + */ 2092 + __mark_reg_unknown(dst_reg); 2093 + return 0; 2094 + } 2095 2095 2096 2096 if (!src_known && 2097 2097 opcode != BPF_ADD && opcode != BPF_SUB && opcode != BPF_AND) { ··· 4011 3993 if (err) 4012 3994 return err; 4013 3995 3996 + if (is_ctx_reg(env, insn->dst_reg)) { 3997 + verbose(env, "BPF_ST stores into R%d context is not allowed\n", 3998 + insn->dst_reg); 3999 + return -EACCES; 4000 + } 4001 + 4014 4002 /* check that memory (dst_reg + off) is writeable */ 4015 4003 err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, 4016 4004 BPF_SIZE(insn->code), BPF_WRITE, ··· 4469 4445 int i, cnt, delta = 0; 4470 4446 4471 4447 for (i = 0; i < insn_cnt; i++, insn++) { 4448 + if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) || 4449 + insn->code == (BPF_ALU | BPF_DIV | BPF_X)) { 4450 + /* due to JIT bugs clear upper 32-bits of src register 4451 + * before div/mod operation 4452 + */ 4453 + insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg); 4454 + insn_buf[1] = *insn; 4455 + cnt = 2; 4456 + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); 4457 + if (!new_prog) 4458 + return -ENOMEM; 4459 + 4460 + delta += cnt - 1; 4461 + env->prog = prog = new_prog; 4462 + insn = new_prog->insnsi + i + delta; 4463 + continue; 4464 + } 4465 + 4472 4466 if (insn->code != (BPF_JMP | BPF_CALL)) 4473 4467 continue; 4474 4468
+4
net/core/filter.c
··· 458 458 convert_bpf_extensions(fp, &insn)) 459 459 break; 460 460 461 + if (fp->code == (BPF_ALU | BPF_DIV | BPF_X) || 462 + fp->code == (BPF_ALU | BPF_MOD | BPF_X)) 463 + *insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X); 464 + 461 465 *insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k); 462 466 break; 463 467
+149 -3
tools/testing/selftests/bpf/test_verifier.c
··· 2593 2593 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 2594 2594 }, 2595 2595 { 2596 + "context stores via ST", 2597 + .insns = { 2598 + BPF_MOV64_IMM(BPF_REG_0, 0), 2599 + BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0), 2600 + BPF_EXIT_INSN(), 2601 + }, 2602 + .errstr = "BPF_ST stores into R1 context is not allowed", 2603 + .result = REJECT, 2604 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 2605 + }, 2606 + { 2607 + "context stores via XADD", 2608 + .insns = { 2609 + BPF_MOV64_IMM(BPF_REG_0, 0), 2610 + BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_1, 2611 + BPF_REG_0, offsetof(struct __sk_buff, mark), 0), 2612 + BPF_EXIT_INSN(), 2613 + }, 2614 + .errstr = "BPF_XADD stores into R1 context is not allowed", 2615 + .result = REJECT, 2616 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 2617 + }, 2618 + { 2596 2619 "direct packet access: test1", 2597 2620 .insns = { 2598 2621 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, ··· 4335 4312 .fixup_map1 = { 2 }, 4336 4313 .errstr_unpriv = "R2 leaks addr into mem", 4337 4314 .result_unpriv = REJECT, 4338 - .result = ACCEPT, 4315 + .result = REJECT, 4316 + .errstr = "BPF_XADD stores into R1 context is not allowed", 4339 4317 }, 4340 4318 { 4341 4319 "leak pointer into ctx 2", ··· 4350 4326 }, 4351 4327 .errstr_unpriv = "R10 leaks addr into mem", 4352 4328 .result_unpriv = REJECT, 4353 - .result = ACCEPT, 4329 + .result = REJECT, 4330 + .errstr = "BPF_XADD stores into R1 context is not allowed", 4354 4331 }, 4355 4332 { 4356 4333 "leak pointer into ctx 3", ··· 6732 6707 BPF_JMP_IMM(BPF_JA, 0, 0, -7), 6733 6708 }, 6734 6709 .fixup_map1 = { 4 }, 6735 - .errstr = "unbounded min value", 6710 + .errstr = "R0 invalid mem access 'inv'", 6736 6711 .result = REJECT, 6737 6712 }, 6738 6713 { ··· 8632 8607 .result = REJECT, 8633 8608 .prog_type = BPF_PROG_TYPE_XDP, 8634 8609 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, 8610 + }, 8611 + { 8612 + "check deducing bounds from const, 1", 8613 + .insns = { 8614 + BPF_MOV64_IMM(BPF_REG_0, 1), 8615 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 1, 0), 8616 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8617 + BPF_EXIT_INSN(), 8618 + }, 8619 + .result = REJECT, 8620 + .errstr = "R0 tried to subtract pointer from scalar", 8621 + }, 8622 + { 8623 + "check deducing bounds from const, 2", 8624 + .insns = { 8625 + BPF_MOV64_IMM(BPF_REG_0, 1), 8626 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 1, 1), 8627 + BPF_EXIT_INSN(), 8628 + BPF_JMP_IMM(BPF_JSLE, BPF_REG_0, 1, 1), 8629 + BPF_EXIT_INSN(), 8630 + BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0), 8631 + BPF_EXIT_INSN(), 8632 + }, 8633 + .result = ACCEPT, 8634 + }, 8635 + { 8636 + "check deducing bounds from const, 3", 8637 + .insns = { 8638 + BPF_MOV64_IMM(BPF_REG_0, 0), 8639 + BPF_JMP_IMM(BPF_JSLE, BPF_REG_0, 0, 0), 8640 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8641 + BPF_EXIT_INSN(), 8642 + }, 8643 + .result = REJECT, 8644 + .errstr = "R0 tried to subtract pointer from scalar", 8645 + }, 8646 + { 8647 + "check deducing bounds from const, 4", 8648 + .insns = { 8649 + BPF_MOV64_IMM(BPF_REG_0, 0), 8650 + BPF_JMP_IMM(BPF_JSLE, BPF_REG_0, 0, 1), 8651 + BPF_EXIT_INSN(), 8652 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1), 8653 + BPF_EXIT_INSN(), 8654 + BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0), 8655 + BPF_EXIT_INSN(), 8656 + }, 8657 + .result = ACCEPT, 8658 + }, 8659 + { 8660 + "check deducing bounds from const, 5", 8661 + .insns = { 8662 + BPF_MOV64_IMM(BPF_REG_0, 0), 8663 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1), 8664 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8665 + BPF_EXIT_INSN(), 8666 + }, 8667 + .result = REJECT, 8668 + .errstr = "R0 tried to subtract pointer from scalar", 8669 + }, 8670 + { 8671 + "check deducing bounds from const, 6", 8672 + .insns = { 8673 + BPF_MOV64_IMM(BPF_REG_0, 0), 8674 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1), 8675 + BPF_EXIT_INSN(), 8676 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8677 + BPF_EXIT_INSN(), 8678 + }, 8679 + .result = REJECT, 8680 + .errstr = "R0 tried to subtract pointer from scalar", 8681 + }, 8682 + { 8683 + "check deducing bounds from const, 7", 8684 + .insns = { 8685 + BPF_MOV64_IMM(BPF_REG_0, ~0), 8686 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 0), 8687 + BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0), 8688 + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 8689 + offsetof(struct __sk_buff, mark)), 8690 + BPF_EXIT_INSN(), 8691 + }, 8692 + .result = REJECT, 8693 + .errstr = "dereference of modified ctx ptr", 8694 + }, 8695 + { 8696 + "check deducing bounds from const, 8", 8697 + .insns = { 8698 + BPF_MOV64_IMM(BPF_REG_0, ~0), 8699 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 1), 8700 + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0), 8701 + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 8702 + offsetof(struct __sk_buff, mark)), 8703 + BPF_EXIT_INSN(), 8704 + }, 8705 + .result = REJECT, 8706 + .errstr = "dereference of modified ctx ptr", 8707 + }, 8708 + { 8709 + "check deducing bounds from const, 9", 8710 + .insns = { 8711 + BPF_MOV64_IMM(BPF_REG_0, 0), 8712 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_0, 0, 0), 8713 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8714 + BPF_EXIT_INSN(), 8715 + }, 8716 + .result = REJECT, 8717 + .errstr = "R0 tried to subtract pointer from scalar", 8718 + }, 8719 + { 8720 + "check deducing bounds from const, 10", 8721 + .insns = { 8722 + BPF_MOV64_IMM(BPF_REG_0, 0), 8723 + BPF_JMP_IMM(BPF_JSLE, BPF_REG_0, 0, 0), 8724 + /* Marks reg as unknown. */ 8725 + BPF_ALU64_IMM(BPF_NEG, BPF_REG_0, 0), 8726 + BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1), 8727 + BPF_EXIT_INSN(), 8728 + }, 8729 + .result = REJECT, 8730 + .errstr = "math between ctx pointer and register with unbounded min value is not allowed", 8635 8731 }, 8636 8732 { 8637 8733 "bpf_exit with invalid return code. test1",