forked from Minki/linux
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: f1174f77b5
("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>
This commit is contained in:
parent
3615353218
commit
0962590e55
@ -51,6 +51,9 @@ struct bpf_reg_state {
|
||||
* PTR_TO_MAP_VALUE_OR_NULL
|
||||
*/
|
||||
struct bpf_map *map_ptr;
|
||||
|
||||
/* Max size from any of the above. */
|
||||
unsigned long raw;
|
||||
};
|
||||
/* Fixed part of pointer offset, pointer types only */
|
||||
s32 off;
|
||||
|
@ -3046,7 +3046,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
dst_reg->umax_value = umax_ptr;
|
||||
dst_reg->var_off = ptr_reg->var_off;
|
||||
dst_reg->off = ptr_reg->off + smin_val;
|
||||
dst_reg->range = ptr_reg->range;
|
||||
dst_reg->raw = ptr_reg->raw;
|
||||
break;
|
||||
}
|
||||
/* 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,
|
||||
}
|
||||
dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
|
||||
dst_reg->off = ptr_reg->off;
|
||||
dst_reg->raw = ptr_reg->raw;
|
||||
if (reg_is_pkt_pointer(ptr_reg)) {
|
||||
dst_reg->id = ++env->id_gen;
|
||||
/* something was added to pkt_ptr, set range to zero */
|
||||
dst_reg->range = 0;
|
||||
dst_reg->raw = 0;
|
||||
}
|
||||
break;
|
||||
case BPF_SUB:
|
||||
@ -3108,7 +3109,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
dst_reg->var_off = ptr_reg->var_off;
|
||||
dst_reg->id = ptr_reg->id;
|
||||
dst_reg->off = ptr_reg->off - smin_val;
|
||||
dst_reg->range = ptr_reg->range;
|
||||
dst_reg->raw = ptr_reg->raw;
|
||||
break;
|
||||
}
|
||||
/* 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,
|
||||
}
|
||||
dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
|
||||
dst_reg->off = ptr_reg->off;
|
||||
dst_reg->raw = ptr_reg->raw;
|
||||
if (reg_is_pkt_pointer(ptr_reg)) {
|
||||
dst_reg->id = ++env->id_gen;
|
||||
/* something was added to pkt_ptr, set range to zero */
|
||||
if (smin_val < 0)
|
||||
dst_reg->range = 0;
|
||||
dst_reg->raw = 0;
|
||||
}
|
||||
break;
|
||||
case BPF_AND:
|
||||
|
Loading…
Reference in New Issue
Block a user