mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-22 18:56:38 +00:00
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
This commit is contained in:
parent
8b081eaa55
commit
35f85edc80
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327495
|
@ -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);
|
||||
|
|
|
@ -79,6 +79,7 @@ static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
|
|||
/* 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 netconfig *nconf,
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue