mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
bpf: Unify const map ptr argument checking for helpers and kfuncs
Both the helper ARG_CONST_MAP_PTR and the kfunc KF_ARG_PTR_TO_MAP recorded the map pointer in meta->map and, when a map was already bound by a preceding timer/workqueue/task_work argument, rejected a mismatching map. Factor the logic into a single process_map_ptr_arg() used by both paths. The bound-object name (timer, workqueue, or bpf_task_work) is derived from the bound map's btf_record, and the register numbers in the message are computed from the map argument position instead of being hard-coded. Signed-off-by: Amery Hung <ameryhung@gmail.com> Reviewed-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/bpf/20260801074633.1595644-3-ameryhung@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
parent
70a841617a
commit
b33d09b4d9
|
|
@ -8274,6 +8274,44 @@ static int get_constant_map_key(struct bpf_verifier_env *env,
|
|||
|
||||
static bool can_elide_value_nullness(const struct bpf_map *map);
|
||||
|
||||
static int process_map_ptr_arg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
|
||||
argno_t argno, struct bpf_call_arg_meta *meta)
|
||||
{
|
||||
/* 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);
|
||||
* }
|
||||
*
|
||||
* Comparing map_ptr is enough to distinguish normal and outer maps.
|
||||
*/
|
||||
if (meta->map.ptr &&
|
||||
(meta->map.ptr != reg->map_ptr || meta->map.uid != reg->map_uid)) {
|
||||
argno_t obj_argno = argno_from_reg(reg_from_argno(argno) - 1);
|
||||
struct btf_record *rec = meta->map.ptr->record;
|
||||
const char *obj_name = "workqueue";
|
||||
|
||||
if (rec->timer_off >= 0)
|
||||
obj_name = "timer";
|
||||
else if (rec->task_work_off >= 0)
|
||||
obj_name = "bpf_task_work";
|
||||
|
||||
verbose(env, "%s pointer in %s map_uid=%d ",
|
||||
obj_name, reg_arg_name(env, obj_argno), meta->map.uid);
|
||||
verbose(env, "doesn't match map pointer in %s map_uid=%d\n",
|
||||
reg_arg_name(env, argno), reg->map_uid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
meta->map.ptr = reg->map_ptr;
|
||||
meta->map.uid = reg->map_uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
|
||||
struct bpf_call_arg_meta *meta,
|
||||
const struct bpf_func_proto *fn,
|
||||
|
|
@ -8349,29 +8387,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
|
|||
switch (base_type(arg_type)) {
|
||||
case ARG_CONST_MAP_PTR:
|
||||
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
|
||||
if (meta->map.ptr) {
|
||||
/* 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);
|
||||
* }
|
||||
*
|
||||
* Comparing map_ptr is enough to distinguish normal and outer maps.
|
||||
*/
|
||||
if (meta->map.ptr != reg->map_ptr ||
|
||||
meta->map.uid != reg->map_uid) {
|
||||
verbose(env,
|
||||
"timer pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n",
|
||||
meta->map.uid, reg->map_uid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
meta->map.ptr = reg->map_ptr;
|
||||
meta->map.uid = reg->map_uid;
|
||||
err = process_map_ptr_arg(env, reg, argno, meta);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case ARG_PTR_TO_MAP_KEY:
|
||||
/* bpf_map_xxx(..., map_ptr, ..., key) call:
|
||||
|
|
@ -12123,36 +12141,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
reg_arg_name(env, argno));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (meta->map.ptr && (reg->map_ptr->record->wq_off >= 0 ||
|
||||
reg->map_ptr->record->task_work_off >= 0)) {
|
||||
/* 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) {
|
||||
* wq = bpf_map_lookup_elem(inner_map1);
|
||||
* if (wq)
|
||||
* // mismatch would have been allowed
|
||||
* bpf_wq_init(wq, inner_map2);
|
||||
* }
|
||||
*
|
||||
* Comparing map_ptr is enough to distinguish normal and outer maps.
|
||||
*/
|
||||
if (meta->map.ptr != reg->map_ptr ||
|
||||
meta->map.uid != reg->map_uid) {
|
||||
if (reg->map_ptr->record->task_work_off >= 0) {
|
||||
verbose(env,
|
||||
"bpf_task_work pointer in R2 map_uid=%d doesn't match map pointer in R3 map_uid=%d\n",
|
||||
meta->map.uid, reg->map_uid);
|
||||
return -EINVAL;
|
||||
}
|
||||
verbose(env,
|
||||
"workqueue pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n",
|
||||
meta->map.uid, reg->map_uid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
meta->map.ptr = reg->map_ptr;
|
||||
meta->map.uid = reg->map_uid;
|
||||
ret = process_map_ptr_arg(env, reg, argno, meta);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fallthrough;
|
||||
case KF_ARG_PTR_TO_ALLOC_BTF_ID:
|
||||
case KF_ARG_PTR_TO_BTF_ID:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user