rngd exits after being stopped and resumed

Linux has documented but somewhat unusual behavior around
SIGSTOP/SIGCONT and certain syscalls, of which epoll_wait(2) is one.  In
this particular case, rngd exited unexpectedly after getting ptrace'd
mid-epoll_wait.  Fix this by handling EINTR from this syscall, and
continuing to add entropy and wait.

Signed-off-by: Krister Johansen <krister.johansen@oracle.com>
This commit is contained in:
Krister Johansen 2019-05-07 15:30:25 -07:00
parent 4dbba2540b
commit 3b20802be7

View File

@ -9,6 +9,7 @@ import (
"flag" "flag"
"log" "log"
"os" "os"
"syscall"
"unsafe" "unsafe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -62,6 +63,17 @@ func main() {
// sleep until we can write more // sleep until we can write more
nevents, err := unix.EpollWait(epfd, events[:], timeout) nevents, err := unix.EpollWait(epfd, events[:], timeout)
if err != nil { if err != nil {
// According to signal(7) on Linux, epoll_wait(2) returns EINTR if
// the system call is interrupted by a SIGSTOP and then resumed by
// a SIGCONT, even if the default signal handler remains in place.
// This is a long-winded way of saying that we must handle EINTR
// here, or else the program may exit after being stopped and then
// resumed by a signal, a debugger, or ptrace.
if e, ok := err.(syscall.Errno); ok {
if e.Temporary() {
continue
}
}
log.Fatalf("epoll wait error: %v", err) log.Fatalf("epoll wait error: %v", err)
} }
if nevents == 1 && events[0].Events&unix.EPOLLOUT == unix.EPOLLOUT { if nevents == 1 && events[0].Events&unix.EPOLLOUT == unix.EPOLLOUT {