summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2024-02-03 05:08:59 +0300
committerAlexei Starovoitov <ast@kernel.org>2024-02-03 05:09:06 +0300
commit2a79690eae953daaac232f93e6c5ac47ac539f2d (patch)
tree0e4d601040f137b0bc160f6757cff8577ae15fe4
parenta68b50f47bec8bd6a33b07b7e1562db2553981a7 (diff)
parent1eb986746a67952df86eb2c50a36450ef103d01b (diff)
downloadlinux-2a79690eae953daaac232f93e6c5ac47ac539f2d.tar.xz
Merge branch 'two-small-fixes-for-global-subprog-tagging'
Andrii Nakryiko says: ==================== Two small fixes for global subprog tagging Fix a bug with passing trusted PTR_TO_BTF_ID_OR_NULL register into global subprog that expects `__arg_trusted __arg_nullable` arguments, which was discovered when adopting production BPF application. Also fix annoying warnings that are irrelevant for static subprogs, which are just an artifact of using btf_prepare_func_args() for both static and global subprogs. ==================== Acked-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20240202190529.2374377-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--kernel/bpf/btf.c6
-rw-r--r--kernel/bpf/verifier.c1
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c32
3 files changed, 36 insertions, 3 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index ef380e546952..f7725cb6e564 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -7122,6 +7122,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
args = (const struct btf_param *)(t + 1);
nargs = btf_type_vlen(t);
if (nargs > MAX_BPF_FUNC_REG_ARGS) {
+ if (!is_global)
+ return -EINVAL;
bpf_log(log, "Global function %s() with %d > %d args. Buggy compiler.\n",
tname, nargs, MAX_BPF_FUNC_REG_ARGS);
return -EINVAL;
@@ -7131,6 +7133,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
while (btf_type_is_modifier(t))
t = btf_type_by_id(btf, t->type);
if (!btf_type_is_int(t) && !btf_is_any_enum(t)) {
+ if (!is_global)
+ return -EINVAL;
bpf_log(log,
"Global function %s() doesn't return scalar. Only those are supported.\n",
tname);
@@ -7251,6 +7255,8 @@ skip_pointer:
sub->args[i].arg_type = ARG_ANYTHING;
continue;
}
+ if (!is_global)
+ return -EINVAL;
bpf_log(log, "Arg#%d type %s in %s() is not supported yet.\n",
i, btf_type_str(t), tname);
return -EINVAL;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a0b8e400b3df..64fa188d00ad 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8242,6 +8242,7 @@ found:
switch ((int)reg->type) {
case PTR_TO_BTF_ID:
case PTR_TO_BTF_ID | PTR_TRUSTED:
+ case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:
case PTR_TO_BTF_ID | MEM_RCU:
case PTR_TO_BTF_ID | PTR_MAYBE_NULL:
case PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU:
diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
index 484d6262363f..4ab0ef18d7eb 100644
--- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
+++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
@@ -19,15 +19,41 @@ __weak int subprog_trusted_task_nullable(struct task_struct *task __arg_trusted
return task->pid + task->tgid;
}
-SEC("?kprobe")
+__weak int subprog_trusted_task_nullable_extra_layer(struct task_struct *task __arg_trusted __arg_nullable)
+{
+ return subprog_trusted_task_nullable(task) + subprog_trusted_task_nullable(NULL);
+}
+
+SEC("?tp_btf/task_newtask")
__success __log_level(2)
__msg("Validating subprog_trusted_task_nullable() func#1...")
__msg(": R1=trusted_ptr_or_null_task_struct(")
int trusted_task_arg_nullable(void *ctx)
{
- struct task_struct *t = bpf_get_current_task_btf();
+ struct task_struct *t1 = bpf_get_current_task_btf();
+ struct task_struct *t2 = bpf_task_acquire(t1);
+ int res = 0;
- return subprog_trusted_task_nullable(t) + subprog_trusted_task_nullable(NULL);
+ /* known NULL */
+ res += subprog_trusted_task_nullable(NULL);
+
+ /* known non-NULL */
+ res += subprog_trusted_task_nullable(t1);
+ res += subprog_trusted_task_nullable_extra_layer(t1);
+
+ /* unknown if NULL or not */
+ res += subprog_trusted_task_nullable(t2);
+ res += subprog_trusted_task_nullable_extra_layer(t2);
+
+ if (t2) {
+ /* known non-NULL after explicit NULL check, just in case */
+ res += subprog_trusted_task_nullable(t2);
+ res += subprog_trusted_task_nullable_extra_layer(t2);
+
+ bpf_task_release(t2);
+ }
+
+ return res;
}
__weak int subprog_trusted_task_nonnull(struct task_struct *task __arg_trusted)