Skip to content

Commit 3e8ce29

Browse files
Alexei Starovoitovborkmann
authored andcommitted
bpf: Prevent pointer mismatch in bpf_timer_init.
bpf_timer_init() arguments are: 1. pointer to a timer (which is embedded in map element). 2. pointer to a map. Make sure that pointer to a timer actually belongs to that map. Use map_uid (which is unique id of inner map) to reject: inner_map1 = bpf_map_lookup_elem(outer_map, key1) inner_map2 = bpf_map_lookup_elem(outer_map, key2) if (inner_map1 && inner_map2) { timer = bpf_map_lookup_elem(inner_map1); if (timer) // mismatch would have been allowed bpf_timer_init(timer, inner_map2); } Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Acked-by: Toke Høiland-Jørgensen <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 6813466 commit 3e8ce29

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

include/linux/bpf_verifier.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,14 @@ struct bpf_reg_state {
5353
/* valid when type == CONST_PTR_TO_MAP | PTR_TO_MAP_VALUE |
5454
* PTR_TO_MAP_VALUE_OR_NULL
5555
*/
56-
struct bpf_map *map_ptr;
56+
struct {
57+
struct bpf_map *map_ptr;
58+
/* To distinguish map lookups from outer map
59+
* the map_uid is non-zero for registers
60+
* pointing to inner maps.
61+
*/
62+
u32 map_uid;
63+
};
5764

5865
/* for PTR_TO_BTF_ID */
5966
struct {

kernel/bpf/verifier.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ struct bpf_call_arg_meta {
255255
int mem_size;
256256
u64 msize_max_value;
257257
int ref_obj_id;
258+
int map_uid;
258259
int func_id;
259260
struct btf *btf;
260261
u32 btf_id;
@@ -1135,6 +1136,10 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg)
11351136
if (map->inner_map_meta) {
11361137
reg->type = CONST_PTR_TO_MAP;
11371138
reg->map_ptr = map->inner_map_meta;
1139+
/* transfer reg's id which is unique for every map_lookup_elem
1140+
* as UID of the inner map.
1141+
*/
1142+
reg->map_uid = reg->id;
11381143
} else if (map->map_type == BPF_MAP_TYPE_XSKMAP) {
11391144
reg->type = PTR_TO_XDP_SOCK;
11401145
} else if (map->map_type == BPF_MAP_TYPE_SOCKMAP ||
@@ -4708,6 +4713,7 @@ static int process_timer_func(struct bpf_verifier_env *env, int regno,
47084713
verbose(env, "verifier bug. Two map pointers in a timer helper\n");
47094714
return -EFAULT;
47104715
}
4716+
meta->map_uid = reg->map_uid;
47114717
meta->map_ptr = map;
47124718
return 0;
47134719
}
@@ -5006,11 +5012,29 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
50065012

50075013
if (arg_type == ARG_CONST_MAP_PTR) {
50085014
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
5009-
if (meta->map_ptr && meta->map_ptr != reg->map_ptr) {
5010-
verbose(env, "Map pointer doesn't match bpf_timer.\n");
5011-
return -EINVAL;
5015+
if (meta->map_ptr) {
5016+
/* Use map_uid (which is unique id of inner map) to reject:
5017+
* inner_map1 = bpf_map_lookup_elem(outer_map, key1)
5018+
* inner_map2 = bpf_map_lookup_elem(outer_map, key2)
5019+
* if (inner_map1 && inner_map2) {
5020+
* timer = bpf_map_lookup_elem(inner_map1);
5021+
* if (timer)
5022+
* // mismatch would have been allowed
5023+
* bpf_timer_init(timer, inner_map2);
5024+
* }
5025+
*
5026+
* Comparing map_ptr is enough to distinguish normal and outer maps.
5027+
*/
5028+
if (meta->map_ptr != reg->map_ptr ||
5029+
meta->map_uid != reg->map_uid) {
5030+
verbose(env,
5031+
"timer pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n",
5032+
meta->map_uid, reg->map_uid);
5033+
return -EINVAL;
5034+
}
50125035
}
50135036
meta->map_ptr = reg->map_ptr;
5037+
meta->map_uid = reg->map_uid;
50145038
} else if (arg_type == ARG_PTR_TO_MAP_KEY) {
50155039
/* bpf_map_xxx(..., map_ptr, ..., key) call:
50165040
* check that [key, key + map->key_size) are within
@@ -6204,6 +6228,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
62046228
return -EINVAL;
62056229
}
62066230
regs[BPF_REG_0].map_ptr = meta.map_ptr;
6231+
regs[BPF_REG_0].map_uid = meta.map_uid;
62076232
if (fn->ret_type == RET_PTR_TO_MAP_VALUE) {
62086233
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE;
62096234
if (map_value_has_spin_lock(meta.map_ptr))

0 commit comments

Comments
 (0)