summaryrefslogtreecommitdiff
path: root/src/lib/crypt_ops
diff options
context:
space:
mode:
authorGeorge Kadianakis <desnacked@riseup.net>2019-04-05 14:52:36 +0300
committerGeorge Kadianakis <desnacked@riseup.net>2019-04-05 14:52:36 +0300
commitb371ea5b0eaca7affed4cdc39d68a34ad8c47c0a (patch)
treed3a1a734294239bcaccfe8c73c904bc002c90e3a /src/lib/crypt_ops
parent574c20767059a9c39b33181a4792ac4aa7c71ba4 (diff)
parent76912bf140ec61856c0bb0d25354283d024229f5 (diff)
downloadtor-b371ea5b0eaca7affed4cdc39d68a34ad8c47c0a.tar.gz
tor-b371ea5b0eaca7affed4cdc39d68a34ad8c47c0a.zip
Merge branch 'tor-github/pr/761'
Diffstat (limited to 'src/lib/crypt_ops')
-rw-r--r--src/lib/crypt_ops/crypto_init.c6
-rw-r--r--src/lib/crypt_ops/crypto_rand_fast.c65
2 files changed, 68 insertions, 3 deletions
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index cf491f32d1..5c2780b2ca 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -152,6 +152,12 @@ crypto_prefork(void)
#ifdef ENABLE_NSS
crypto_nss_prefork();
#endif
+ /* It is not safe to share a fast_rng object across a fork boundary unless
+ * we actually have zero-on-fork support in map_anon.c. If we have
+ * drop-on-fork support, we will crash; if we have neither, we will yield
+ * a copy of the parent process's rng, which is scary and insecure.
+ */
+ destroy_thread_fast_rng();
}
/** Run operations that the crypto library requires to be happy again
diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c
index 760e1025ed..01817c618f 100644
--- a/src/lib/crypt_ops/crypto_rand_fast.c
+++ b/src/lib/crypt_ops/crypto_rand_fast.c
@@ -46,8 +46,25 @@
#include "lib/log/util_bug.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include <string.h>
+#ifdef NOINHERIT_CAN_FAIL
+#define CHECK_PID
+#endif
+
+#ifdef CHECK_PID
+#define PID_FIELD_LEN sizeof(pid_t)
+#else
+#define PID_FIELD_LEN 0
+#endif
+
/* Alias for CRYPTO_FAST_RNG_SEED_LEN to make our code shorter.
*/
#define SEED_LEN (CRYPTO_FAST_RNG_SEED_LEN)
@@ -59,7 +76,7 @@
/* The number of random bytes that we can yield to the user after each
* time we fill a crypto_fast_rng_t's buffer.
*/
-#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN)
+#define BUFLEN (MAPLEN - 2*sizeof(uint16_t) - SEED_LEN - PID_FIELD_LEN)
/* The number of buffer refills after which we should fetch more
* entropy from crypto_strongest_rand().
@@ -82,6 +99,11 @@ struct crypto_fast_rng_t {
uint16_t n_till_reseed;
/** How many bytes are remaining in cbuf.bytes? */
uint16_t bytes_left;
+#ifdef CHECK_PID
+ /** Which process owns this fast_rng? If this value is zero, we do not
+ * need to test the owner. */
+ pid_t owner;
+#endif
struct cbuf {
/** The seed (key and IV) that we will use the next time that we refill
* cbuf. */
@@ -130,16 +152,32 @@ crypto_fast_rng_new(void)
crypto_fast_rng_t *
crypto_fast_rng_new_from_seed(const uint8_t *seed)
{
+ unsigned inherit = INHERIT_RES_KEEP;
/* We try to allocate this object as securely as we can, to avoid
* having it get dumped, swapped, or shared after fork.
*/
crypto_fast_rng_t *result = tor_mmap_anonymous(sizeof(*result),
- ANONMAP_PRIVATE | ANONMAP_NOINHERIT);
-
+ ANONMAP_PRIVATE | ANONMAP_NOINHERIT,
+ &inherit);
memcpy(result->buf.seed, seed, SEED_LEN);
/* Causes an immediate refill once the user asks for data. */
result->bytes_left = 0;
result->n_till_reseed = RESEED_AFTER;
+#ifdef CHECK_PID
+ if (inherit == INHERIT_RES_KEEP) {
+ /* This value will neither be dropped nor zeroed after fork, so we need to
+ * check our pid to make sure we are not sharing it across a fork. This
+ * can be expensive if the pid value isn't cached, sadly.
+ */
+ result->owner = getpid();
+ }
+#elif defined(_WIN32)
+ /* Windows can't fork(), so there's no need to noinherit. */
+#else
+ /* We decided above that noinherit would always do _something_. Assert here
+ * that we were correct. */
+ tor_assert(inherit != INHERIT_RES_KEEP);
+#endif
return result;
}
@@ -211,6 +249,27 @@ static void
crypto_fast_rng_getbytes_impl(crypto_fast_rng_t *rng, uint8_t *out,
const size_t n)
{
+#ifdef CHECK_PID
+ if (rng->owner) {
+ /* Note that we only need to do this check when we have owner set: that
+ * is, when our attempt to block inheriting failed, and the result was
+ * INHERIT_RES_KEEP.
+ *
+ * If the result was INHERIT_RES_DROP, then any attempt to access the rng
+ * memory after forking will crash.
+ *
+ * If the result was INHERIT_RES_ZERO, then forking will set the bytes_left
+ * and n_till_reseed fields to zero. This function will call
+ * crypto_fast_rng_refill(), which will in turn reseed the PRNG.
+ *
+ * So we only need to do this test in the case when mmap_anonymous()
+ * returned INHERIT_KEEP. We avoid doing it needlessly, since getpid() is
+ * often a system call, and that can be slow.
+ */
+ tor_assert(rng->owner == getpid());
+ }
+#endif
+
size_t bytes_to_yield = n;
while (bytes_to_yield) {