History

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.

Daniel Borkmann committed 8 years ago

Commit 09625901 parent 36153532 files · +9 −4Browse files

Unified · Split

2 files
  1. include/linux/bpf_verifier.h +3 −0
  2. kernel/bpf/verifier.c +6 −4
include/linux/bpf_verifier.h+3−0
@@ -51,6 +51,9 @@ struct bpf_reg_state { · 50 unmodified lines
5151 * PTR_TO_MAP_VALUE_OR_NULL
5252 */
5353 struct bpf_map *map_ptr;
54+
55+ /* Max size from any of the above. */
56+ unsigned long raw;
5457 };
5558 /* Fixed part of pointer offset, pointer types only */
5659 s32 off;
kernel/bpf/verifier.c+6−4
@@ -3046,7 +3046,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 3045 unmodified lines
30463046 dst_reg->umax_value = umax_ptr;
30473047 dst_reg->var_off = ptr_reg->var_off;
30483048 dst_reg->off = ptr_reg->off + smin_val;
3049− dst_reg->range = ptr_reg->range;
3049+ dst_reg->raw = ptr_reg->raw;
30503050 break;
30513051 }
30523052 /* 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, · 23 unmodified lines
30763076 }
30773077 dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
30783078 dst_reg->off = ptr_reg->off;
3079+ dst_reg->raw = ptr_reg->raw;
30793080 if (reg_is_pkt_pointer(ptr_reg)) {
30803081 dst_reg->id = ++env->id_gen;
30813082 /* something was added to pkt_ptr, set range to zero */
3082− dst_reg->range = 0;
3083+ dst_reg->raw = 0;
30833084 }
30843085 break;
30853086 case BPF_SUB:
@@ -3108,7 +3109,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 22 unmodified lines
31083109 dst_reg->var_off = ptr_reg->var_off;
31093110 dst_reg->id = ptr_reg->id;
31103111 dst_reg->off = ptr_reg->off - smin_val;
3111− dst_reg->range = ptr_reg->range;
3112+ dst_reg->raw = ptr_reg->raw;
31123113 break;
31133114 }
31143115 /* 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, · 19 unmodified lines
31343135 }
31353136 dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
31363137 dst_reg->off = ptr_reg->off;
3138+ dst_reg->raw = ptr_reg->raw;
31373139 if (reg_is_pkt_pointer(ptr_reg)) {
31383140 dst_reg->id = ++env->id_gen;
31393141 /* something was added to pkt_ptr, set range to zero */
31403142 if (smin_val < 0)
3141− dst_reg->range = 0;
3143+ dst_reg->raw = 0;
31423144 }
31433145 break;
31443146 case BPF_AND:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t