forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel…
…/git/bpf/bpf Daniel Borkmann says: ==================== pull-request: bpf 2024-07-11 The following pull-request contains BPF updates for your *net* tree. We've added 4 non-merge commits during the last 2 day(s) which contain a total of 4 files changed, 262 insertions(+), 19 deletions(-). The main changes are: 1) Fixes for a BPF timer lockup and a use-after-free scenario when timers are used concurrently, from Kumar Kartikeya Dwivedi. 2) Fix the argument order in the call to bpf_map_kvcalloc() which could otherwise lead to a compilation error, from Mohammad Shehar Yaar Tausif. bpf-for-netdev * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: Add timer lockup selftest bpf: Defer work in bpf_timer_cancel_and_free bpf: Fail bpf_timer_cancel when callback is being cancelled bpf: fix order of args in call to bpf_map_kvcalloc ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
- Loading branch information
Showing
4 changed files
with
262 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#define _GNU_SOURCE | ||
#include <sched.h> | ||
#include <test_progs.h> | ||
#include <pthread.h> | ||
#include <network_helpers.h> | ||
|
||
#include "timer_lockup.skel.h" | ||
|
||
static long cpu; | ||
static int *timer1_err; | ||
static int *timer2_err; | ||
static bool skip; | ||
|
||
volatile int k = 0; | ||
|
||
static void *timer_lockup_thread(void *arg) | ||
{ | ||
LIBBPF_OPTS(bpf_test_run_opts, opts, | ||
.data_in = &pkt_v4, | ||
.data_size_in = sizeof(pkt_v4), | ||
.repeat = 1000, | ||
); | ||
int i, prog_fd = *(int *)arg; | ||
cpu_set_t cpuset; | ||
|
||
CPU_ZERO(&cpuset); | ||
CPU_SET(__sync_fetch_and_add(&cpu, 1), &cpuset); | ||
ASSERT_OK(pthread_setaffinity_np(pthread_self(), sizeof(cpuset), | ||
&cpuset), | ||
"cpu affinity"); | ||
|
||
for (i = 0; !READ_ONCE(*timer1_err) && !READ_ONCE(*timer2_err); i++) { | ||
bpf_prog_test_run_opts(prog_fd, &opts); | ||
/* Skip the test if we can't reproduce the race in a reasonable | ||
* amount of time. | ||
*/ | ||
if (i > 50) { | ||
WRITE_ONCE(skip, true); | ||
break; | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
void test_timer_lockup(void) | ||
{ | ||
int timer1_prog, timer2_prog; | ||
struct timer_lockup *skel; | ||
pthread_t thrds[2]; | ||
void *ret; | ||
|
||
skel = timer_lockup__open_and_load(); | ||
if (!ASSERT_OK_PTR(skel, "timer_lockup__open_and_load")) | ||
return; | ||
|
||
timer1_prog = bpf_program__fd(skel->progs.timer1_prog); | ||
timer2_prog = bpf_program__fd(skel->progs.timer2_prog); | ||
|
||
timer1_err = &skel->bss->timer1_err; | ||
timer2_err = &skel->bss->timer2_err; | ||
|
||
if (!ASSERT_OK(pthread_create(&thrds[0], NULL, timer_lockup_thread, | ||
&timer1_prog), | ||
"pthread_create thread1")) | ||
goto out; | ||
if (!ASSERT_OK(pthread_create(&thrds[1], NULL, timer_lockup_thread, | ||
&timer2_prog), | ||
"pthread_create thread2")) { | ||
pthread_exit(&thrds[0]); | ||
goto out; | ||
} | ||
|
||
pthread_join(thrds[1], &ret); | ||
pthread_join(thrds[0], &ret); | ||
|
||
if (skip) { | ||
test__skip(); | ||
goto out; | ||
} | ||
|
||
if (*timer1_err != -EDEADLK && *timer1_err != 0) | ||
ASSERT_FAIL("timer1_err bad value"); | ||
if (*timer2_err != -EDEADLK && *timer2_err != 0) | ||
ASSERT_FAIL("timer2_err bad value"); | ||
out: | ||
timer_lockup__destroy(skel); | ||
return; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
#include <linux/bpf.h> | ||
#include <time.h> | ||
#include <errno.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include "bpf_misc.h" | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
struct elem { | ||
struct bpf_timer t; | ||
}; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, int); | ||
__type(value, struct elem); | ||
} timer1_map SEC(".maps"); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, int); | ||
__type(value, struct elem); | ||
} timer2_map SEC(".maps"); | ||
|
||
int timer1_err; | ||
int timer2_err; | ||
|
||
static int timer_cb1(void *map, int *k, struct elem *v) | ||
{ | ||
struct bpf_timer *timer; | ||
int key = 0; | ||
|
||
timer = bpf_map_lookup_elem(&timer2_map, &key); | ||
if (timer) | ||
timer2_err = bpf_timer_cancel(timer); | ||
|
||
return 0; | ||
} | ||
|
||
static int timer_cb2(void *map, int *k, struct elem *v) | ||
{ | ||
struct bpf_timer *timer; | ||
int key = 0; | ||
|
||
timer = bpf_map_lookup_elem(&timer1_map, &key); | ||
if (timer) | ||
timer1_err = bpf_timer_cancel(timer); | ||
|
||
return 0; | ||
} | ||
|
||
SEC("tc") | ||
int timer1_prog(void *ctx) | ||
{ | ||
struct bpf_timer *timer; | ||
int key = 0; | ||
|
||
timer = bpf_map_lookup_elem(&timer1_map, &key); | ||
if (timer) { | ||
bpf_timer_init(timer, &timer1_map, CLOCK_BOOTTIME); | ||
bpf_timer_set_callback(timer, timer_cb1); | ||
bpf_timer_start(timer, 1, BPF_F_TIMER_CPU_PIN); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
SEC("tc") | ||
int timer2_prog(void *ctx) | ||
{ | ||
struct bpf_timer *timer; | ||
int key = 0; | ||
|
||
timer = bpf_map_lookup_elem(&timer2_map, &key); | ||
if (timer) { | ||
bpf_timer_init(timer, &timer2_map, CLOCK_BOOTTIME); | ||
bpf_timer_set_callback(timer, timer_cb2); | ||
bpf_timer_start(timer, 1, BPF_F_TIMER_CPU_PIN); | ||
} | ||
|
||
return 0; | ||
} |