[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ZAAgfwgo5GU8V28f@maniforge>
Date: Wed, 1 Mar 2023 22:05:19 -0600
From: David Vernet <void@...ifault.com>
To: Alexei Starovoitov <alexei.starovoitov@...il.com>
Cc: davem@...emloft.net, daniel@...earbox.net, andrii@...nel.org,
martin.lau@...nel.org, davemarchevsky@...a.com, tj@...nel.org,
memxor@...il.com, netdev@...r.kernel.org, bpf@...r.kernel.org,
kernel-team@...com
Subject: Re: [PATCH v4 bpf-next 6/6] bpf: Refactor RCU enforcement in the
verifier.
On Wed, Mar 01, 2023 at 02:35:55PM -0800, Alexei Starovoitov wrote:
> From: Alexei Starovoitov <ast@...nel.org>
>
> bpf_rcu_read_lock/unlock() are only available in clang compiled kernels. Lack
> of such key mechanism makes it impossible for sleepable bpf programs to use RCU
> pointers.
>
> Allow bpf_rcu_read_lock/unlock() in GCC compiled kernels (though GCC doesn't
> support btf_type_tag yet) and allowlist certain field dereferences in important
> data structures like tast_struct, cgroup, socket that are used by sleepable
> programs either as RCU pointer or full trusted pointer (which is valid outside
> of RCU CS). Use BTF_TYPE_SAFE_RCU and BTF_TYPE_SAFE_TRUSTED macros for such
> tagging. They will be removed once GCC supports btf_type_tag.
>
> With that refactor check_ptr_to_btf_access(). Make it strict in enforcing
> PTR_TRUSTED and PTR_UNTRUSTED while deprecating old PTR_TO_BTF_ID without
> modifier flags. There is a chance that this strict enforcement might break
> existing programs (especially on GCC compiled kernels), but this cleanup has to
> start sooner than later. Note PTR_TO_CTX access still yields old deprecated
> PTR_TO_BTF_ID. Once it's converted to strict PTR_TRUSTED or PTR_UNTRUSTED the
> kfuncs and helpers will be able to default to KF_TRUSTED_ARGS. KF_RCU will
> remain as a weaker version of KF_TRUSTED_ARGS where obj refcnt could be 0.
>
> Signed-off-by: Alexei Starovoitov <ast@...nel.org>
Nice, this is a great cleanup. Looks good overall, left a couple of
minor comments / questions below.
> ---
> include/linux/bpf.h | 2 +-
> include/linux/bpf_verifier.h | 1 -
> kernel/bpf/btf.c | 15 +-
> kernel/bpf/cpumask.c | 40 ++--
> kernel/bpf/verifier.c | 178 ++++++++++++------
> .../bpf/prog_tests/cgrp_local_storage.c | 14 +-
> .../selftests/bpf/prog_tests/rcu_read_lock.c | 16 +-
> .../selftests/bpf/progs/cgrp_ls_sleepable.c | 4 +-
> .../selftests/bpf/progs/cpumask_failure.c | 2 +-
> .../bpf/progs/nested_trust_failure.c | 2 +-
> .../selftests/bpf/progs/rcu_read_lock.c | 6 +-
> tools/testing/selftests/bpf/verifier/calls.c | 2 +-
> 12 files changed, 172 insertions(+), 110 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 23ec684e660d..d3456804f7aa 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -2279,7 +2279,7 @@ struct bpf_core_ctx {
>
> bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
> const struct bpf_reg_state *reg,
> - int off);
> + int off, const char *suffix);
>
> bool btf_type_ids_nocast_alias(struct bpf_verifier_log *log,
> const struct btf *reg_btf, u32 reg_id,
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index b26ff2a8f63b..18538bad2b8c 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -537,7 +537,6 @@ struct bpf_verifier_env {
> bool bypass_spec_v1;
> bool bypass_spec_v4;
> bool seen_direct_write;
> - bool rcu_tag_supported;
> struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
> const struct bpf_line_info *prev_linfo;
> struct bpf_verifier_log log;
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index c5e1d6955491..bae384728ec7 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -6329,6 +6329,15 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> * of this field or inside of this struct
> */
> if (btf_type_is_struct(mtype)) {
> + if (BTF_INFO_KIND(mtype->info) == BTF_KIND_UNION &&
> + btf_type_vlen(mtype) != 1)
> + /*
> + * walking unions yields untrusted pointers
> + * with exception of __bpf_md_ptr and others
s/others/other
> + * unions with a single member
> + */
> + *flag |= PTR_UNTRUSTED;
> +
> /* our field must be inside that union or struct */
> t = mtype;
>
> @@ -6373,7 +6382,7 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
> stype = btf_type_skip_modifiers(btf, mtype->type, &id);
> if (btf_type_is_struct(stype)) {
> *next_btf_id = id;
> - *flag = tmp_flag;
> + *flag |= tmp_flag;
Now that this function doesn't do a full write of the variable, the
semantics have changed such that the caller has to initialize the
variable on behalf of bpf_struct_walk(). This makes callers such as
btf_struct_ids_match() (line 6503) have random crud in the pointer.
Doesn't really matter for that case because the variable isn't used
anyways, but it seems slightly less brittle to initialize *flag to 0 at
the beginning of the function to avoid requiring the caller to
initialize it. Wdyt?
> return WALK_PTR;
> }
> }
> @@ -8357,7 +8366,7 @@ int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
>
> bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
> const struct bpf_reg_state *reg,
> - int off)
> + int off, const char *suffix)
> {
> struct btf *btf = reg->btf;
> const struct btf_type *walk_type, *safe_type;
> @@ -8374,7 +8383,7 @@ bool btf_nested_type_is_trusted(struct bpf_verifier_log *log,
>
> tname = btf_name_by_offset(btf, walk_type->name_off);
>
> - ret = snprintf(safe_tname, sizeof(safe_tname), "%s__safe_fields", tname);
> + ret = snprintf(safe_tname, sizeof(safe_tname), "%s%s", tname, suffix);
> if (ret < 0)
> return false;
>
> diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c
> index 2b3fbbfebdc5..2223562dd54e 100644
> --- a/kernel/bpf/cpumask.c
> +++ b/kernel/bpf/cpumask.c
> @@ -427,26 +427,26 @@ BTF_ID_FLAGS(func, bpf_cpumask_create, KF_ACQUIRE | KF_RET_NULL)
> BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE | KF_TRUSTED_ARGS)
> BTF_ID_FLAGS(func, bpf_cpumask_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
> BTF_ID_FLAGS(func, bpf_cpumask_kptr_get, KF_ACQUIRE | KF_KPTR_GET | KF_RET_NULL)
> -BTF_ID_FLAGS(func, bpf_cpumask_first, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_first_zero, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_set_cpu, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_clear_cpu, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_test_cpu, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_test_and_set_cpu, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_test_and_clear_cpu, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_setall, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_clear, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_and, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_or, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_xor, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_equal, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_intersects, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_subset, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_empty, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_full, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_any, KF_TRUSTED_ARGS)
> -BTF_ID_FLAGS(func, bpf_cpumask_any_and, KF_TRUSTED_ARGS)
> +BTF_ID_FLAGS(func, bpf_cpumask_first, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_first_zero, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_set_cpu, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_clear_cpu, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_test_cpu, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_test_and_set_cpu, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_test_and_clear_cpu, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_setall, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_clear, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_and, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_or, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_xor, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_equal, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_intersects, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_subset, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_empty, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_full, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_any, KF_TRUSTED_ARGS | KF_RCU)
> +BTF_ID_FLAGS(func, bpf_cpumask_any_and, KF_TRUSTED_ARGS | KF_RCU)
It's functionally the same, but could you please remove KF_TRUSTED_ARGS
given that it's accepted for KF_RCU? We should ideally be removing
KF_TRUSTED_ARGS altogether soon(ish) anyways, so might as well do it
here.
> BTF_SET8_END(cpumask_kfunc_btf_ids)
>
> static const struct btf_kfunc_id_set cpumask_kfunc_set = {
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a095055d7ef4..10d674e8154a 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5073,29 +5073,76 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val)
> return 0;
> }
>
> -#define BTF_TYPE_SAFE_NESTED(__type) __PASTE(__type, __safe_fields)
> +#define BTF_TYPE_SAFE_RCU(__type) __PASTE(__type, __safe_rcu)
> +#define BTF_TYPE_SAFE_TRUSTED(__type) __PASTE(__type, __safe_trusted)
>
> -BTF_TYPE_SAFE_NESTED(struct task_struct) {
> +/*
> + * Allow list few fields as RCU trusted or full trusted.
> + * This logic doesn't allow mix tagging and will be removed once GCC supports
> + * btf_type_tag.
> + */
> +
> +/* RCU trusted: these fields are trusted in RCU CS and never NULL */
> +BTF_TYPE_SAFE_RCU(struct task_struct) {
> const cpumask_t *cpus_ptr;
> struct css_set __rcu *cgroups;
> + struct task_struct __rcu *real_parent;
> + struct task_struct *group_leader;
> };
>
> -BTF_TYPE_SAFE_NESTED(struct css_set) {
> +BTF_TYPE_SAFE_RCU(struct css_set) {
> struct cgroup *dfl_cgrp;
> };
>
> -static bool nested_ptr_is_trusted(struct bpf_verifier_env *env,
> - struct bpf_reg_state *reg,
> - int off)
> +/* full trusted: these fields are trusted even outside of RCU CS and never NULL */
> +BTF_TYPE_SAFE_TRUSTED(struct bpf_iter_meta) {
> + __bpf_md_ptr(struct seq_file *, seq);
> +};
> +
> +BTF_TYPE_SAFE_TRUSTED(struct bpf_iter__task) {
> + __bpf_md_ptr(struct bpf_iter_meta *, meta);
> + __bpf_md_ptr(struct task_struct *, task);
> +};
> +
> +BTF_TYPE_SAFE_TRUSTED(struct linux_binprm) {
> + struct file *file;
> +};
> +
> +BTF_TYPE_SAFE_TRUSTED(struct file) {
> + struct inode *f_inode;
> +};
> +
> +BTF_TYPE_SAFE_TRUSTED(struct dentry) {
> + /* no negative dentry-s in places where bpf can see it */
> + struct inode *d_inode;
> +};
> +
> +BTF_TYPE_SAFE_TRUSTED(struct socket) {
> + struct sock *sk;
> +};
> +
> +static bool type_is_rcu(struct bpf_verifier_env *env,
> + struct bpf_reg_state *reg,
> + int off)
> {
> - /* If its parent is not trusted, it can't regain its trusted status. */
> - if (!is_trusted_reg(reg))
> - return false;
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_RCU(struct task_struct));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_RCU(struct css_set));
>
> - BTF_TYPE_EMIT(BTF_TYPE_SAFE_NESTED(struct task_struct));
> - BTF_TYPE_EMIT(BTF_TYPE_SAFE_NESTED(struct css_set));
> + return btf_nested_type_is_trusted(&env->log, reg, off, "__safe_rcu");
> +}
>
> - return btf_nested_type_is_trusted(&env->log, reg, off);
> +static bool type_is_trusted(struct bpf_verifier_env *env,
> + struct bpf_reg_state *reg,
> + int off)
> +{
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct bpf_iter_meta));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct bpf_iter__task));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct socket));
> +
> + return btf_nested_type_is_trusted(&env->log, reg, off, "__safe_trusted");
> }
>
> static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
> @@ -5181,49 +5228,58 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
> if (ret < 0)
> return ret;
>
> - /* If this is an untrusted pointer, all pointers formed by walking it
> - * also inherit the untrusted flag.
> - */
> - if (type_flag(reg->type) & PTR_UNTRUSTED)
> - flag |= PTR_UNTRUSTED;
> + if (ret != PTR_TO_BTF_ID) {
> + /* just mark; */
>
> - /* By default any pointer obtained from walking a trusted pointer is no
> - * longer trusted, unless the field being accessed has explicitly been
> - * marked as inheriting its parent's state of trust.
> - *
> - * An RCU-protected pointer can also be deemed trusted if we are in an
> - * RCU read region. This case is handled below.
> - */
> - if (nested_ptr_is_trusted(env, reg, off)) {
> - flag |= PTR_TRUSTED;
> - /*
> - * task->cgroups is trusted. It provides a stronger guarantee
> - * than __rcu tag on 'cgroups' field in 'struct task_struct'.
> - * Clear MEM_RCU in such case.
> + } else if (type_flag(reg->type) & PTR_UNTRUSTED) {
> + /* If this is an untrusted pointer, all pointers formed by walking it
> + * also inherit the untrusted flag.
> + */
> + flag = PTR_UNTRUSTED;
> +
> + } else if (is_trusted_reg(reg) || is_rcu_reg(reg)) {
> + /* By default any pointer obtained from walking a trusted pointer is no
> + * longer trusted, unless the field being accessed has explicitly been
> + * marked as inheriting its parent's state of trust (either full or RCU).
> + * For example:
> + * 'cgroups' pointer is untrusted if task->cgroups dereference
> + * happened in a sleepable program outside of bpf_rcu_read_lock()
> + * section. In a non-sleepable program it's trusted while in RCU CS (aka MEM_RCU).
> + * Note bpf_rcu_read_unlock() converts MEM_RCU pointers to PTR_UNTRUSTED.
> + *
> + * A regular RCU-protected pointer with __rcu tag can also be deemed
> + * trusted if we are in an RCU CS. Such pointer can be NULL.
> */
> - flag &= ~MEM_RCU;
> + if (type_is_trusted(env, reg, off)) {
> + flag |= PTR_TRUSTED;
> + } else if (in_rcu_cs(env) && !type_may_be_null(reg->type)) {
> + if (type_is_rcu(env, reg, off)) {
> + /* ignore __rcu tag and mark it MEM_RCU */
> + flag |= MEM_RCU;
> + } else if (flag & MEM_RCU) {
> + /* __rcu tagged pointers can be NULL */
> + flag |= PTR_MAYBE_NULL;
I'm not quite understanding the distinction between manually-specified
RCU-safe types being non-nullable, vs. __rcu pointers being nullable.
Aren't they functionally the exact same thing, with the exception being
that gcc doesn't support __rcu, so we've decided to instead manually
specify them for some types that we know we need until __rcu is the
default mechanism? If the plan is to remove these macros once gcc
supports __rcu, this could break some programs that are expecting the
fields to be non-NULL, no?
I see why we're doing this in the interim -- task->cgroups,
css->dfl_cgrp, task->cpus_ptr, etc can never be NULL. The problem is
that I think those are implementation details that are separate from the
pointers being RCU safe. This seems rather like we need a separate
non-nullable tag, or something to that effect.
> + } else if (flag & (MEM_PERCPU | MEM_USER)) {
> + /* keep as-is */
> + } else {
> + /* walking unknown pointers yields untrusted pointer */
> + flag = PTR_UNTRUSTED;
> + }
> + } else {
> + /*
> + * If not in RCU CS or MEM_RCU pointer can be NULL then
> + * aggressively mark as untrusted otherwise such
> + * pointers will be plain PTR_TO_BTF_ID without flags
> + * and will be allowed to be passed into helpers for
> + * compat reasons.
> + */
> + flag = PTR_UNTRUSTED;
> + }
> } else {
> + /* Old compat. Deperecated */
s/Deperecated/Deprecated
> flag &= ~PTR_TRUSTED;
Do you know what else is left for us to fix to be able to just set
PTR_UNTRUSTED here?
> }
>
> - if (flag & MEM_RCU) {
> - /* Mark value register as MEM_RCU only if it is protected by
> - * bpf_rcu_read_lock() and the ptr reg is rcu or trusted. MEM_RCU
> - * itself can already indicate trustedness inside the rcu
> - * read lock region. Also mark rcu pointer as PTR_MAYBE_NULL since
> - * it could be null in some cases.
> - */
> - if (in_rcu_cs(env) && (is_trusted_reg(reg) || is_rcu_reg(reg)))
> - flag |= PTR_MAYBE_NULL;
> - else
> - flag &= ~MEM_RCU;
> - } else if (reg->type & MEM_RCU) {
> - /* ptr (reg) is marked as MEM_RCU, but the struct field is not tagged
> - * with __rcu. Mark the flag as PTR_UNTRUSTED conservatively.
> - */
> - flag |= PTR_UNTRUSTED;
> - }
> -
> if (atype == BPF_READ && value_regno >= 0)
> mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag);
>
> @@ -10049,10 +10105,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>
> rcu_lock = is_kfunc_bpf_rcu_read_lock(&meta);
> rcu_unlock = is_kfunc_bpf_rcu_read_unlock(&meta);
> - if ((rcu_lock || rcu_unlock) && !env->rcu_tag_supported) {
> - verbose(env, "no vmlinux btf rcu tag support for kfunc %s\n", func_name);
> - return -EACCES;
> - }
>
> if (env->cur_state->active_rcu_lock) {
> struct bpf_func_state *state;
> @@ -14911,8 +14963,22 @@ static int do_check(struct bpf_verifier_env *env)
> * src_reg == stack|map in some other branch.
> * Reject it.
> */
> - verbose(env, "same insn cannot be used with different pointers\n");
> - return -EINVAL;
> + if (base_type(src_reg_type) == PTR_TO_BTF_ID &&
> + base_type(*prev_src_type) == PTR_TO_BTF_ID) {
> + /*
> + * Have to support a use case when one path through
> + * the program yields TRUSTED pointer while another
> + * is UNTRUSTED. Fallback to UNTRUSTED to generate
> + * BPF_PROBE_MEM.
> + */
> + *prev_src_type = PTR_TO_BTF_ID | PTR_UNTRUSTED;
> + } else {
> + verbose(env,
> + "The same insn cannot be used with different pointers: %s",
> + reg_type_str(env, src_reg_type));
> + verbose(env, " != %s\n", reg_type_str(env, *prev_src_type));
> + return -EINVAL;
> + }
> }
>
> } else if (class == BPF_STX) {
> @@ -17984,8 +18050,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr)
> env->bypass_spec_v1 = bpf_bypass_spec_v1();
> env->bypass_spec_v4 = bpf_bypass_spec_v4();
> env->bpf_capable = bpf_capable();
> - env->rcu_tag_supported = btf_vmlinux &&
> - btf_find_by_name_kind(btf_vmlinux, "rcu", BTF_KIND_TYPE_TAG) > 0;
>
> if (is_priv)
> env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
> diff --git a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
> index 2cc759956e3b..63e776f4176e 100644
> --- a/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
> +++ b/tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
> @@ -193,7 +193,7 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
> cgrp_ls_sleepable__destroy(skel);
> }
>
> -static void test_no_rcu_lock(__u64 cgroup_id)
> +static void test_yes_rcu_lock(__u64 cgroup_id)
> {
> struct cgrp_ls_sleepable *skel;
> int err;
> @@ -204,7 +204,7 @@ static void test_no_rcu_lock(__u64 cgroup_id)
>
> skel->bss->target_pid = syscall(SYS_gettid);
>
> - bpf_program__set_autoload(skel->progs.no_rcu_lock, true);
> + bpf_program__set_autoload(skel->progs.yes_rcu_lock, true);
> err = cgrp_ls_sleepable__load(skel);
> if (!ASSERT_OK(err, "skel_load"))
> goto out;
> @@ -220,7 +220,7 @@ static void test_no_rcu_lock(__u64 cgroup_id)
> cgrp_ls_sleepable__destroy(skel);
> }
>
> -static void test_rcu_lock(void)
> +static void test_no_rcu_lock(void)
> {
> struct cgrp_ls_sleepable *skel;
> int err;
> @@ -229,7 +229,7 @@ static void test_rcu_lock(void)
> if (!ASSERT_OK_PTR(skel, "skel_open"))
> return;
>
> - bpf_program__set_autoload(skel->progs.yes_rcu_lock, true);
> + bpf_program__set_autoload(skel->progs.no_rcu_lock, true);
> err = cgrp_ls_sleepable__load(skel);
> ASSERT_ERR(err, "skel_load");
>
> @@ -256,10 +256,10 @@ void test_cgrp_local_storage(void)
> test_negative();
> if (test__start_subtest("cgroup_iter_sleepable"))
> test_cgroup_iter_sleepable(cgroup_fd, cgroup_id);
> + if (test__start_subtest("yes_rcu_lock"))
> + test_yes_rcu_lock(cgroup_id);
> if (test__start_subtest("no_rcu_lock"))
> - test_no_rcu_lock(cgroup_id);
> - if (test__start_subtest("rcu_lock"))
> - test_rcu_lock();
> + test_no_rcu_lock();
>
> close(cgroup_fd);
> }
> diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
> index 447d8560ecb6..3f1f58d3a729 100644
> --- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
> +++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c
> @@ -25,10 +25,10 @@ static void test_success(void)
>
> bpf_program__set_autoload(skel->progs.get_cgroup_id, true);
> bpf_program__set_autoload(skel->progs.task_succ, true);
> - bpf_program__set_autoload(skel->progs.no_lock, true);
> bpf_program__set_autoload(skel->progs.two_regions, true);
> bpf_program__set_autoload(skel->progs.non_sleepable_1, true);
> bpf_program__set_autoload(skel->progs.non_sleepable_2, true);
> + bpf_program__set_autoload(skel->progs.task_trusted_non_rcuptr, true);
> err = rcu_read_lock__load(skel);
> if (!ASSERT_OK(err, "skel_load"))
> goto out;
> @@ -69,6 +69,7 @@ static void test_rcuptr_acquire(void)
>
> static const char * const inproper_region_tests[] = {
> "miss_lock",
> + "no_lock",
> "miss_unlock",
> "non_sleepable_rcu_mismatch",
> "inproper_sleepable_helper",
> @@ -99,7 +100,6 @@ static void test_inproper_region(void)
> }
>
> static const char * const rcuptr_misuse_tests[] = {
> - "task_untrusted_non_rcuptr",
> "task_untrusted_rcuptr",
> "cross_rcu_region",
> };
> @@ -128,17 +128,8 @@ static void test_rcuptr_misuse(void)
>
> void test_rcu_read_lock(void)
> {
> - struct btf *vmlinux_btf;
> int cgroup_fd;
>
> - vmlinux_btf = btf__load_vmlinux_btf();
> - if (!ASSERT_OK_PTR(vmlinux_btf, "could not load vmlinux BTF"))
> - return;
> - if (btf__find_by_name_kind(vmlinux_btf, "rcu", BTF_KIND_TYPE_TAG) < 0) {
> - test__skip();
> - goto out;
> - }
> -
> cgroup_fd = test__join_cgroup("/rcu_read_lock");
> if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /rcu_read_lock"))
> goto out;
> @@ -153,6 +144,5 @@ void test_rcu_read_lock(void)
> if (test__start_subtest("negative_tests_rcuptr_misuse"))
> test_rcuptr_misuse();
> close(cgroup_fd);
> -out:
> - btf__free(vmlinux_btf);
> +out:;
> }
> diff --git a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c
> index 2d11ed528b6f..7615dc23d301 100644
> --- a/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c
> +++ b/tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c
> @@ -49,7 +49,7 @@ int no_rcu_lock(void *ctx)
> if (task->pid != target_pid)
> return 0;
>
> - /* ptr_to_btf_id semantics. should work. */
> + /* task->cgroups is untrusted in sleepable prog outside of RCU CS */
> cgrp = task->cgroups->dfl_cgrp;
> ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0,
> BPF_LOCAL_STORAGE_GET_F_CREATE);
> @@ -71,7 +71,7 @@ int yes_rcu_lock(void *ctx)
>
> bpf_rcu_read_lock();
> cgrp = task->cgroups->dfl_cgrp;
> - /* cgrp is untrusted and cannot pass to bpf_cgrp_storage_get() helper. */
> + /* cgrp is trusted under RCU CS */
> ptr = bpf_cgrp_storage_get(&map_a, cgrp, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
> if (ptr)
> cgroup_id = cgrp->kn->id;
> diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c
> index 33e8e86dd090..c16f7563b84e 100644
> --- a/tools/testing/selftests/bpf/progs/cpumask_failure.c
> +++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c
> @@ -44,7 +44,7 @@ int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flag
> }
>
> SEC("tp_btf/task_newtask")
> -__failure __msg("bpf_cpumask_acquire args#0 expected pointer to STRUCT bpf_cpumask")
> +__failure __msg("must be referenced")
> int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags)
> {
> struct bpf_cpumask *cpumask;
> diff --git a/tools/testing/selftests/bpf/progs/nested_trust_failure.c b/tools/testing/selftests/bpf/progs/nested_trust_failure.c
> index 14aff7676436..0d1aa6bbace4 100644
> --- a/tools/testing/selftests/bpf/progs/nested_trust_failure.c
> +++ b/tools/testing/selftests/bpf/progs/nested_trust_failure.c
> @@ -17,7 +17,7 @@ char _license[] SEC("license") = "GPL";
> */
>
> SEC("tp_btf/task_newtask")
> -__failure __msg("R2 must be referenced or trusted")
> +__failure __msg("R2 must be")
> int BPF_PROG(test_invalid_nested_user_cpus, struct task_struct *task, u64 clone_flags)
> {
> bpf_cpumask_test_cpu(0, task->user_cpus_ptr);
> diff --git a/tools/testing/selftests/bpf/progs/rcu_read_lock.c b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
> index 5cecbdbbb16e..7250bb76d18a 100644
> --- a/tools/testing/selftests/bpf/progs/rcu_read_lock.c
> +++ b/tools/testing/selftests/bpf/progs/rcu_read_lock.c
> @@ -81,7 +81,7 @@ int no_lock(void *ctx)
> {
> struct task_struct *task, *real_parent;
>
> - /* no bpf_rcu_read_lock(), old code still works */
> + /* old style ptr_to_btf_id is not allowed in sleepable */
> task = bpf_get_current_task_btf();
> real_parent = task->real_parent;
> (void)bpf_task_storage_get(&map_a, real_parent, 0, 0);
> @@ -286,13 +286,13 @@ int nested_rcu_region(void *ctx)
> }
>
> SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
> -int task_untrusted_non_rcuptr(void *ctx)
> +int task_trusted_non_rcuptr(void *ctx)
> {
> struct task_struct *task, *group_leader;
>
> task = bpf_get_current_task_btf();
> bpf_rcu_read_lock();
> - /* the pointer group_leader marked as untrusted */
> + /* the pointer group_leader is explicitly marked as trusted */
> group_leader = task->real_parent->group_leader;
> (void)bpf_task_storage_get(&map_a, group_leader, 0, 0);
> bpf_rcu_read_unlock();
> diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
> index 9a326a800e5c..5702fc9761ef 100644
> --- a/tools/testing/selftests/bpf/verifier/calls.c
> +++ b/tools/testing/selftests/bpf/verifier/calls.c
> @@ -181,7 +181,7 @@
> },
> .result_unpriv = REJECT,
> .result = REJECT,
> - .errstr = "negative offset ptr_ ptr R1 off=-4 disallowed",
> + .errstr = "ptr R1 off=-4 disallowed",
> },
> {
> "calls: invalid kfunc call: PTR_TO_BTF_ID with variable offset",
> --
> 2.39.2
>
Powered by blists - more mailing lists