Bug 224503 - rpcbind: Broken in the face of signal termination
Summary: rpcbind: Broken in the face of signal termination
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: Conrad Meyer
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-12-21 18:35 UTC by Conrad Meyer
Modified: 2018-01-02 17:26 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Conrad Meyer freebsd_committer freebsd_triage 2017-12-21 18:35:47 UTC
Rpcbind may crash in signal-induced termination.

E.g.:

> (gdb) bt
> ...
> #12 __free (ptr=0x8006f8140) at jemalloc_jemalloc.c:1277
> #13 0x0000000800d4c8e7 in vector_free (esize=<optimized out>, vec=<optimized out>, count=<optimized out>, esize=<optimized out>, free_elem=<optimized out>)
>     at /b/mnt/src/lib/libc/net/nsdispatch.c:250
> #14 nss_atexit () at /b/mnt/src/lib/libc/net/nsdispatch.c:577
> #15 0x0000000800d4d5b9 in __cxa_finalize (dso=0x0) at /b/mnt/src/lib/libc/stdlib/atexit.c:200
> #16 0x0000000800cfe1ac in exit (status=2) at /b/mnt/src/lib/libc/stdlib/exit.c:67
> #17 0x0000000000404df5 in terminate (signum=-26832) at /b/mnt/src/usr.sbin/rpcbind/rpcbind.c:860
> #18 0x000000080337f67b in handle_signal (actp=<optimized out>, sig=15, info=0x7fffffffa9f0, ucp=0x7fffffffa680) at /b/mnt/src/lib/libthr/thread/thr_sig.c:240
> #19 0x000000080337f263 in thr_sighandler (sig=15, info=0x7fffffffa9f0, _ucp=0x800700210) at /b/mnt/src/lib/libthr/thread/thr_sig.c:183

rpcbind got a sig 15 (TERM) and attempted to call exit(3) from a signal handler.  But, exit(3) is not an async-signal safe function.  Probably these crashes are the result of the program manipulating jemalloc internal structures at the time the SIGTERM is delivered and handled unsafely.

The cause can be explained:

195         /* catch the usual termination signals for graceful exit */
196         (void) signal(SIGCHLD, reap);
197         (void) signal(SIGINT, terminate);
198         (void) signal(SIGTERM, terminate);
199         (void) signal(SIGQUIT, terminate);
...

758 /*
759  * Catch the signal and die
760  */
761 static void
762 terminate(int signum __unused)
763 {
764         close(rpcbindlockfd);
765 #ifdef WARMSTART
766         syslog(LOG_ERR,
767             "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"",
768             signum);
769         write_warmstart();      /* Dump yourself */
770 #endif
771         exit(2);
772 }
...

// close(2) is async-safe -- rpcbindlockfd must be initalized before the signal is
// delivered, though.
//
// syslog() is definitely not safe.
//
// write_warmstart() uses fopen(3), syslog(3), ... definitely not safe.
//
// Finally, exit(3) itself is not safe either.

857 void
858 reap(int dummy __unused)
859 {
860         int save_errno = errno;
861
862         while (wait3(NULL, WNOHANG, NULL) > 0)
863                 ;
864         errno = save_errno;
865 }

// wait(2) and waitpid(2) are allowed, but wait3() is not documented as allowed in
// sigaction(2).  It likely is allowed, though, given it is implemented identically
// to wait(2) (in terms of wait4(2)).  So `reap` for SIGCHLD is probably ok.
Comment 1 Conrad Meyer freebsd_committer freebsd_triage 2017-12-21 18:37:08 UTC
Tentatively throwing at -fs@ as rpcbind is a component of NFS
Comment 2 Conrad Meyer freebsd_committer freebsd_triage 2018-01-01 21:40:38 UTC
https://reviews.freebsd.org/D13728
Comment 3 commit-hook freebsd_committer freebsd_triage 2018-01-02 00:48:38 UTC
A commit references this bug:

Author: cem
Date: Tue Jan  2 00:48:19 UTC 2018
New revision: 327482
URL: https://svnweb.freebsd.org/changeset/base/327482

Log:
  rpcbind: Do not use signal-unsafe functions in SIGTERM handler

  syslog(3), routines used in write_warmstart(), and exit(3) are all
  signal-unsafe.  Instead, set a signal-safe flag and check the flag in the
  rpcbind main loop to shutdown safely.

  PR:		224503
  Reviewed by:	kib, markj
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D13728

Changes:
  head/usr.sbin/rpcbind/rpcb_svc_com.c
  head/usr.sbin/rpcbind/rpcbind.c
  head/usr.sbin/rpcbind/rpcbind.h
Comment 4 commit-hook freebsd_committer freebsd_triage 2018-01-02 01:48:41 UTC
A commit references this bug:

Author: cem
Date: Tue Jan  2 01:48:11 UTC 2018
New revision: 327483
URL: https://svnweb.freebsd.org/changeset/base/327483

Log:
  rpcbind: Fix build

  Add missed unistd.h include.  Not sure where it was lost; I believe it
  compiled before I submitted the change.

  PR:		224503
  Reported by:	Cy Schubert <Cy.Schubert AT komquats.com>
  Sponsored by:	Dell EMC Isilon

Changes:
  head/usr.sbin/rpcbind/rpcb_svc_com.c
Comment 5 commit-hook freebsd_committer freebsd_triage 2018-01-02 17:26:10 UTC
A commit references this bug:

Author: cem
Date: Tue Jan  2 17:25:13 UTC 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

Changes:
  head/usr.sbin/rpcbind/rpcb_svc_com.c
  head/usr.sbin/rpcbind/rpcbind.c
  head/usr.sbin/rpcbind/rpcbind.h