Files
linux/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c
Andrii Nakryiko 1b2bfc2969 selftests/bpf: fix test_spin_lock_fail.c's global vars usage
Global variables of special types (like `struct bpf_spin_lock`) make
underlying ARRAY maps non-mmapable. To make this work with libbpf's
mmaping logic, application is expected to declare such special variables
as static, so libbpf doesn't even attempt to mmap() such ARRAYs.

test_spin_lock_fail.c didn't follow this rule, but given it relied on
this test to trigger failures, this went unnoticed, as we never got to
the step of mmap()'ing these ARRAY maps.

It is fragile and relies on specific sequence of libbpf steps, which are
an internal implementation details.

Fix the test by marking lockA and lockB as static.

Fixes: c48748aea4 ("selftests/bpf: Add failure test cases for spin lock pairing")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20241023043908.3834423-2-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2024-10-23 22:15:09 -07:00

249 lines
5.3 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include "bpf_experimental.h"
struct foo {
struct bpf_spin_lock lock;
int data;
};
struct array_map {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, int);
__type(value, struct foo);
__uint(max_entries, 1);
} array_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__uint(max_entries, 1);
__type(key, int);
__type(value, int);
__array(values, struct array_map);
} map_of_maps SEC(".maps") = {
.values = {
[0] = &array_map,
},
};
static struct bpf_spin_lock lockA SEC(".data.A");
static struct bpf_spin_lock lockB SEC(".data.B");
SEC("?tc")
int lock_id_kptr_preserve(void *ctx)
{
struct foo *f;
f = bpf_obj_new(typeof(*f));
if (!f)
return 0;
bpf_this_cpu_ptr(f);
return 0;
}
SEC("?tc")
int lock_id_global_zero(void *ctx)
{
bpf_this_cpu_ptr(&lockA);
return 0;
}
SEC("?tc")
int lock_id_mapval_preserve(void *ctx)
{
struct foo *f;
int key = 0;
f = bpf_map_lookup_elem(&array_map, &key);
if (!f)
return 0;
bpf_this_cpu_ptr(f);
return 0;
}
SEC("?tc")
int lock_id_innermapval_preserve(void *ctx)
{
struct foo *f;
int key = 0;
void *map;
map = bpf_map_lookup_elem(&map_of_maps, &key);
if (!map)
return 0;
f = bpf_map_lookup_elem(map, &key);
if (!f)
return 0;
bpf_this_cpu_ptr(f);
return 0;
}
#define CHECK(test, A, B) \
SEC("?tc") \
int lock_id_mismatch_##test(void *ctx) \
{ \
struct foo *f1, *f2, *v, *iv; \
int key = 0; \
void *map; \
\
map = bpf_map_lookup_elem(&map_of_maps, &key); \
if (!map) \
return 0; \
iv = bpf_map_lookup_elem(map, &key); \
if (!iv) \
return 0; \
v = bpf_map_lookup_elem(&array_map, &key); \
if (!v) \
return 0; \
f1 = bpf_obj_new(typeof(*f1)); \
if (!f1) \
return 0; \
f2 = bpf_obj_new(typeof(*f2)); \
if (!f2) { \
bpf_obj_drop(f1); \
return 0; \
} \
bpf_spin_lock(A); \
bpf_spin_unlock(B); \
return 0; \
}
CHECK(kptr_kptr, &f1->lock, &f2->lock);
CHECK(kptr_global, &f1->lock, &lockA);
CHECK(kptr_mapval, &f1->lock, &v->lock);
CHECK(kptr_innermapval, &f1->lock, &iv->lock);
CHECK(global_global, &lockA, &lockB);
CHECK(global_kptr, &lockA, &f1->lock);
CHECK(global_mapval, &lockA, &v->lock);
CHECK(global_innermapval, &lockA, &iv->lock);
SEC("?tc")
int lock_id_mismatch_mapval_mapval(void *ctx)
{
struct foo *f1, *f2;
int key = 0;
f1 = bpf_map_lookup_elem(&array_map, &key);
if (!f1)
return 0;
f2 = bpf_map_lookup_elem(&array_map, &key);
if (!f2)
return 0;
bpf_spin_lock(&f1->lock);
f1->data = 42;
bpf_spin_unlock(&f2->lock);
return 0;
}
CHECK(mapval_kptr, &v->lock, &f1->lock);
CHECK(mapval_global, &v->lock, &lockB);
CHECK(mapval_innermapval, &v->lock, &iv->lock);
SEC("?tc")
int lock_id_mismatch_innermapval_innermapval1(void *ctx)
{
struct foo *f1, *f2;
int key = 0;
void *map;
map = bpf_map_lookup_elem(&map_of_maps, &key);
if (!map)
return 0;
f1 = bpf_map_lookup_elem(map, &key);
if (!f1)
return 0;
f2 = bpf_map_lookup_elem(map, &key);
if (!f2)
return 0;
bpf_spin_lock(&f1->lock);
f1->data = 42;
bpf_spin_unlock(&f2->lock);
return 0;
}
SEC("?tc")
int lock_id_mismatch_innermapval_innermapval2(void *ctx)
{
struct foo *f1, *f2;
int key = 0;
void *map;
map = bpf_map_lookup_elem(&map_of_maps, &key);
if (!map)
return 0;
f1 = bpf_map_lookup_elem(map, &key);
if (!f1)
return 0;
map = bpf_map_lookup_elem(&map_of_maps, &key);
if (!map)
return 0;
f2 = bpf_map_lookup_elem(map, &key);
if (!f2)
return 0;
bpf_spin_lock(&f1->lock);
f1->data = 42;
bpf_spin_unlock(&f2->lock);
return 0;
}
CHECK(innermapval_kptr, &iv->lock, &f1->lock);
CHECK(innermapval_global, &iv->lock, &lockA);
CHECK(innermapval_mapval, &iv->lock, &v->lock);
#undef CHECK
__noinline
int global_subprog(struct __sk_buff *ctx)
{
volatile int ret = 0;
if (ctx->protocol)
ret += ctx->protocol;
return ret + ctx->mark;
}
__noinline
static int static_subprog_call_global(struct __sk_buff *ctx)
{
volatile int ret = 0;
if (ctx->protocol)
return ret;
return ret + ctx->len + global_subprog(ctx);
}
SEC("?tc")
int lock_global_subprog_call1(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
if (ctx->mark == 42)
ret = global_subprog(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
SEC("?tc")
int lock_global_subprog_call2(struct __sk_buff *ctx)
{
int ret = 0;
bpf_spin_lock(&lockA);
if (ctx->mark == 42)
ret = static_subprog_call_global(ctx);
bpf_spin_unlock(&lockA);
return ret;
}
char _license[] SEC("license") = "GPL";