aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2018-10-31 19:05:52 -0400
committerAlexei Starovoitov <ast@kernel.org>2018-10-31 19:53:17 -0400
commit0962590e553331db2cc0aef2dc35c57f6300dbbe (patch)
tree8b206dfaa37c6d4efb244768dcdd25893a27902d /kernel/bpf
parent3615353218744bb60f55170c620ce4dce1a008c7 (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.c10
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: