diff options
author | Alexei Starovoitov <ast@kernel.org> | 2024-02-03 05:08:59 +0300 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2024-02-03 05:09:06 +0300 |
commit | 2a79690eae953daaac232f93e6c5ac47ac539f2d (patch) | |
tree | 0e4d601040f137b0bc160f6757cff8577ae15fe4 | |
parent | a68b50f47bec8bd6a33b07b7e1562db2553981a7 (diff) | |
parent | 1eb986746a67952df86eb2c50a36450ef103d01b (diff) | |
download | linux-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.c | 6 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 1 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c | 32 |
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) |