History

bpf: use check_ids() for active_lock comparison

An update for verifier.c:states_equal()/regsafe() to use check_ids() for active spin lock comparisons. This fixes the issue reported by Kumar Kartikeya Dwivedi in [1] using technique suggested by Edward Cree. W/o this commit the verifier might be tricked to accept the following program working with a map containing spin locks: 0: r9 = map_lookup_elem(...) ; Returns PTR_TO_MAP_VALUE_OR_NULL id=1. 1: r8 = map_lookup_elem(...) ; Returns PTR_TO_MAP_VALUE_OR_NULL id=2. 2: if r9 == 0 goto exit ; r9 -> PTR_TO_MAP_VALUE. 3: if r8 == 0 goto exit ; r8 -> PTR_TO_MAP_VALUE. 4: r7 = ktime_get_ns() ; Unbound SCALAR_VALUE. 5: r6 = ktime_get_ns() ; Unbound SCALAR_VALUE. 6: bpf_spin_lock(r8) ; active_lock.id == 2. 7: if r6 > r7 goto +1 ; No new information about the state ; is derived from this check, thus ; produced verifier states differ only ; in 'insn_idx'. 8: r9 = r8 ; Optionally make r9.id == r8.id. --- checkpoint --- ; Assume is_state_visisted() creates a ; checkpoint here. 9: bpf_spin_unlock(r9) ; (a,b) active_lock.id == 2. ; (a) r9.id == 2, (b) r9.id == 1. 10: exit(0) Consider two verification paths: (a) 0-10 (b) 0-7,9-10 The path (a) is verified first. If checkpoint is created at (8) the (b) would assume that (8) is safe because regsafe() does not compare register ids for registers of type PTR_TO_MAP_VALUE. [1] https://lore.kernel.org/bpf/20221111202719.982118-1-memxor@gmail.com/

Eduard Zingerman committed 3 years ago

Commit 4ea2bb11 parent 7d057941 file · +13 −3Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/bpf/verifier.c+13−3
@@ -13119,7 +13119,8 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, · 13118 unmodified lines
1311913119 */
1312013120 return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 &&
1312113121 range_within(rold, rcur) &&
13122− tnum_in(rold->var_off, rcur->var_off);
13122+ tnum_in(rold->var_off, rcur->var_off) &&
13123+ check_ids(rold->id, rcur->id, idmap);
1312313124 case PTR_TO_PACKET_META:
1312413125 case PTR_TO_PACKET:
1312513126 if (rcur->type != rold->type)
@@ -13291,8 +13292,17 @@ static bool states_equal(struct bpf_verifier_env *env, · 165 unmodified lines
1329113292 if (old->speculative && !cur->speculative)
1329213293 return false;
1329313294
13294− if (old->active_lock.ptr != cur->active_lock.ptr ||
13295− old->active_lock.id != cur->active_lock.id)
13295+ if (old->active_lock.ptr != cur->active_lock.ptr)
13296+ return false;
13297+
13298+ /* Old and cur active_lock's have to be either both present
13299+ * or both absent.
13300+ */
13301+ if (!!old->active_lock.id != !!cur->active_lock.id)
13302+ return false;
13303+
13304+ if (old->active_lock.id &&
13305+ !check_ids(old->active_lock.id, cur->active_lock.id, env->idmap_scratch))
1329613306 return false;
1329713307
1329813308 if (old->active_rcu_lock != cur->active_rcu_lock)