From owner-svn-src-all@freebsd.org Tue Jan 2 17:25:14 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8FA8FEAFF9E; Tue, 2 Jan 2018 17:25:14 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 676DD69EA0; Tue, 2 Jan 2018 17:25:14 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w02HPDEB068480; Tue, 2 Jan 2018 17:25:13 GMT (envelope-from cem@FreeBSD.org) Received: (from cem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w02HPDaj068477; Tue, 2 Jan 2018 17:25:13 GMT (envelope-from cem@FreeBSD.org) Message-Id: <201801021725.w02HPDaj068477@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cem set sender to cem@FreeBSD.org using -f From: Conrad Meyer Date: Tue, 2 Jan 2018 17:25:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r327495 - head/usr.sbin/rpcbind X-SVN-Group: head X-SVN-Commit-Author: cem X-SVN-Commit-Paths: head/usr.sbin/rpcbind X-SVN-Commit-Revision: 327495 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jan 2018 17:25:14 -0000 Author: cem Date: Tue Jan 2 17:25:13 2018 New Revision: 327495 URL: https://svnweb.freebsd.org/changeset/base/327495 Log: rpcbind: Fix race in signal termination If a signal was delivered while the main thread was not in poll(2) and after check was performed, we could reenter poll and never detect termination. Fix this with the pipefd trick. (This race was introduced very recently, in r327482.) PR: 224503 Reported by: kib Reviewed by: kib, markj Sponsored by: Dell EMC Isilon Modified: head/usr.sbin/rpcbind/rpcb_svc_com.c head/usr.sbin/rpcbind/rpcbind.c head/usr.sbin/rpcbind/rpcbind.h Modified: head/usr.sbin/rpcbind/rpcb_svc_com.c ============================================================================== --- head/usr.sbin/rpcbind/rpcb_svc_com.c Tue Jan 2 16:50:57 2018 (r327494) +++ head/usr.sbin/rpcbind/rpcb_svc_com.c Tue Jan 2 17:25:13 2018 (r327495) @@ -1101,7 +1101,7 @@ void my_svc_run(void) { size_t nfds; - struct pollfd pollfds[FD_SETSIZE]; + struct pollfd pollfds[FD_SETSIZE + 1]; int poll_ret, check_ret; int n; #ifdef SVC_RUN_DEBUG @@ -1112,6 +1112,9 @@ my_svc_run(void) for (;;) { p = pollfds; + p->fd = terminate_rfd; + p->events = MASKVAL; + p++; for (n = 0; n <= svc_maxfd; n++) { if (FD_ISSET(n, &svc_fdset)) { p->fd = n; @@ -1130,23 +1133,26 @@ my_svc_run(void) fprintf(stderr, ">\n"); } #endif - switch (poll_ret = poll(pollfds, nfds, 30 * 1000)) { + poll_ret = poll(pollfds, nfds, 30 * 1000); + + if (doterminate != 0) { + close(rpcbindlockfd); +#ifdef WARMSTART + syslog(LOG_ERR, + "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"", + (int)doterminate); + write_warmstart(); /* Dump yourself */ +#endif + exit(2); + } + + switch (poll_ret) { case -1: /* * We ignore all errors, continuing with the assumption * that it was set by the signal handlers (or any * other outside event) and not caused by poll(). */ - if (doterminate != 0) { - close(rpcbindlockfd); -#ifdef WARMSTART - syslog(LOG_ERR, - "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"", - (int)doterminate); - write_warmstart(); /* Dump yourself */ -#endif - exit(2); - } case 0: cleanfds = svc_fdset; __svc_clean_idle(&cleanfds, 30, FALSE); Modified: head/usr.sbin/rpcbind/rpcbind.c ============================================================================== --- head/usr.sbin/rpcbind/rpcbind.c Tue Jan 2 16:50:57 2018 (r327494) +++ head/usr.sbin/rpcbind/rpcbind.c Tue Jan 2 17:25:13 2018 (r327495) @@ -79,6 +79,7 @@ static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Co /* Global variables */ int debugging = 0; /* Tell me what's going on */ int doabort = 0; /* When debugging, do an abort on errors */ +int terminate_rfd; /* Pipefd to wake on signal */ volatile sig_atomic_t doterminate = 0; /* Terminal signal received */ rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ int rpcbindlockfd; @@ -101,6 +102,7 @@ static struct sockaddr **bound_sa; static int ipv6_only = 0; static int nhosts = 0; static int on = 1; +static int terminate_wfd; #ifdef WARMSTART /* Local Variable */ @@ -133,6 +135,7 @@ main(int argc, char *argv[]) void *nc_handle; /* Net config handle */ struct rlimit rl; int maxrec = RPC_MAXDATASIZE; + int error, fds[2]; parseargs(argc, argv); @@ -192,6 +195,16 @@ main(int argc, char *argv[]) } endnetconfig(nc_handle); + /* + * Allocate pipe fd to wake main thread from signal handler in non-racy + * way. + */ + error = pipe(fds); + if (error != 0) + err(1, "pipe failed"); + terminate_rfd = fds[0]; + terminate_wfd = fds[1]; + /* catch the usual termination signals for graceful exit */ (void) signal(SIGCHLD, reap); (void) signal(SIGINT, terminate); @@ -761,8 +774,13 @@ rbllist_add(rpcprog_t prog, rpcvers_t vers, struct net static void terminate(int signum) { + char c = '\0'; + ssize_t wr; doterminate = signum; + wr = write(terminate_wfd, &c, 1); + if (wr < 1) + _exit(2); } void Modified: head/usr.sbin/rpcbind/rpcbind.h ============================================================================== --- head/usr.sbin/rpcbind/rpcbind.h Tue Jan 2 16:50:57 2018 (r327494) +++ head/usr.sbin/rpcbind/rpcbind.h Tue Jan 2 17:25:13 2018 (r327495) @@ -70,6 +70,7 @@ struct r_rmtcall_args { extern int debugging; extern int doabort; +extern int terminate_rfd; extern volatile sig_atomic_t doterminate; #ifdef LIBWRAP extern int libwrap;