[stunnel-users] [PATCH] only use aysnc-signal-safe functions after fork

Michal Trojnara Michal.Trojnara at mirt.net
Wed Oct 14 19:01:00 CEST 2015


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Philip,

I didn't use the patch itself, but I implemented a similar
functionality in stunnel 5.25b2:
https://www.stunnel.org/downloads.html

Best regards,
	Mike

On 14.10.2015 10:41, Philip Craig wrote:
> POSIX requires that multi-threaded processes only use
> async-signal-safe functions after calling fork(). For more info on
> the problems this avoids, see the rationale at: 
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfo
rk.html
>
>  The specific problem this patch solves is that, when there are
> multiple simultaneous requests, stunnel is often hanging on a futex
> syscall when a child process calls free as a result of
> tls_alloc().
> 
> This problem is experienced when using uClibc. I haven't tested,
> but I believe the malloc implementation in glibc does not have this
> problem.
> 
> 
> --- stunnel-5.24.orig/src/client.c +++ stunnel-5.24/src/client.c @@
> -1100,6 +1100,8 @@ NOEXPORT SOCKET connect_local(CLI *c) {
> 
> NOEXPORT SOCKET connect_local(CLI *c) { /* spawn local process */ 
> char *name, host[40], port[6]; +    char *env[10]; +    int i,
> envc; int fd[2], pid; X509 *peer_cert; #ifdef HAVE_PTHREAD_SIGMASK 
> @@ -1115,19 +1117,55 @@ NOEXPORT SOCKET connect_local(CLI *c) { }
> else if(make_sockets(fd)) longjmp(c->err, 1); +
> set_nonblock(fd[1], 0); /* switch back to blocking mode */ + +
> envc = 0; + +    if(!getnameinfo(&c->peer_addr.sa,
> c->peer_addr_len, +            host, 40, port, 6,
> NI_NUMERICHOST|NI_NUMERICSERV)) { +        /* just don't set these
> variables if getnameinfo() fails */ +        env[envc++] =
> str_printf("REMOTE_HOST=%s", host); +        env[envc++] =
> str_printf("REMOTE_PORT=%s", port); +
> if(c->opt->option.transparent_src) { +#ifndef LIBDIR +#define
> LIBDIR "." +#endif +#ifdef MACH64 +            env[envc++] =
> str_dup("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); +
> env[envc++] = str_dup("LD_PRELOAD_64=" LIBDIR "/" MACH64
> "/libstunnel.so"); +#elif __osf /* for Tru64 _RLD_LIST is used
> instead */ +            env[envc++] = str_dup("_RLD_LIST=" LIBDIR
> "/libstunnel.so:DEFAULT"); +#else +            env[envc++] =
> str_dup("LD_PRELOAD=" LIBDIR "/libstunnel.so"); +#endif +        } 
> +    } + +    if(c->ssl) { +
> peer_cert=SSL_get_peer_certificate(c->ssl); +        if(peer_cert)
> { +
> name=X509_NAME2text(X509_get_subject_name(peer_cert)); +
> env[envc++] = str_printf("SSL_CLIENT_DN=%s", name); +
> name=X509_NAME2text(X509_get_issuer_name(peer_cert)); +
> env[envc++] = str_printf("SSL_CLIENT_I_DN=%s", name); +
> X509_free(peer_cert); +        } +    } + +    env[envc] = NULL;
> 
> pid=fork(); c->pid=(unsigned long)pid; switch(pid) { case -1:    /*
> error */ +        for (i = 0; i < envc; i++) +
> str_free(env[i]); closesocket(fd[0]); closesocket(fd[1]); 
> ioerror("fork"); longjmp(c->err, 1); case  0:    /* child */ -
> tls_alloc(NULL, c->tls, NULL); /* reuse thread-local storage */ 
> closesocket(fd[0]); -        set_nonblock(fd[1], 0); /* switch back
> to blocking mode */ /* dup2() does not copy FD_CLOEXEC flag */ 
> dup2(fd[1], 0); dup2(fd[1], 1); @@ -1135,36 +1173,6 @@ NOEXPORT
> SOCKET connect_local(CLI *c) { dup2(fd[1], 2); closesocket(fd[1]);
> /* not really needed due to FD_CLOEXEC */
> 
> -        if(!getnameinfo(&c->peer_addr.sa, c->peer_addr_len, -
> host, 40, port, 6, NI_NUMERICHOST|NI_NUMERICSERV)) { -
> /* just don't set these variables if getnameinfo() fails */ -
> putenv(str_printf("REMOTE_HOST=%s", host)); -
> putenv(str_printf("REMOTE_PORT=%s", port)); -
> if(c->opt->option.transparent_src) { -#ifndef LIBDIR -#define
> LIBDIR "." -#endif -#ifdef MACH64 -
> putenv("LD_PRELOAD_32=" LIBDIR "/libstunnel.so"); -
> putenv("LD_PRELOAD_64=" LIBDIR "/" MACH64 "/libstunnel.so"); -#elif
> __osf /* for Tru64 _RLD_LIST is used instead */ -
> putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT"); -#else -
> putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so"); -#endif -
> } -        } - -        if(c->ssl) { -
> peer_cert=SSL_get_peer_certificate(c->ssl); -
> if(peer_cert) { -
> name=X509_NAME2text(X509_get_subject_name(peer_cert)); -
> putenv(str_printf("SSL_CLIENT_DN=%s", name)); -
> name=X509_NAME2text(X509_get_issuer_name(peer_cert)); -
> putenv(str_printf("SSL_CLIENT_I_DN=%s", name)); -
> X509_free(peer_cert); -            } -        } #ifdef
> HAVE_PTHREAD_SIGMASK sigemptyset(&newmask); 
> sigprocmask(SIG_SETMASK, &newmask, NULL); @@ -1176,11 +1184,13 @@
> NOEXPORT SOCKET connect_local(CLI *c) { signal(SIGTERM, SIG_DFL); 
> signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); -
> execvp(c->opt->exec_name, c->opt->exec_args); +
> execve(c->opt->exec_name, c->opt->exec_args, env); 
> ioerror(c->opt->exec_name); /* execvp failed */ _exit(1); default:
> /* parent */ s_log(LOG_INFO, "Local mode child started (PID=%lu)",
> c->pid); +        for (i = 0; i < envc; i++) +
> str_free(env[i]); closesocket(fd[1]); return fd[0]; } 
> _______________________________________________ stunnel-users
> mailing list stunnel-users at stunnel.org 
> https://www.stunnel.org/cgi-bin/mailman/listinfo/stunnel-users
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQIcBAEBCAAGBQJWHopMAAoJEC78f/DUFuAUJnwQAKkbfZhC5ctCfJstNQli2syF
oEVo1o0LADUmUGrDYyvmlKI9zZPFshZI0nYSYqPsy8HShSgPFtFn5eP37tl52/6n
ydZ2GtzJS08gVtltB1Rt7TbvX1aAYjwT7YIE1yQi6VzOQNgUYciWJqslB7u4AEuO
dtkx7wPf5vMiOkAJOShR3GVLkjnM9cRDQHo2aAGTMlj2w00NEzOjbkrsU9Ui1IS7
CfS9kYRx75RYuvoDlXwS3S9ri1ZtwmWM2LsF6Au5pfsY6SDHcPrE7wIjzciYskOR
IaA00xWeVbWStVBcGkUAu+a5zcHorgqEPBAPBxrofv45PEiRS311O+Tmlyo+lxrf
NHiSdmHin+4Ggdmg2g5by57YXI7vMJlN6hLuTgZV1SLeoX9nWf5VhfU2eI3EZXG1
g4DIsdtUOkZoOis85pvYTQ7B/bwj5rk+hqFrI3tBQw11NzARjD6mQzBTCyiKSuZI
pB9vrNlPFb1nXfciym/u5p3CVHjSK3pj+2ehQ/B/4szA9iClYrNQhAoldDQvheQc
jthRCEFKXF6obw+PVo/iKTOdGz3c0YKLYrwiiuBN3RvUtnIqDe3WPIyO/Kj+R7wJ
PZIjIuUPElQBkskB4RIpkglDE5dn5O1qAGSMWGQs3zFVfvBTu3uso9mqm6hTX1qG
Ij8h8K+Il9JtwftizDJW
=5GkW
-----END PGP SIGNATURE-----


More information about the stunnel-users mailing list