diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2018-10-31 19:05:52 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-10-31 19:53:17 -0400 |
commit | 0962590e553331db2cc0aef2dc35c57f6300dbbe (patch) | |
tree | 8b206dfaa37c6d4efb244768dcdd25893a27902d /kernel/bpf | |
parent | 3615353218744bb60f55170c620ce4dce1a008c7 (diff) |
bpf: fix partial copy of map_ptr when dst is scalar
ALU operations on pointers such as scalar_reg += map_value_ptr are
handled in adjust_ptr_min_max_vals(). Problem is however that map_ptr
and range in the register state share a union, so transferring state
through dst_reg->range = ptr_reg->range is just buggy as any new
map_ptr in the dst_reg is then truncated (or null) for subsequent
checks. Fix this by adding a raw member and use it for copying state
over to dst_reg.
Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Cc: Edward Cree <ecree@solarflare.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf')
-rw-r--r-- | kernel/bpf/verifier.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 171a2c88e77d..774fa40a32ae 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -3046,7 +3046,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
3046 | dst_reg->umax_value = umax_ptr; | 3046 | dst_reg->umax_value = umax_ptr; |
3047 | dst_reg->var_off = ptr_reg->var_off; | 3047 | dst_reg->var_off = ptr_reg->var_off; |
3048 | dst_reg->off = ptr_reg->off + smin_val; | 3048 | dst_reg->off = ptr_reg->off + smin_val; |
3049 | dst_reg->range = ptr_reg->range; | 3049 | dst_reg->raw = ptr_reg->raw; |
3050 | break; | 3050 | break; |
3051 | } | 3051 | } |
3052 | /* A new variable offset is created. Note that off_reg->off | 3052 | /* A new variable offset is created. Note that off_reg->off |
@@ -3076,10 +3076,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
3076 | } | 3076 | } |
3077 | dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off); | 3077 | dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off); |
3078 | dst_reg->off = ptr_reg->off; | 3078 | dst_reg->off = ptr_reg->off; |
3079 | dst_reg->raw = ptr_reg->raw; | ||
3079 | if (reg_is_pkt_pointer(ptr_reg)) { | 3080 | if (reg_is_pkt_pointer(ptr_reg)) { |
3080 | dst_reg->id = ++env->id_gen; | 3081 | dst_reg->id = ++env->id_gen; |
3081 | /* something was added to pkt_ptr, set range to zero */ | 3082 | /* something was added to pkt_ptr, set range to zero */ |
3082 | dst_reg->range = 0; | 3083 | dst_reg->raw = 0; |
3083 | } | 3084 | } |
3084 | break; | 3085 | break; |
3085 | case BPF_SUB: | 3086 | case BPF_SUB: |
@@ -3108,7 +3109,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
3108 | dst_reg->var_off = ptr_reg->var_off; | 3109 | dst_reg->var_off = ptr_reg->var_off; |
3109 | dst_reg->id = ptr_reg->id; | 3110 | dst_reg->id = ptr_reg->id; |
3110 | dst_reg->off = ptr_reg->off - smin_val; | 3111 | dst_reg->off = ptr_reg->off - smin_val; |
3111 | dst_reg->range = ptr_reg->range; | 3112 | dst_reg->raw = ptr_reg->raw; |
3112 | break; | 3113 | break; |
3113 | } | 3114 | } |
3114 | /* A new variable offset is created. If the subtrahend is known | 3115 | /* A new variable offset is created. If the subtrahend is known |
@@ -3134,11 +3135,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, | |||
3134 | } | 3135 | } |
3135 | dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off); | 3136 | dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off); |
3136 | dst_reg->off = ptr_reg->off; | 3137 | dst_reg->off = ptr_reg->off; |
3138 | dst_reg->raw = ptr_reg->raw; | ||
3137 | if (reg_is_pkt_pointer(ptr_reg)) { | 3139 | if (reg_is_pkt_pointer(ptr_reg)) { |
3138 | dst_reg->id = ++env->id_gen; | 3140 | dst_reg->id = ++env->id_gen; |
3139 | /* something was added to pkt_ptr, set range to zero */ | 3141 | /* something was added to pkt_ptr, set range to zero */ |
3140 | if (smin_val < 0) | 3142 | if (smin_val < 0) |
3141 | dst_reg->range = 0; | 3143 | dst_reg->raw = 0; |
3142 | } | 3144 | } |
3143 | break; | 3145 | break; |
3144 | case BPF_AND: | 3146 | case BPF_AND: |