commit 12205c3cbee4e71ded2b5710a57342b510e9d6df Author: Nick Mathewson nickm@torproject.org Date: Wed Mar 6 10:35:02 2019 -0500
Make map_anon expose the result of a noinherit attempt
Previously we did this for tests only, but it's valuable for getting proper fork behavior in rand_fast. --- src/lib/crypt_ops/crypto_rand_fast.c | 4 +-- src/lib/malloc/map_anon.c | 48 ++++++++++++++---------------------- src/lib/malloc/map_anon.h | 17 +++++++++---- src/test/test_util.c | 21 +++++++++------- 4 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/src/lib/crypt_ops/crypto_rand_fast.c b/src/lib/crypt_ops/crypto_rand_fast.c index 760e1025e..f1acc9faf 100644 --- a/src/lib/crypt_ops/crypto_rand_fast.c +++ b/src/lib/crypt_ops/crypto_rand_fast.c @@ -134,8 +134,8 @@ crypto_fast_rng_new_from_seed(const uint8_t *seed) * 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, + NULL); memcpy(result->buf.seed, seed, SEED_LEN); /* Causes an immediate refill once the user asks for data. */ result->bytes_left = 0; diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 5dac5256a..bb0a3d574 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -107,54 +107,34 @@ nodump_mem(void *mem, size_t sz) #endif }
-#ifdef TOR_UNIT_TESTS -static unsigned last_anon_map_noinherit = ~0; -/* Testing helper: return the outcome of the last call to noinherit_mem(): - * 0 if it did no good; 1 if it caused the memory not to be inherited, and - * 2 if it caused the memory to be cleared on fork */ -unsigned -get_last_anon_map_noinherit(void) -{ - return last_anon_map_noinherit; -} -static void -set_last_anon_map_noinherit(unsigned f) -{ - last_anon_map_noinherit = f; -} -#else -static void -set_last_anon_map_noinherit(unsigned f) -{ - (void)f; -} -#endif - /** * Helper: try to prevent the <b>sz</b> bytes at <b>mem</b> from being * accessible in child processes -- ideally by having them set to 0 after a * fork, and if that doesn't work, by having them unmapped after a fork. * Return 0 on success or if the facility is not available on this OS; return * -1 on failure. + * + * If we successfully make the memory uninheritable, adjust the value of + * *<b>inherit_result_out</b>. */ static int -noinherit_mem(void *mem, size_t sz) +noinherit_mem(void *mem, size_t sz, unsigned *inherit_result_out) { - set_last_anon_map_noinherit(0); #ifdef FLAG_ZERO int r = MINHERIT(mem, sz, FLAG_ZERO); if (r == 0) { - set_last_anon_map_noinherit(2); + *inherit_result_out = INHERIT_ZERO; return 0; } #endif #ifdef FLAG_NOINHERIT int r2 = MINHERIT(mem, sz, FLAG_NOINHERIT); if (r2 == 0) { - set_last_anon_map_noinherit(1); + *inherit_result_out = INHERIT_DROP; } return r2; #else + (void)inherit_result_out; (void)mem; (void)sz; return 0; @@ -174,14 +154,24 @@ noinherit_mem(void *mem, size_t sz) * Memory returned from this function must be released with * tor_munmap_anonymous(). * + * If <b>inherit_result_out</b> is non-NULL, set it to one of INHERIT_KEEP, + * INHERIT_DROP, and INHERIT_ZERO, depending on the properties of the returned + * memory. + * * [Note: OS people use the word "anonymous" here to mean that the memory * isn't associated with any file. This has *nothing* to do with the kind of * anonymity that Tor is trying to provide.] */ void * -tor_mmap_anonymous(size_t sz, unsigned flags) +tor_mmap_anonymous(size_t sz, unsigned flags, unsigned *inherit_result_out) { void *ptr; + unsigned itmp=0; + if (inherit_result_out == NULL) { + inherit_result_out = &itmp; + } + *inherit_result_out = INHERIT_KEEP; + #if defined(_WIN32) HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, /*attributes*/ @@ -214,7 +204,7 @@ tor_mmap_anonymous(size_t sz, unsigned flags) }
if (flags & ANONMAP_NOINHERIT) { - int noinherit_result = noinherit_mem(ptr, sz); + int noinherit_result = noinherit_mem(ptr, sz, inherit_result_out); raw_assert(noinherit_result == 0); }
diff --git a/src/lib/malloc/map_anon.h b/src/lib/malloc/map_anon.h index 395145bd7..edd750082 100644 --- a/src/lib/malloc/map_anon.h +++ b/src/lib/malloc/map_anon.h @@ -31,11 +31,18 @@ */ #define ANONMAP_NOINHERIT (1u<<1)
-void *tor_mmap_anonymous(size_t sz, unsigned flags); -void tor_munmap_anonymous(void *mapping, size_t sz); +/** Possible value for inherit_result_out: the memory will be kept + * by any child process. */ +#define INHERIT_KEEP 0 +/** Possible value for inherit_result_out: the memory will be dropped in + * the child process. Attempting to access it will likely cause a segfault. */ +#define INHERIT_DROP 1 +/** Possible value for inherit_result_out: the memory will be cleared in + * the child process. */ +#define INHERIT_ZERO 2
-#ifdef TOR_UNIT_TESTS -unsigned get_last_anon_map_noinherit(void); -#endif +void *tor_mmap_anonymous(size_t sz, unsigned flags, + unsigned *inherit_result_out); +void tor_munmap_anonymous(void *mapping, size_t sz);
#endif /* !defined(TOR_MAP_ANON_H) */ diff --git a/src/test/test_util.c b/src/test/test_util.c index 4990aa709..039fc435c 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -6130,10 +6130,12 @@ test_util_map_anon(void *arg) (void)arg; char *ptr = NULL; size_t sz = 16384; + unsigned inherit=0;
/* Basic checks. */ - ptr = tor_mmap_anonymous(sz, 0); + ptr = tor_mmap_anonymous(sz, 0, &inherit); tt_ptr_op(ptr, OP_NE, 0); + tt_int_op(inherit, OP_EQ, INHERIT_KEEP); ptr[sz-1] = 3; tt_int_op(ptr[0], OP_EQ, 0); tt_int_op(ptr[sz-2], OP_EQ, 0); @@ -6141,8 +6143,9 @@ test_util_map_anon(void *arg)
/* Try again, with a private (non-swappable) mapping. */ tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_PRIVATE); + ptr = tor_mmap_anonymous(sz, ANONMAP_PRIVATE, &inherit); tt_ptr_op(ptr, OP_NE, 0); + tt_int_op(inherit, OP_EQ, INHERIT_KEEP); ptr[sz-1] = 10; tt_int_op(ptr[0], OP_EQ, 0); tt_int_op(ptr[sz/2], OP_EQ, 0); @@ -6150,7 +6153,7 @@ test_util_map_anon(void *arg)
/* Now let's test a drop-on-fork mapping. */ tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT); + ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit); tt_ptr_op(ptr, OP_NE, 0); ptr[sz-1] = 10; tt_int_op(ptr[0], OP_EQ, 0); @@ -6179,10 +6182,10 @@ test_util_map_anon_nofork(void *arg) char *ptr = NULL; size_t sz = 16384; int pipefd[2] = {-1, -1}; + unsigned inherit=0;
tor_munmap_anonymous(ptr, sz); - ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT); - int outcome = get_last_anon_map_noinherit(); + ptr = tor_mmap_anonymous(sz, ANONMAP_NOINHERIT, &inherit); tt_ptr_op(ptr, OP_NE, 0); memset(ptr, 0xd0, sz);
@@ -6204,16 +6207,16 @@ test_util_map_anon_nofork(void *arg) char buf[1]; ssize_t r = read(pipefd[0], buf, 1);
- if (outcome == 2) { + if (inherit == INHERIT_ZERO) { // We should be seeing clear-on-fork behavior. tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. tt_int_op(buf[0], OP_EQ, 0); // that byte should be zero. - } else if (outcome == 1) { + } else if (inherit == INHERIT_DROP) { // We should be seeing noinherit behavior. tt_int_op(r, OP_LE, 0); // child said nothing; it should have crashed. } else { // noinherit isn't implemented. - tt_int_op(outcome, OP_EQ, 0); + tt_int_op(inherit, OP_EQ, INHERIT_KEEP); tt_int_op((int)r, OP_EQ, 1); // child should send us a byte. tt_int_op(buf[0], OP_EQ, 0xd0); // that byte should what we set it to. } @@ -6221,7 +6224,7 @@ test_util_map_anon_nofork(void *arg) int ws; waitpid(child, &ws, 0);
- if (outcome == 0) { + if (inherit == INHERIT_KEEP) { /* Call this test "skipped", not "passed", since noinherit wasn't * implemented. */ tt_skip();
tor-commits@lists.torproject.org