Commit 2edc3de6 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Andrii Nakryiko

bpf: Recognize btf_decl_tag("arg: Arena") as PTR_TO_ARENA.

In global bpf functions recognize btf_decl_tag("arg:arena") as PTR_TO_ARENA.

Note, when the verifier sees:

__weak void foo(struct bar *p)

it recognizes 'p' as PTR_TO_MEM and 'struct bar' has to be a struct with scalars.
Hence the only way to use arena pointers in global functions is to tag them with "arg:arena".
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/bpf/20240308010812.89848-7-alexei.starovoitov@gmail.com
parent 6082b6c3
...@@ -712,6 +712,7 @@ enum bpf_arg_type { ...@@ -712,6 +712,7 @@ enum bpf_arg_type {
* on eBPF program stack * on eBPF program stack
*/ */
ARG_PTR_TO_MEM, /* pointer to valid memory (stack, packet, map value) */ ARG_PTR_TO_MEM, /* pointer to valid memory (stack, packet, map value) */
ARG_PTR_TO_ARENA,
ARG_CONST_SIZE, /* number of bytes accessed from memory */ ARG_CONST_SIZE, /* number of bytes accessed from memory */
ARG_CONST_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */ ARG_CONST_SIZE_OR_ZERO, /* number of bytes accessed from memory or 0 */
......
...@@ -7111,10 +7111,11 @@ static int btf_get_ptr_to_btf_id(struct bpf_verifier_log *log, int arg_idx, ...@@ -7111,10 +7111,11 @@ static int btf_get_ptr_to_btf_id(struct bpf_verifier_log *log, int arg_idx,
} }
enum btf_arg_tag { enum btf_arg_tag {
ARG_TAG_CTX = 0x1, ARG_TAG_CTX = BIT_ULL(0),
ARG_TAG_NONNULL = 0x2, ARG_TAG_NONNULL = BIT_ULL(1),
ARG_TAG_TRUSTED = 0x4, ARG_TAG_TRUSTED = BIT_ULL(2),
ARG_TAG_NULLABLE = 0x8, ARG_TAG_NULLABLE = BIT_ULL(3),
ARG_TAG_ARENA = BIT_ULL(4),
}; };
/* Process BTF of a function to produce high-level expectation of function /* Process BTF of a function to produce high-level expectation of function
...@@ -7226,6 +7227,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) ...@@ -7226,6 +7227,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
tags |= ARG_TAG_NONNULL; tags |= ARG_TAG_NONNULL;
} else if (strcmp(tag, "nullable") == 0) { } else if (strcmp(tag, "nullable") == 0) {
tags |= ARG_TAG_NULLABLE; tags |= ARG_TAG_NULLABLE;
} else if (strcmp(tag, "arena") == 0) {
tags |= ARG_TAG_ARENA;
} else { } else {
bpf_log(log, "arg#%d has unsupported set of tags\n", i); bpf_log(log, "arg#%d has unsupported set of tags\n", i);
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -7280,6 +7283,14 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) ...@@ -7280,6 +7283,14 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
sub->args[i].btf_id = kern_type_id; sub->args[i].btf_id = kern_type_id;
continue; continue;
} }
if (tags & ARG_TAG_ARENA) {
if (tags & ~ARG_TAG_ARENA) {
bpf_log(log, "arg#%d arena cannot be combined with any other tags\n", i);
return -EINVAL;
}
sub->args[i].arg_type = ARG_PTR_TO_ARENA;
continue;
}
if (is_global) { /* generic user data pointer */ if (is_global) { /* generic user data pointer */
u32 mem_size; u32 mem_size;
......
...@@ -9379,6 +9379,18 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog, ...@@ -9379,6 +9379,18 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
bpf_log(log, "arg#%d is expected to be non-NULL\n", i); bpf_log(log, "arg#%d is expected to be non-NULL\n", i);
return -EINVAL; return -EINVAL;
} }
} else if (base_type(arg->arg_type) == ARG_PTR_TO_ARENA) {
/*
* Can pass any value and the kernel won't crash, but
* only PTR_TO_ARENA or SCALAR make sense. Everything
* else is a bug in the bpf program. Point it out to
* the user at the verification time instead of
* run-time debug nightmare.
*/
if (reg->type != PTR_TO_ARENA && reg->type != SCALAR_VALUE) {
bpf_log(log, "R%d is not a pointer to arena or scalar.\n", regno);
return -EINVAL;
}
} else if (arg->arg_type == (ARG_PTR_TO_DYNPTR | MEM_RDONLY)) { } else if (arg->arg_type == (ARG_PTR_TO_DYNPTR | MEM_RDONLY)) {
ret = process_dynptr_func(env, regno, -1, arg->arg_type, 0); ret = process_dynptr_func(env, regno, -1, arg->arg_type, 0);
if (ret) if (ret)
...@@ -20448,6 +20460,9 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) ...@@ -20448,6 +20460,9 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
reg->btf = bpf_get_btf_vmlinux(); /* can't fail at this point */ reg->btf = bpf_get_btf_vmlinux(); /* can't fail at this point */
reg->btf_id = arg->btf_id; reg->btf_id = arg->btf_id;
reg->id = ++env->id_gen; reg->id = ++env->id_gen;
} else if (base_type(arg->arg_type) == ARG_PTR_TO_ARENA) {
/* caller can pass either PTR_TO_ARENA or SCALAR */
mark_reg_unknown(env, regs, i);
} else { } else {
WARN_ONCE(1, "BUG: unhandled arg#%d type %d\n", WARN_ONCE(1, "BUG: unhandled arg#%d type %d\n",
i - BPF_REG_1, arg->arg_type); i - BPF_REG_1, arg->arg_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment