Skip to content

Commit

Permalink
bpf/selftests: Test using global cpumask kptr with RCU
Browse files Browse the repository at this point in the history
Now that struct bpf_cpumask * is considered an RCU-safe type according
to the verifier, we should add tests that validate its common usages.
This patch adds those tests to the cpumask test suite. A subsequent
changes will remove bpf_cpumask_kptr_get(), and will adjust the selftest
and BPF documentation accordingly.

Signed-off-by: David Vernet <void@manifault.com>
Link: https://lore.kernel.org/r/20230316054028.88924-4-void@manifault.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
David Vernet authored and Alexei Starovoitov committed Mar 16, 2023
1 parent 63d2d83 commit a5a197d
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions tools/testing/selftests/bpf/prog_tests/cpumask.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static const char * const cpumask_success_testcases[] = {
"test_insert_leave",
"test_insert_remove_release",
"test_insert_kptr_get_release",
"test_global_mask_rcu",
};

static void verify_success(const char *prog_name)
Expand Down
6 changes: 6 additions & 0 deletions tools/testing/selftests/bpf/progs/cpumask_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

int err;

#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
private(MASK) static struct bpf_cpumask __kptr * global_mask;

struct __cpumask_map_value {
struct bpf_cpumask __kptr * cpumask;
};
Expand Down Expand Up @@ -51,6 +54,9 @@ void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym
u32 bpf_cpumask_any(const struct cpumask *src) __ksym;
u32 bpf_cpumask_any_and(const struct cpumask *src1, const struct cpumask *src2) __ksym;

void bpf_rcu_read_lock(void) __ksym;
void bpf_rcu_read_unlock(void) __ksym;

static inline const struct cpumask *cast(struct bpf_cpumask *cpumask)
{
return (const struct cpumask *)cpumask;
Expand Down
62 changes: 62 additions & 0 deletions tools/testing/selftests/bpf/progs/cpumask_failure.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,65 @@ int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags)

return 0;
}

SEC("tp_btf/task_newtask")
__failure __msg("R2 must be a rcu pointer")
int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *local, *prev;

local = create_cpumask();
if (!local)
return 0;

prev = bpf_kptr_xchg(&global_mask, local);
if (prev) {
bpf_cpumask_release(prev);
err = 3;
return 0;
}

bpf_rcu_read_lock();
local = global_mask;
if (!local) {
err = 4;
bpf_rcu_read_unlock();
return 0;
}

bpf_rcu_read_unlock();

/* RCU region is exited before calling KF_RCU kfunc. */

bpf_cpumask_test_cpu(0, (const struct cpumask *)local);

return 0;
}

SEC("tp_btf/task_newtask")
__failure __msg("NULL pointer passed to trusted arg1")
int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *local, *prev;

local = create_cpumask();
if (!local)
return 0;

prev = bpf_kptr_xchg(&global_mask, local);
if (prev) {
bpf_cpumask_release(prev);
err = 3;
return 0;
}

bpf_rcu_read_lock();
local = global_mask;

/* No NULL check is performed on global cpumask kptr. */
bpf_cpumask_test_cpu(0, (const struct cpumask *)local);

bpf_rcu_read_unlock();

return 0;
}
33 changes: 33 additions & 0 deletions tools/testing/selftests/bpf/progs/cpumask_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,36 @@ int BPF_PROG(test_insert_kptr_get_release, struct task_struct *task, u64 clone_f

return 0;
}

SEC("tp_btf/task_newtask")
int BPF_PROG(test_global_mask_rcu, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *local, *prev;

if (!is_test_task())
return 0;

local = create_cpumask();
if (!local)
return 0;

prev = bpf_kptr_xchg(&global_mask, local);
if (prev) {
bpf_cpumask_release(prev);
err = 3;
return 0;
}

bpf_rcu_read_lock();
local = global_mask;
if (!local) {
err = 4;
bpf_rcu_read_unlock();
return 0;
}

bpf_cpumask_test_cpu(0, (const struct cpumask *)local);
bpf_rcu_read_unlock();

return 0;
}

0 comments on commit a5a197d

Please sign in to comment.