-
Notifications
You must be signed in to change notification settings - Fork 52.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add exception handling selftests for tp_bpf program
Exception handling is triggered in BPF tracing programs when a NULL pointer is dereferenced; the exception handler zeroes the target register and execution of the BPF program progresses. To test exception handling then, we need to trigger a NULL pointer dereference for a field which should never be zero; if it is, the only explanation is the exception handler ran. task->task_works is the NULL pointer chosen (for a new task from fork() no work is associated), and the task_works->func field should not be zero if task_works is non-NULL. The test verifies that task_works and task_works->func are 0. Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/1636131046-5982-3-git-send-email-alan.maguire@oracle.com
- Loading branch information
1 parent
b89ddf4
commit c23551c
Showing
2 changed files
with
86 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021, Oracle and/or its affiliates. */ | ||
|
||
#include <test_progs.h> | ||
|
||
/* Test that verifies exception handling is working. fork() | ||
* triggers task_newtask tracepoint; that new task will have a | ||
* NULL pointer task_works, and the associated task->task_works->func | ||
* should not be NULL if task_works itself is non-NULL. | ||
* | ||
* So to verify exception handling we want to see a NULL task_works | ||
* and task_works->func; if we see this we can conclude that the | ||
* exception handler ran when we attempted to dereference task->task_works | ||
* and zeroed the destination register. | ||
*/ | ||
#include "exhandler_kern.skel.h" | ||
|
||
void test_exhandler(void) | ||
{ | ||
int err = 0, duration = 0, status; | ||
struct exhandler_kern *skel; | ||
pid_t cpid; | ||
|
||
skel = exhandler_kern__open_and_load(); | ||
if (CHECK(!skel, "skel_load", "skeleton failed: %d\n", err)) | ||
goto cleanup; | ||
|
||
skel->bss->test_pid = getpid(); | ||
|
||
err = exhandler_kern__attach(skel); | ||
if (!ASSERT_OK(err, "attach")) | ||
goto cleanup; | ||
cpid = fork(); | ||
if (!ASSERT_GT(cpid, -1, "fork failed")) | ||
goto cleanup; | ||
if (cpid == 0) | ||
_exit(0); | ||
waitpid(cpid, &status, 0); | ||
|
||
ASSERT_NEQ(skel->bss->exception_triggered, 0, "verify exceptions occurred"); | ||
cleanup: | ||
exhandler_kern__destroy(skel); | ||
} |
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,43 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021, Oracle and/or its affiliates. */ | ||
|
||
#include "vmlinux.h" | ||
|
||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include <bpf/bpf_core_read.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
unsigned int exception_triggered; | ||
int test_pid; | ||
|
||
/* TRACE_EVENT(task_newtask, | ||
* TP_PROTO(struct task_struct *p, u64 clone_flags) | ||
*/ | ||
SEC("tp_btf/task_newtask") | ||
int BPF_PROG(trace_task_newtask, struct task_struct *task, u64 clone_flags) | ||
{ | ||
int pid = bpf_get_current_pid_tgid() >> 32; | ||
struct callback_head *work; | ||
void *func; | ||
|
||
if (test_pid != pid) | ||
return 0; | ||
|
||
/* To verify we hit an exception we dereference task->task_works->func. | ||
* If task work has been added, | ||
* - task->task_works is non-NULL; and | ||
* - task->task_works->func is non-NULL also (the callback function | ||
* must be specified for the task work. | ||
* | ||
* However, for a newly-created task, task->task_works is NULLed, | ||
* so we know the exception handler triggered if task_works is | ||
* NULL and func is NULL. | ||
*/ | ||
work = task->task_works; | ||
func = work->func; | ||
if (!work && !func) | ||
exception_triggered++; | ||
return 0; | ||
} |