winpr: fix CreateProcess signal handler issues

The calling thread of CreateProcess can be in any library and
can have arbitrary signal masks and handlers.

We now save the caller's mask and  block all signals before forking.
After fork:
- child resets the handlers and unblocks all signals.
- parent restores the caller's original signal mask.
This commit is contained in:
Norbert Federa 2015-07-02 11:21:09 +02:00
parent 873a25621d
commit c84e90bf06

View File

@ -80,6 +80,14 @@
#include "../handle/handle.h"
#include "../security/security.h"
#ifndef NSIG
#ifdef SIGMAX
#define NSIG SIGMAX
#else
#define NSIG 64
#endif
#endif
char** EnvironmentBlockToEnvpA(LPCH lpszEnvironmentBlock)
{
char* p;
@ -210,6 +218,9 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags,
WINPR_ACCESS_TOKEN* token;
LPTCH lpszEnvironmentBlock;
BOOL ret = FALSE;
sigset_t oldSigMask;
sigset_t newSigMask;
BOOL restoreSigMask = FALSE;
pid = 0;
numArgs = 0;
@ -241,6 +252,10 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags,
if (NULL == filename)
goto finish;
/* block all signals so that the child can safely reset the caller's handlers */
sigfillset(&newSigMask);
restoreSigMask = !pthread_sigmask(SIG_SETMASK, &newSigMask, &oldSigMask);
/* fork and exec */
pid = fork();
@ -254,16 +269,33 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags,
if (pid == 0)
{
/* child process */
#ifndef __sun
int maxfd;
#endif
int fd;
int sig;
sigset_t set;
struct sigaction act;
/* set default signal handlers */
memset(&act, 0, sizeof(act));
act.sa_sigaction = SIG_DFL;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
for (sig = 1; sig < NSIG; sig++)
sigaction(sig, &act, NULL);
/* unblock all signals */
sigfillset(&set);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
#ifdef __sun
closefrom(3);
#else
int maxfd;
#ifdef F_MAXFD // on some BSD derivates
maxfd = fcntl(0, F_MAXFD);
#else
maxfd = sysconf(_SC_OPEN_MAX);
#endif
int fd;
for(fd=3; fd<maxfd; fd++)
close(fd);
#endif // __sun
@ -324,6 +356,12 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags,
ret = TRUE;
finish:
/* restore caller's original signal mask */
if (restoreSigMask)
pthread_sigmask(SIG_SETMASK, &oldSigMask, NULL);
free(filename);
if (pArgs)