diff options
| author | Daniel Borkmann <daniel@iogearbox.net> | 2017-05-24 19:05:06 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-05-25 13:44:27 -0400 |
| commit | a9789ef9afcb4fb0193f8dd94f2665ba3ad71e79 (patch) | |
| tree | f2709d8120df7b4368ca173096b7260625965021 /kernel | |
| parent | 1ad2f5838d345e1c102bd1cd27c4f4c1349b0dc8 (diff) | |
bpf: properly reset caller saved regs after helper call and ld_abs/ind
Currently, after performing helper calls, we clear all caller saved
registers, that is r0 - r5 and fill r0 depending on struct bpf_func_proto
specification. The way we reset these regs can affect pruning decisions
in later paths, since we only reset register's imm to 0 and type to
NOT_INIT. However, we leave out clearing of other variables such as id,
min_value, max_value, etc, which can later on lead to pruning mismatches
due to stale data.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e37e06b1229d..339c8a1371de 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -463,19 +463,22 @@ static const int caller_saved[CALLER_SAVED_REGS] = { | |||
| 463 | BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5 | 463 | BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5 |
| 464 | }; | 464 | }; |
| 465 | 465 | ||
| 466 | static void mark_reg_not_init(struct bpf_reg_state *regs, u32 regno) | ||
| 467 | { | ||
| 468 | BUG_ON(regno >= MAX_BPF_REG); | ||
| 469 | |||
| 470 | memset(®s[regno], 0, sizeof(regs[regno])); | ||
| 471 | regs[regno].type = NOT_INIT; | ||
| 472 | regs[regno].min_value = BPF_REGISTER_MIN_RANGE; | ||
| 473 | regs[regno].max_value = BPF_REGISTER_MAX_RANGE; | ||
| 474 | } | ||
| 475 | |||
| 466 | static void init_reg_state(struct bpf_reg_state *regs) | 476 | static void init_reg_state(struct bpf_reg_state *regs) |
| 467 | { | 477 | { |
| 468 | int i; | 478 | int i; |
| 469 | 479 | ||
| 470 | for (i = 0; i < MAX_BPF_REG; i++) { | 480 | for (i = 0; i < MAX_BPF_REG; i++) |
| 471 | regs[i].type = NOT_INIT; | 481 | mark_reg_not_init(regs, i); |
| 472 | regs[i].imm = 0; | ||
| 473 | regs[i].min_value = BPF_REGISTER_MIN_RANGE; | ||
| 474 | regs[i].max_value = BPF_REGISTER_MAX_RANGE; | ||
| 475 | regs[i].min_align = 0; | ||
| 476 | regs[i].aux_off = 0; | ||
| 477 | regs[i].aux_off_align = 0; | ||
| 478 | } | ||
| 479 | 482 | ||
| 480 | /* frame pointer */ | 483 | /* frame pointer */ |
| 481 | regs[BPF_REG_FP].type = FRAME_PTR; | 484 | regs[BPF_REG_FP].type = FRAME_PTR; |
| @@ -1346,7 +1349,6 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) | |||
| 1346 | struct bpf_verifier_state *state = &env->cur_state; | 1349 | struct bpf_verifier_state *state = &env->cur_state; |
| 1347 | const struct bpf_func_proto *fn = NULL; | 1350 | const struct bpf_func_proto *fn = NULL; |
| 1348 | struct bpf_reg_state *regs = state->regs; | 1351 | struct bpf_reg_state *regs = state->regs; |
| 1349 | struct bpf_reg_state *reg; | ||
| 1350 | struct bpf_call_arg_meta meta; | 1352 | struct bpf_call_arg_meta meta; |
| 1351 | bool changes_data; | 1353 | bool changes_data; |
| 1352 | int i, err; | 1354 | int i, err; |
| @@ -1413,11 +1415,8 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) | |||
| 1413 | } | 1415 | } |
| 1414 | 1416 | ||
| 1415 | /* reset caller saved regs */ | 1417 | /* reset caller saved regs */ |
| 1416 | for (i = 0; i < CALLER_SAVED_REGS; i++) { | 1418 | for (i = 0; i < CALLER_SAVED_REGS; i++) |
| 1417 | reg = regs + caller_saved[i]; | 1419 | mark_reg_not_init(regs, caller_saved[i]); |
| 1418 | reg->type = NOT_INIT; | ||
| 1419 | reg->imm = 0; | ||
| 1420 | } | ||
| 1421 | 1420 | ||
| 1422 | /* update return register */ | 1421 | /* update return register */ |
| 1423 | if (fn->ret_type == RET_INTEGER) { | 1422 | if (fn->ret_type == RET_INTEGER) { |
| @@ -2445,7 +2444,6 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
| 2445 | { | 2444 | { |
| 2446 | struct bpf_reg_state *regs = env->cur_state.regs; | 2445 | struct bpf_reg_state *regs = env->cur_state.regs; |
| 2447 | u8 mode = BPF_MODE(insn->code); | 2446 | u8 mode = BPF_MODE(insn->code); |
| 2448 | struct bpf_reg_state *reg; | ||
| 2449 | int i, err; | 2447 | int i, err; |
| 2450 | 2448 | ||
| 2451 | if (!may_access_skb(env->prog->type)) { | 2449 | if (!may_access_skb(env->prog->type)) { |
| @@ -2478,11 +2476,8 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) | |||
| 2478 | } | 2476 | } |
| 2479 | 2477 | ||
| 2480 | /* reset caller saved regs to unreadable */ | 2478 | /* reset caller saved regs to unreadable */ |
| 2481 | for (i = 0; i < CALLER_SAVED_REGS; i++) { | 2479 | for (i = 0; i < CALLER_SAVED_REGS; i++) |
| 2482 | reg = regs + caller_saved[i]; | 2480 | mark_reg_not_init(regs, caller_saved[i]); |
| 2483 | reg->type = NOT_INIT; | ||
| 2484 | reg->imm = 0; | ||
| 2485 | } | ||
| 2486 | 2481 | ||
| 2487 | /* mark destination R0 register as readable, since it contains | 2482 | /* mark destination R0 register as readable, since it contains |
| 2488 | * the value fetched from the packet | 2483 | * the value fetched from the packet |
