Problem: fd leak in tweetnacl with one ctx per thread

Solution: add a crypto [de-]initialiser, refcounted and serialised
through critical sections.
This is necessary as utility APIs such as zmq_curve_keypair also
call into the sodium/tweetnacl libraries and need the initialisation
outside of the zmq context.
Also the libsodium documentation explicitly says that sodium_init
must not be called concurrently from multiple threads, which could
have happened until now. Also the randombytes_close function does
not appear to be thread safe either.
This change guarantees that the library is initialised only once at
any given time across the whole program.
Fixes #2632
This commit is contained in:
Luca Boccassi
2017-07-27 14:43:14 +01:00
parent a7bf010ee2
commit e015a0f8b9
7 changed files with 113 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
@@ -45,12 +45,7 @@
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
#if defined (ZMQ_USE_TWEETNACL)
# include "tweetnacl.h"
#elif defined (ZMQ_USE_LIBSODIUM)
# include "sodium.h"
#endif
#include "random.hpp"
#ifdef ZMQ_HAVE_VMCI
#include <vmci_sockets.h>
@@ -91,15 +86,8 @@ zmq::ctx_t::ctx_t () :
vmci_family = -1;
#endif
scoped_lock_t locker(crypto_sync);
#if defined (ZMQ_USE_TWEETNACL)
// allow opening of /dev/urandom
unsigned char tmpbytes[4];
randombytes(tmpbytes, 4);
#elif defined (ZMQ_USE_LIBSODIUM)
int rc = sodium_init ();
zmq_assert (rc != -1);
#endif
// Initialise crypto library, if needed.
zmq::random_open ();
}
bool zmq::ctx_t::check_tag ()
@@ -131,11 +119,8 @@ zmq::ctx_t::~ctx_t ()
// corresponding io_thread/socket objects.
free (slots);
// If we've done any Curve encryption, we may have a file handle
// to /dev/urandom open that needs to be cleaned up.
#ifdef ZMQ_HAVE_CURVE
randombytes_close ();
#endif
// De-initialise crypto library, if needed.
zmq::random_close ();
// Remove the tag, so that the object is considered dead.
tag = ZMQ_CTX_TAG_VALUE_BAD;