0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-26 23:01:04 +08:00

Problem: calling randombytes_close with libsodium can crash Contexts in other threads (#4242)

* add opt-out for randombytes_close

Problem: randombytes_close is either a no-op or unsafe when a Context is running.

Unfortunately, there does not appear to be a single always correct choice,
so let builders pick between two not-great options.

Opting out can leak an FD on /dev/urandom which may need to be closed explicitly.
However, with the default behavior,
using multiple contexts with CURVE can crash with no application-level workaround available.

randombytes_close is not threadsafe and calling it while still in use by a Context can cause a crash.

For implementations using /dev/[u]random, this can leave up to one leftover FD per process.

The libsodium docs suggest that this function rarely needs to be called explicitly.
This commit is contained in:
Min RK 2021-08-13 16:11:29 +02:00 committed by GitHub
parent f6e99e72ec
commit bcb659e00e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 0 deletions

View File

@ -258,6 +258,7 @@ endif()
option(WITH_LIBSODIUM "Use libsodium instead of built-in tweetnacl" ON) option(WITH_LIBSODIUM "Use libsodium instead of built-in tweetnacl" ON)
option(WITH_LIBSODIUM_STATIC "Use static libsodium library" OFF) option(WITH_LIBSODIUM_STATIC "Use static libsodium library" OFF)
option(ENABLE_LIBSODIUM_RANDOMBYTES_CLOSE "Automatically close libsodium randombytes. Not threadsafe without getrandom()" ON)
option(ENABLE_CURVE "Enable CURVE security" ON) option(ENABLE_CURVE "Enable CURVE security" ON)
if(ENABLE_CURVE) if(ENABLE_CURVE)
@ -271,6 +272,9 @@ if(ENABLE_CURVE)
endif() endif()
set(ZMQ_USE_LIBSODIUM 1) set(ZMQ_USE_LIBSODIUM 1)
set(ZMQ_HAVE_CURVE 1) set(ZMQ_HAVE_CURVE 1)
if (ENABLE_LIBSODIUM_RANDOMBYTES_CLOSE)
set(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE 1)
endif()
else() else()
message( message(
WARNING WARNING

View File

@ -550,6 +550,20 @@ AS_IF([test "x$with_libsodium" = "xyes"], [
AC_ARG_ENABLE([curve], AC_ARG_ENABLE([curve],
[AS_HELP_STRING([--disable-curve], [disable CURVE security [default=no]])]) [AS_HELP_STRING([--disable-curve], [disable CURVE security [default=no]])])
AC_ARG_ENABLE(
[libsodium_randombytes_close],
[AS_HELP_STRING(
[--disable-libsodium_randombytes_close],
[Do not call libsodium randombytes_close() when terminating contexts.
If disabled, may leave one FD open on /dev/urandom
until randombytes_close() is called explicitly,
but fixes a crash when multiple contexts are used with CURVE.
Has no effect when getrandom() is available. [default=enabled]]
)],
[],
[enable_libsodium_randombytes_close=yes]
)
if test "x$enable_curve" = "xno"; then if test "x$enable_curve" = "xno"; then
curve_library="" curve_library=""
AC_MSG_NOTICE([CURVE security is disabled]) AC_MSG_NOTICE([CURVE security is disabled])
@ -558,6 +572,12 @@ elif test "x$with_libsodium" = "xyes"; then
AC_MSG_NOTICE([Using libsodium for CURVE security]) AC_MSG_NOTICE([Using libsodium for CURVE security])
AC_DEFINE(ZMQ_HAVE_CURVE, [1], [Using curve encryption]) AC_DEFINE(ZMQ_HAVE_CURVE, [1], [Using curve encryption])
AC_DEFINE(ZMQ_USE_LIBSODIUM, [1], [Using libsodium for curve encryption]) AC_DEFINE(ZMQ_USE_LIBSODIUM, [1], [Using libsodium for curve encryption])
if test "x$enable_libsodium_randombytes_close" = "xyes"; then
AC_DEFINE(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE, [1], [Automatically close libsodium randombytes. Not threadsafe without getrandom()])
else
AC_MSG_NOTICE([Disabling libsodium randombytes_close(). randombytes_close() may need to be called in applcation code.])
fi
curve_library="libsodium" curve_library="libsodium"
enable_curve="yes" enable_curve="yes"

View File

@ -151,8 +151,13 @@ static void manage_random (bool init_)
if (init_) { if (init_) {
int rc = sodium_init (); int rc = sodium_init ();
zmq_assert (rc != -1); zmq_assert (rc != -1);
#if defined(ZMQ_LIBSODIUM_RANDOMBYTES_CLOSE)
} else { } else {
// randombytes_close either a no-op or not threadsafe
// doing this without refcounting can cause crashes
// if called while a context is active
randombytes_close (); randombytes_close ();
#endif
} }
#else #else
LIBZMQ_UNUSED (init_); LIBZMQ_UNUSED (init_);