mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
fast_rng: if noinherit has failed, then check getpid() for bad forks
getpid() can be really expensive sometimes, and it can fail to detect some kind of fork+prng mistakes, so we need to avoid it if it's safe to do so. This patch might slow down fast_prng a lot on any old operating system that lacks a way to prevent ram from being inherited, AND requires a syscall for any getpid() calls. But it should make sure that we either crash or continue safely on incorrect fork+prng usage elsewhere in the future.
This commit is contained in:
parent
361e955cf3
commit
785c3f84de
@ -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_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,
|
||||
NULL);
|
||||
&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_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_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_KEEP.
|
||||
*
|
||||
* If the result was INHERIT_DROP, then any attempt to access the rng
|
||||
* memory after forking will crash.
|
||||
*
|
||||
* If the result was INHERIT_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) {
|
||||
|
Loading…
Reference in New Issue
Block a user