From ef08703ab94c42a41802a1df820e0647ddf590ff Mon Sep 17 00:00:00 2001 From: Timo Beckers Date: Wed, 28 Sep 2022 09:28:28 +0200 Subject: [PATCH] sys: mask SIGPROF during BPF_PROG_LOAD to prevent livelocks If a thread receives a signal while blocked in BPF_PROG_LOAD, the verifier can cooperatively interrupt itself by checking pending signals for the thread and return -EAGAIN from the syscall to request userspace to retry. When a Go program is built and run with pprof enabled, threads are routinely sent a SIGPROF to make them dump profiling information, which can lead to a runaway reaction if the program takes longer to verify than the interrupt frequency. To prevent this, mask SIGPROF before calling BPF_PROG_LOAD and remove it when done. Signed-off-by: Timo Beckers --- internal/sys/syscall.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/sys/syscall.go b/internal/sys/syscall.go index 6dde23075..3205ede80 100644 --- a/internal/sys/syscall.go +++ b/internal/sys/syscall.go @@ -17,6 +17,13 @@ var ENOTSUPP = syscall.Errno(524) // // Any pointers contained in attr must use the Pointer type from this package. func BPF(cmd Cmd, attr unsafe.Pointer, size uintptr) (uintptr, error) { + // Prevent the Go profiler from repeatedly interrupting the verifier, + // which could otherwise lead to a livelock due to receiving EAGAIN. + if cmd == BPF_PROG_LOAD { + maskProfilerSignal() + defer unmaskProfilerSignal() + } + for { r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) runtime.KeepAlive(attr)