summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2014-06-19 00:13:23 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2014-06-19 00:13:23 +0000
commitd700ec794a7b7b73827f25cafc026425cb050ddb (patch)
treea54d5b8e68a5e272a8e21d307e088704a04581c6
parent2a70ff3acb7585d39bb5f4b146e153ba2f2b8c79 (diff)
Move rs_chacha and rs_buf into the same memory page and don't mark it
MAP_INHERIT_ZERO anymore. This restores arc4random's previous behavior where fork children would mix in some randomness from the parent process. New behavior noticed by deraadt ok deraadt, tedu
-rw-r--r--lib/libc/crypt/arc4random.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/lib/libc/crypt/arc4random.c b/lib/libc/crypt/arc4random.c
index 03eb047f98e..985fa8a0e56 100644
--- a/lib/libc/crypt/arc4random.c
+++ b/lib/libc/crypt/arc4random.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arc4random.c,v 1.34 2014/06/17 00:37:07 matthew Exp $ */
+/* $OpenBSD: arc4random.c,v 1.35 2014/06/19 00:13:22 matthew Exp $ */
/*
* Copyright (c) 1996, David Mazieres <dm@uun.org>
@@ -49,12 +49,17 @@
#define BLOCKSZ 64
#define RSBUFSZ (16*BLOCKSZ)
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
static struct {
size_t rs_have; /* valid bytes at end of rs_buf */
size_t rs_count; /* bytes till reseed */
- chacha_ctx rs_chacha; /* chacha context for random keystream */
} *rs;
-static u_char *rs_buf; /* keystream blocks */
+
+/* Preserved in fork children. */
+static struct {
+ chacha_ctx rs_chacha; /* chacha context for random keystream */
+ u_char rs_buf[RSBUFSZ]; /* keystream blocks */
+} *rsx;
static inline void _rs_rekey(u_char *dat, size_t datlen);
@@ -66,21 +71,19 @@ _rs_init(u_char *buf, size_t n)
if (rs == NULL) {
if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE,
- MAP_ANON, -1, 0)) == MAP_FAILED)
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
abort();
if (minherit(rs, sizeof(*rs), MAP_INHERIT_ZERO) == -1)
abort();
}
- if (rs_buf == NULL) {
- if ((rs_buf = mmap(NULL, RSBUFSZ, PROT_READ|PROT_WRITE,
- MAP_ANON, -1, 0)) == MAP_FAILED)
- abort();
- if (minherit(rs_buf, RSBUFSZ, MAP_INHERIT_ZERO) == -1)
+ if (rsx == NULL) {
+ if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
abort();
}
- chacha_keysetup(&rs->rs_chacha, buf, KEYSZ * 8, 0);
- chacha_ivsetup(&rs->rs_chacha, buf + KEYSZ);
+ chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
+ chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
}
static void
@@ -99,7 +102,7 @@ _rs_stir(void)
/* invalidate rs_buf */
rs->rs_have = 0;
- memset(rs_buf, 0, RSBUFSZ);
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
rs->rs_count = 1600000;
}
@@ -119,36 +122,40 @@ static inline void
_rs_rekey(u_char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
- memset(rs_buf, 0,RSBUFSZ);
+ memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
#endif
/* fill rs_buf with the keystream */
- chacha_encrypt_bytes(&rs->rs_chacha, rs_buf, rs_buf, RSBUFSZ);
+ chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+ rsx->rs_buf, sizeof(rsx->rs_buf));
/* mix in optional user provided data */
if (dat) {
size_t i, m;
m = MIN(datlen, KEYSZ + IVSZ);
for (i = 0; i < m; i++)
- rs_buf[i] ^= dat[i];
+ rsx->rs_buf[i] ^= dat[i];
}
/* immediately reinit for backtracking resistance */
- _rs_init(rs_buf, KEYSZ + IVSZ);
- memset(rs_buf, 0, KEYSZ + IVSZ);
- rs->rs_have = RSBUFSZ - KEYSZ - IVSZ;
+ _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+ memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+ rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
}
static inline void
_rs_random_buf(void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
+ u_char *keystream;
size_t m;
_rs_stir_if_needed(n);
while (n > 0) {
if (rs->rs_have > 0) {
m = MIN(n, rs->rs_have);
- memcpy(buf, rs_buf + RSBUFSZ - rs->rs_have, m);
- memset(rs_buf + RSBUFSZ - rs->rs_have, 0, m);
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+ - rs->rs_have;
+ memcpy(buf, keystream, m);
+ memset(keystream, 0, m);
buf += m;
n -= m;
rs->rs_have -= m;
@@ -161,11 +168,13 @@ _rs_random_buf(void *_buf, size_t n)
static inline void
_rs_random_u32(u_int32_t *val)
{
+ u_char *keystream;
_rs_stir_if_needed(sizeof(*val));
if (rs->rs_have < sizeof(*val))
_rs_rekey(NULL, 0);
- memcpy(val, rs_buf + RSBUFSZ - rs->rs_have, sizeof(*val));
- memset(rs_buf + RSBUFSZ - rs->rs_have, 0, sizeof(*val));
+ keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+ memcpy(val, keystream, sizeof(*val));
+ memset(keystream, 0, sizeof(*val));
rs->rs_have -= sizeof(*val);
}