Commit a5a197df authored by David Vernet's avatar David Vernet Committed by Alexei Starovoitov
Browse files

bpf/selftests: Test using global cpumask kptr with RCU



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: default avatarDavid Vernet <void@manifault.com>
Link: https://lore.kernel.org/r/20230316054028.88924-4-void@manifault.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 63d2d83d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+6 −0
Original line number Diff line number Diff line
@@ -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;
};
@@ -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;
+62 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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;
}