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
51 * PTR_TO_MAP_VALUE_OR_NULL51 * PTR_TO_MAP_VALUE_OR_NULL
52 */52 */
53 struct bpf_map *map_ptr;53 struct bpf_map *map_ptr;
54
55 /* Max size from any of the above. */
56 unsigned long raw;
54 };57 };
55 /* Fixed part of pointer offset, pointer types only */58 /* Fixed part of pointer offset, pointer types only */
56 s32 off;59 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
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->off3052 /* 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
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, · 22 unmodified lines
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 known3115 /* 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
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:

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