From: Miroslav Lichvar Date: Wed, 4 Apr 2018 07:07:10 +0000 (+0200) Subject: ntp: fix handling of socket errors with error queue X-Git-Tag: 3.3~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=19f3ab222586274e60e62eb35b3f68beb39acbb8;p=thirdparty%2Fchrony.git 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. --- diff --git a/ntp_io.c b/ntp_io.c index d63eb1d3..5c8c47a9 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 202e7c20..f4b532d9 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 */