[gnutls-devel] [TLS] multiple clients in one process (was: Re: Deployment ... Re: This working group has failed)

Nico Williams nico at cryptonector.com
Sun Dec 1 03:03:14 CET 2013


On Sat, Nov 30, 2013 at 2:58 AM, Nikos Mavrogiannopoulos
<nmav at gnutls.org> wrote:
> On Fri, 2013-11-29 at 18:03 -0600, Nico Williams wrote:
>> It is not safe to use PKCS#11 on the child-side of fork() without
>> [...]
>
> I was referring to his issue. As far as I understood he didn't use PKCS
> #11 at all, so there should be no breakage. When ones uses PKCS #11 in
> gnutls he is (currently) required to call gnutls_pkcs11_reinit() on a
> fork.

Remember, we're talking about layered software.  This might be a
process using PAM and loading multiple PAMs that use GnuTLS, so: which
one of them should reinit GnuTLS?  No, the library *must*
self-[re-]initialize.  Always.  Period.  Full stop.  There must be no
question of some caller being first to initialize, there must be no
way for two callers to step on each others' toes by re-initializing
the library and destroying the other caller's state.

Yes, nothing should fork() and try to use a non-async-signal-safe
interface on the child-side of the fork.  That does give a library an
excuse to have undefined fork-safety.  But it's much, much better to
have well-defined fork-safety.  It's OK to lose access to all
objects/whatever on the child-side of fork(), and it's even OK to leak
them (since the data structures in question may not be in a consistent
state, the library may not be able to walk them, and free() is not
async-signal-safe).  It'd even be better to abort() if called on the
child-side of fork() than to have undefined behavior -- after all,
callers of fork() are not supposed to call async-signal-unsafe code.
The key is to have deterministic and *noticeable* behavior.

The recipe is simple:

 - use a InitOnceInitialize/pthread_once interface to initialize once as needed
   (don't require that the caller initialize the library)

 - use a pthread_atfork() child-side handler to reinitialize all
global state (all locks, ...), leaking all of it OR to set a flag,
then abort() if called with this flag set

Nico
--



More information about the Gnutls-devel mailing list