[gnutls-devel] [TLS] multiple clients in one process (was: Re: Deployment ... Re: This working group has failed)
nico at cryptonector.com
Thu Nov 28 01:16:03 CET 2013
On Wed, Nov 27, 2013 at 5:58 PM, Andy Lutomirski <luto at amacapital.net> wrote:
> [stripped tls at ietf.org]
> On Wed, Nov 27, 2013 at 3:54 PM, Nico Williams <nico at cryptonector.com> wrote:
>> All of this is off-topic for this list. I'll post a reply anyways, and
>> I apologize to the list.
>> On Tue, Nov 19, 2013 at 10:24:03PM -0800, Andy Lutomirski wrote:
>>> [...]. gnutls_global_init is documented as being
>>> unsafe if called from multiple threads, which seems silly.
>> Initialization is not thread-safe in OpenSSL either. This is a terrible
>> thing. It *can* be made thread-safe, so there's no excuse for it not
>> being thread-safe.
>>> GnuTLS has gnutls_pkcs11_init, which is rather impolite -- it
>>> manipulates global state, and it sometimes causes things to
>>> malfunction after forking. [...]
>> PKCS#11 is by definition fork-unsafe (see the PKCS#11 docs).
>> Any API dealing with "tokens" (in the PKCS#11 sense) is bound to be
>> fork-unsafe for at least open sessions/objects on tokens that require
>> authentication (PIN). That's because any library using file descriptors
>> where offset is not a relevant concept will necessarily be fork-unsafe
>> by default. And: any stateful cryptography library (e.g., an
>> implementation of TLS) will tend to be fork-unsafe (imagine a process
>> trying to use a TLS connection on both sides of a fork()!).
> I agree with all of this, except that I don't think that GnuTLS has
> any business even trying to use PKCS11 unless something explicitly
> requests it. I've had all kinds of problems with libvmime causing
> GnuTLS to start interfacing with some mysterious GNOME PKCS11 token,
> when I don't want any of the above. It breaks fork for no good
> reason. (I'm not even trying to do crypto in the child -- I just want
> to avoid getting all kinds of random errors.)
The thing to do is to arrange to re-initialize on the child-side of
fork(). I don't mean lock-everything in a pre-fork() atfork handler,
then unlock everything in the parent and child handlers -- that's not
safe. I mean: reset all global state in the PKCS#11 implementation on
the child-side of fork() in a child atfork handler -- yes, this means
leaking memory (and its contents), but hopefully the child will
immediately _exit() or exec*(). Also, O_CLOEXEC should be safely set
on all file descriptors used by the PKCS#11 implementation.
>> Of course, that's all rather POSIX-specific, but the problem is inherent
>> to any fork()-like interface. Use posix_spawn() or similar, then you
>> won't have to worry about fork-safety at all. Long ago I used to think
>> fork+exec superior to spawn since spawn was easy to implement in terms
>> of fork+exec, but in truth fork() is a dangerous and difficult-to-use
>> interface -- the only safe things to do on the child side of fork() are:
>> async-signal-safe things, culminating in _exit() or exec*() ASAP.
> Except that glibc's posix_spawn is screwed up wrt atfork. There are
> some bugs open about it.
That's because it needs a real vfork() (or at least to tell fork() not
to run atfork handlers when called from posix_spawn()). Anyways, it
should be possible to write atfork handlers that don't screw up a
posix_spawn() user. If one really does use only async-signal-safe
code in the atfork handlers, then that's really not that hard. But of
course, you've no idea what atfork handlers have been set...
More information about the Gnutls-devel