From 19f3ab222586274e60e62eb35b3f68beb39acbb8 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 4 Apr 2018 09:07:10 +0200 Subject: [PATCH] ntp: fix handling of socket errors with error queue In the next Linux version the recvmmsg() system call will be probably fixed to not return socket errors (e.g. due to ICMP) when reading from the error queue. The NTP I/O code assumed this was the correct behavior. When the system call is fixed, a socket error on a client socket will cause chronyd to enter a busy loop consuming the CPU until the receive timeout is reached (8 seconds by default). Use getsockopt(SO_ERROR) to clear the socket error when reading from the error queue failed. --- ntp_io.c | 14 ++++++++++++++ sys_linux.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ntp_io.c b/ntp_io.c index d63eb1d..5c8c47a 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -717,6 +717,20 @@ read_from_socket(int sock_fd, int event, void *anything) #endif if (status < 0) { +#ifdef HAVE_LINUX_TIMESTAMPING + /* If reading from the error queue failed, the exception should be + for a socket error. Clear the error to avoid a busy loop. */ + if (flags & MSG_ERRQUEUE) { + int error = 0; + socklen_t len = sizeof (error); + + if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len)) + DEBUG_LOG("Could not get SO_ERROR"); + if (error) + errno = error; + } +#endif + DEBUG_LOG("Could not receive from fd %d : %s", sock_fd, strerror(errno)); return; diff --git a/sys_linux.c b/sys_linux.c index 202e7c2..f4b532d 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -497,7 +497,7 @@ SYS_Linux_EnableSystemCallFilter(int level) SCMP_SYS(lseek), SCMP_SYS(rename), SCMP_SYS(stat), SCMP_SYS(stat64), SCMP_SYS(statfs), SCMP_SYS(statfs64), SCMP_SYS(unlink), /* Socket */ - SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname), + SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname), SCMP_SYS(getsockopt), SCMP_SYS(recvfrom), SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg), SCMP_SYS(sendmmsg), SCMP_SYS(sendmsg), SCMP_SYS(sendto), /* TODO: check socketcall arguments */