diff options
| author | Daniel Borkmann <daniel@iogearbox.net> | 2018-12-20 17:28:29 +0100 |
|---|---|---|
| committer | Daniel Borkmann <daniel@iogearbox.net> | 2018-12-20 17:28:30 +0100 |
| commit | d70f4ece9da12b7319a87d02d33a89353268c689 (patch) | |
| tree | c3841eb8de8ce0313010b5d003b41d25383d48f6 /kernel | |
| parent | 9df95e8ec568f98d89fe2c72342714296ac6ce27 (diff) | |
| parent | 489c066cfdf1cad776c5e041f32a2e3cdb05050a (diff) | |
Merge branch 'bpf-jset-verifier'
Jakub Kicinski says:
====================
This is a v2 of the patch set to teach the verifier about BPF_JSET
instruction. There is also a number of tests include for both
basic functioning of the instruction and the verifier logic.
The NFP JIT handling of JSET is tweaked. Last patch adds missing
file to gitignore.
Reposting part of previous series without the dead code elimination.
====================
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/verifier.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5c64281d566e..d27d5a880015 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3859,6 +3859,12 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) if (tnum_is_const(reg->var_off)) return !tnum_equals_const(reg->var_off, val); break; + case BPF_JSET: + if ((~reg->var_off.mask & reg->var_off.value) & val) + return 1; + if (!((reg->var_off.mask | reg->var_off.value) & val)) + return 0; + break; case BPF_JGT: if (reg->umin_value > val) return 1; @@ -3943,6 +3949,13 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, */ __mark_reg_known(false_reg, val); break; + case BPF_JSET: + false_reg->var_off = tnum_and(false_reg->var_off, + tnum_const(~val)); + if (is_power_of_2(val)) + true_reg->var_off = tnum_or(true_reg->var_off, + tnum_const(val)); + break; case BPF_JGT: false_reg->umax_value = min(false_reg->umax_value, val); true_reg->umin_value = max(true_reg->umin_value, val + 1); @@ -4015,6 +4028,13 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, */ __mark_reg_known(false_reg, val); break; + case BPF_JSET: + false_reg->var_off = tnum_and(false_reg->var_off, + tnum_const(~val)); + if (is_power_of_2(val)) + true_reg->var_off = tnum_or(true_reg->var_off, + tnum_const(val)); + break; case BPF_JGT: true_reg->umax_value = min(true_reg->umax_value, val - 1); false_reg->umin_value = max(false_reg->umin_value, val); @@ -6963,10 +6983,11 @@ skip_full_check: free_states(env); if (ret == 0) - sanitize_dead_code(env); + ret = check_max_stack_depth(env); + /* instruction rewrites happen after this point */ if (ret == 0) - ret = check_max_stack_depth(env); + sanitize_dead_code(env); if (ret == 0) /* program is valid, convert *(u32*)(ctx + off) accesses */ |
