diff -up ./nss/lib/freebl/shvfy.c.block_sigchld ./nss/lib/freebl/shvfy.c --- ./nss/lib/freebl/shvfy.c.block_sigchld 2014-10-23 10:38:01.494609227 -0700 +++ ./nss/lib/freebl/shvfy.c 2014-10-23 10:44:35.395609071 -0700 @@ -45,8 +45,50 @@ #include #include #include -#include #include +#include + +#define __USE_POSIX199309 1 /* need to use posix signal handler */ +#include +#include /* must be after signal.h */ + + +/* + * handler to block our sigchld call to keep from confusing parent apps + */ +static struct sigaction parent_handler; +static int child_pid = 0; + +static void +handle_sigchld(int signum, siginfo_t *sinfo, void *utcx) +{ + int status; + int save_errno = errno; + int ret; + + if ((signum == SIGCHLD) && (sinfo->si_pid == child_pid)) { + waitpid(sinfo->si_pid,&status, 0); + errno = save_errno; + return; + } + + + /* call parent, first set the parents mask */ + ret = sigprocmask(SIG_BLOCK, &parent_handler.sa_mask, NULL); + errno = save_errno; /* restore previous errno. allow parent to change + * errno if it needs to */ + if (ret < 0) { + return; + } + /* now call the parent */ + if (parent_handler.sa_flags & SA_SIGINFO) { + (*parent_handler.sa_sigaction)(signum, sinfo, utcx); + } else { + (*parent_handler.sa_handler)(signum); + } + /* libc/kernel should restore our mask as this point, so we don't + * need to restore the mask we set above. */ +} /* * This function returns an NSPR PRFileDesc * which the caller can read to @@ -72,6 +114,8 @@ bl_OpenUnPrelink(const char *shName, int pid_t child; int argc = 0, argNext = 0; struct stat statBuf; + struct sigaction our_handler; + sigset_t inMask,outMask; int pipefd[2] = {-1,-1}; int ret; @@ -155,6 +199,25 @@ bl_OpenUnPrelink(const char *shName, int goto loser; } + child_pid = 0; + our_handler.sa_flags = SA_SIGINFO; + our_handler.sa_sigaction = handle_sigchld; + sigemptyset(&our_handler.sa_mask); + ret = sigaction(SIGCHLD, &our_handler, &parent_handler); + if (ret < 0) { + goto loser; + } + + /* don't accept a sigchild until we've set out child pid */ + sigemptyset(&inMask); + sigemptyset(&outMask); + sigaddset(&inMask,SIGCHLD); + ret = sigprocmask(SIG_BLOCK, &inMask, &outMask); + if (ret < 0) { + sigaction(SIGCHLD, &parent_handler, NULL); + goto loser; + } + /* use vfork() so we don't trigger the pthread_at_fork() handlers */ child = vfork(); if (child < 0) goto loser; @@ -174,6 +237,8 @@ bl_OpenUnPrelink(const char *shName, int /* avoid at_exit() handlers */ _exit(1); /* shouldn't reach here except on an error */ } + child_pid = child; + sigprocmask(SIG_SETMASK, &outMask, 0); /* child is set,accept signals now */ close(pipefd[1]); pipefd[1] = -1; @@ -218,6 +283,9 @@ bl_CloseUnPrelink( PRFileDesc *file, int /* reap the child */ if (pid) { waitpid(pid, NULL, 0); + /* restore the parent handler */ + sigaction(SIGCHLD, &parent_handler, NULL); + child_pid = 0; } } #endif