mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
selftests: bpf: add bpf_cpumask_populate selftests
Add selftests for the bpf_cpumask_populate helper that sets a bpf_cpumask to a bit pattern provided by a BPF program. Signed-off-by: Emil Tsalapatis (Meta) <emil@etsalapatis.com> Acked-by: Hou Tao <houtao1@huawei.com> Link: https://lore.kernel.org/r/20250309230427.26603-3-emil@etsalapatis.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
950ad93df2
commit
918ba2636d
|
|
@ -25,6 +25,9 @@ static const char * const cpumask_success_testcases[] = {
|
|||
"test_global_mask_nested_deep_rcu",
|
||||
"test_global_mask_nested_deep_array_rcu",
|
||||
"test_cpumask_weight",
|
||||
"test_populate_reject_small_mask",
|
||||
"test_populate_reject_unaligned",
|
||||
"test_populate",
|
||||
};
|
||||
|
||||
static void verify_success(const char *prog_name)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym __weak;
|
|||
u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1,
|
||||
const struct cpumask *src2) __ksym __weak;
|
||||
u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym __weak;
|
||||
int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak;
|
||||
|
||||
void bpf_rcu_read_lock(void) __ksym __weak;
|
||||
void bpf_rcu_read_unlock(void) __ksym __weak;
|
||||
|
|
|
|||
|
|
@ -222,3 +222,41 @@ int BPF_PROG(test_invalid_nested_array, struct task_struct *task, u64 clone_flag
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
__failure __msg("type=scalar expected=fp")
|
||||
int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 clone_flags)
|
||||
{
|
||||
struct bpf_cpumask *invalid = (struct bpf_cpumask *)0x123456;
|
||||
u64 bits;
|
||||
int ret;
|
||||
|
||||
ret = bpf_cpumask_populate((struct cpumask *)invalid, &bits, sizeof(bits));
|
||||
if (!ret)
|
||||
err = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
__failure __msg("leads to invalid memory access")
|
||||
int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_flags)
|
||||
{
|
||||
void *garbage = (void *)0x123456;
|
||||
struct bpf_cpumask *local;
|
||||
int ret;
|
||||
|
||||
local = create_cpumask();
|
||||
if (!local) {
|
||||
err = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = bpf_cpumask_populate((struct cpumask *)local, garbage, 8);
|
||||
if (!ret)
|
||||
err = 2;
|
||||
|
||||
bpf_cpumask_release(local);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -770,3 +770,122 @@ int BPF_PROG(test_refcount_null_tracking, struct task_struct *task, u64 clone_fl
|
|||
bpf_cpumask_release(mask2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
int BPF_PROG(test_populate_reject_small_mask, struct task_struct *task, u64 clone_flags)
|
||||
{
|
||||
struct bpf_cpumask *local;
|
||||
u8 toofewbits;
|
||||
int ret;
|
||||
|
||||
if (!is_test_task())
|
||||
return 0;
|
||||
|
||||
local = create_cpumask();
|
||||
if (!local)
|
||||
return 0;
|
||||
|
||||
/* The kfunc should prevent this operation */
|
||||
ret = bpf_cpumask_populate((struct cpumask *)local, &toofewbits, sizeof(toofewbits));
|
||||
if (ret != -EACCES)
|
||||
err = 2;
|
||||
|
||||
bpf_cpumask_release(local);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Mask is guaranteed to be large enough for bpf_cpumask_t. */
|
||||
#define CPUMASK_TEST_MASKLEN (sizeof(cpumask_t))
|
||||
|
||||
/* Add an extra word for the test_populate_reject_unaligned test. */
|
||||
u64 bits[CPUMASK_TEST_MASKLEN / 8 + 1];
|
||||
extern bool CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS __kconfig __weak;
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
int BPF_PROG(test_populate_reject_unaligned, struct task_struct *task, u64 clone_flags)
|
||||
{
|
||||
struct bpf_cpumask *mask;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
if (!is_test_task())
|
||||
return 0;
|
||||
|
||||
/* Skip if unaligned accesses are fine for this arch. */
|
||||
if (CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
return 0;
|
||||
|
||||
mask = bpf_cpumask_create();
|
||||
if (!mask) {
|
||||
err = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Misalign the source array by a byte. */
|
||||
src = &((char *)bits)[1];
|
||||
|
||||
ret = bpf_cpumask_populate((struct cpumask *)mask, src, CPUMASK_TEST_MASKLEN);
|
||||
if (ret != -EINVAL)
|
||||
err = 2;
|
||||
|
||||
bpf_cpumask_release(mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
int BPF_PROG(test_populate, struct task_struct *task, u64 clone_flags)
|
||||
{
|
||||
struct bpf_cpumask *mask;
|
||||
bool bit;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!is_test_task())
|
||||
return 0;
|
||||
|
||||
/* Set only odd bits. */
|
||||
__builtin_memset(bits, 0xaa, CPUMASK_TEST_MASKLEN);
|
||||
|
||||
mask = bpf_cpumask_create();
|
||||
if (!mask) {
|
||||
err = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pass the entire bits array, the kfunc will only copy the valid bits. */
|
||||
ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN);
|
||||
if (ret) {
|
||||
err = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test is there to appease the verifier. We cannot directly
|
||||
* access NR_CPUS, the upper bound for nr_cpus, so we infer
|
||||
* it from the size of cpumask_t.
|
||||
*/
|
||||
if (nr_cpus < 0 || nr_cpus >= CPUMASK_TEST_MASKLEN * 8) {
|
||||
err = 3;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bpf_for(i, 0, nr_cpus) {
|
||||
/* Odd-numbered bits should be set, even ones unset. */
|
||||
bit = bpf_cpumask_test_cpu(i, (const struct cpumask *)mask);
|
||||
if (bit == (i % 2 != 0))
|
||||
continue;
|
||||
|
||||
err = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
bpf_cpumask_release(mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef CPUMASK_TEST_MASKLEN
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user