mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 07:31:45 +00:00
bpf: Introduce allocated objects support
Introduce support for representing pointers to objects allocated by the BPF program, i.e. PTR_TO_BTF_ID that point to a type in program BTF. This is indicated by the presence of MEM_ALLOC type flag in reg->type to avoid having to check btf_is_kernel when trying to match argument types in helpers. Whenever walking such types, any pointers being walked will always yield a SCALAR instead of pointer. In the future we might permit kptr inside such allocated objects (either kernel or program allocated), and it will then form a PTR_TO_BTF_ID of the respective type. For now, such allocated objects will always be referenced in verifier context, hence ref_obj_id == 0 for them is a bug. It is allowed to write to such objects, as long fields that are special are not touched (support for which will be added in subsequent patches). Note that once such a pointer is marked PTR_UNTRUSTED, it is no longer allowed to write to it. No PROBE_MEM handling is therefore done for loads into this type unless PTR_UNTRUSTED is part of the register type, since they can never be in an undefined state, and their lifetime will always be valid. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20221118015614.2013203-6-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
f73e601aaf
commit
282de143ea
@ -525,6 +525,11 @@ enum bpf_type_flag {
|
||||
/* Size is known at compile time. */
|
||||
MEM_FIXED_SIZE = BIT(10 + BPF_BASE_TYPE_BITS),
|
||||
|
||||
/* MEM is of an allocated object of type in program BTF. This is used to
|
||||
* tag PTR_TO_BTF_ID allocated using bpf_obj_new.
|
||||
*/
|
||||
MEM_ALLOC = BIT(11 + BPF_BASE_TYPE_BITS),
|
||||
|
||||
__BPF_TYPE_FLAG_MAX,
|
||||
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
|
||||
};
|
||||
@ -2792,4 +2797,10 @@ struct bpf_key {
|
||||
bool has_ref;
|
||||
};
|
||||
#endif /* CONFIG_KEYS */
|
||||
|
||||
static inline bool type_is_alloc(u32 type)
|
||||
{
|
||||
return type & MEM_ALLOC;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_BPF_H */
|
||||
|
@ -6034,6 +6034,11 @@ int btf_struct_access(struct bpf_verifier_log *log,
|
||||
|
||||
switch (err) {
|
||||
case WALK_PTR:
|
||||
/* For local types, the destination register cannot
|
||||
* become a pointer again.
|
||||
*/
|
||||
if (type_is_alloc(reg->type))
|
||||
return SCALAR_VALUE;
|
||||
/* If we found the pointer or scalar on t+off,
|
||||
* we're done.
|
||||
*/
|
||||
|
@ -4687,14 +4687,27 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (env->ops->btf_struct_access) {
|
||||
if (env->ops->btf_struct_access && !type_is_alloc(reg->type)) {
|
||||
if (!btf_is_kernel(reg->btf)) {
|
||||
verbose(env, "verifier internal error: reg->btf must be kernel btf\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
ret = env->ops->btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
|
||||
} else {
|
||||
if (atype != BPF_READ) {
|
||||
/* Writes are permitted with default btf_struct_access for
|
||||
* program allocated objects (which always have ref_obj_id > 0),
|
||||
* but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC.
|
||||
*/
|
||||
if (atype != BPF_READ && reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
|
||||
verbose(env, "only read is supported\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (type_is_alloc(reg->type) && !reg->ref_obj_id) {
|
||||
verbose(env, "verifier internal error: ref_obj_id for allocated object must be non-zero\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
|
||||
}
|
||||
|
||||
@ -5973,6 +5986,7 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env,
|
||||
* fixed offset.
|
||||
*/
|
||||
case PTR_TO_BTF_ID:
|
||||
case PTR_TO_BTF_ID | MEM_ALLOC:
|
||||
/* When referenced PTR_TO_BTF_ID is passed to release function,
|
||||
* it's fixed offset must be 0. In the other cases, fixed offset
|
||||
* can be non-zero.
|
||||
@ -13690,6 +13704,13 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
|
||||
break;
|
||||
case PTR_TO_BTF_ID:
|
||||
case PTR_TO_BTF_ID | PTR_UNTRUSTED:
|
||||
/* PTR_TO_BTF_ID | MEM_ALLOC always has a valid lifetime, unlike
|
||||
* PTR_TO_BTF_ID, and an active ref_obj_id, but the same cannot
|
||||
* be said once it is marked PTR_UNTRUSTED, hence we must handle
|
||||
* any faults for loads into such types. BPF_WRITE is disallowed
|
||||
* for this case.
|
||||
*/
|
||||
case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED:
|
||||
if (type == BPF_READ) {
|
||||
insn->code = BPF_LDX | BPF_PROBE_MEM |
|
||||
BPF_SIZE((insn)->code);
|
||||
|
Loading…
Reference in New Issue
Block a user