Skip to content

Commit 0a1fcad

Browse files
committed
auto merge of #4958 : cpeterso/rust/reseed-rng, r=graydon
For Issue #4709: **c531506 rt: rand.rs expects `rust_next()` to return `uint32_t`, not `size_t`** rand.rs expects `rustrt::rand_next()` to return `u32`, but the `rand_next()` C function returns `size_t`: https://github.com/mozilla/rust/blob/ca71c6ec5bb8106121cbe33eec5a6a9ca7786039/src/libcore/rand.rs#L34 **f4320b6 move isaac RNG utility functions to new rust_rng.cpp file** **665e900 encapsulate isaac RNG in `rust_rng` struct** Move isaac's `randctx` into a `rust_rng` struct to make names similar to `rand::Rng` function names and prepare for auto-reseeding in the next commit. **9a78dc9 reseed `rust_rng` after generating 32KB** Precedents from other languages: * Haskell's `GenAutoReseed` generator reseeds itself after generating 32KB: http://hackage.haskell.org/packages/archive/DRBG/0.1.2/doc/html/Crypto-Random-DRBG.html#t:GenAutoReseed * Go's RNG reseeds itself after generating 1MB: https://code.google.com/p/go/source/browse/src/pkg/crypto/rand/rand_unix.go?name=go1.0.3#94 **9a76d71 don't deplete RNG entropy when there is only one runnable task** `rust_sched_loop::schedule_task()` unnecessarily calls `isaac_rand()` for the common case when there is only 1 runnable task, thus depleting RNG entropy and incurring unnecessary overhead.
2 parents 9727008 + 9a76d71 commit 0a1fcad

9 files changed

+189
-92
lines changed

Diff for: mk/rt.mk

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ RUNTIME_CXXS_$(1) := \
5050
rt/rust_builtin.cpp \
5151
rt/rust_run_program.cpp \
5252
rt/rust_env.cpp \
53+
rt/rust_rng.cpp \
5354
rt/rust_sched_loop.cpp \
5455
rt/rust_sched_launcher.cpp \
5556
rt/rust_sched_driver.cpp \

Diff for: src/libcore/rand.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ impl<T: Rand> Rand for Option<T> {
116116
}
117117

118118
#[allow(non_camel_case_types)] // runtime type
119-
enum rctx {}
119+
enum rust_rng {}
120120

121121
#[abi = "cdecl"]
122122
extern mod rustrt {
123123
unsafe fn rand_seed() -> ~[u8];
124-
unsafe fn rand_new() -> *rctx;
125-
unsafe fn rand_new_seeded2(&&seed: ~[u8]) -> *rctx;
126-
unsafe fn rand_next(c: *rctx) -> u32;
127-
unsafe fn rand_free(c: *rctx);
124+
unsafe fn rand_new() -> *rust_rng;
125+
unsafe fn rand_new_seeded2(&&seed: ~[u8]) -> *rust_rng;
126+
unsafe fn rand_next(rng: *rust_rng) -> u32;
127+
unsafe fn rand_free(rng: *rust_rng);
128128
}
129129

130130
/// A random number generator
@@ -363,24 +363,24 @@ impl Rng {
363363
}
364364

365365
struct RandRes {
366-
c: *rctx,
366+
rng: *rust_rng,
367367
drop {
368368
unsafe {
369-
rustrt::rand_free(self.c);
369+
rustrt::rand_free(self.rng);
370370
}
371371
}
372372
}
373373

374-
fn RandRes(c: *rctx) -> RandRes {
374+
fn RandRes(rng: *rust_rng) -> RandRes {
375375
RandRes {
376-
c: c
376+
rng: rng
377377
}
378378
}
379379

380380
impl Rng for @RandRes {
381381
fn next() -> u32 {
382382
unsafe {
383-
return rustrt::rand_next((*self).c);
383+
return rustrt::rand_next((*self).rng);
384384
}
385385
}
386386
}

Diff for: src/rt/rust_builtin.cpp

+16-15
Original file line numberDiff line numberDiff line change
@@ -135,51 +135,52 @@ rand_seed() {
135135
rust_vec *v = (rust_vec *) task->kernel->malloc(vec_size<uint8_t>(size),
136136
"rand_seed");
137137
v->fill = v->alloc = size;
138-
isaac_seed(task->kernel, (uint8_t*) &v->data, size);
138+
rng_gen_seed(task->kernel, (uint8_t*) &v->data, size);
139139
return v;
140140
}
141141

142142
extern "C" CDECL void *
143143
rand_new() {
144144
rust_task *task = rust_get_current_task();
145145
rust_sched_loop *thread = task->sched_loop;
146-
randctx *rctx = (randctx *) task->malloc(sizeof(randctx), "rand_new");
147-
if (!rctx) {
146+
rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng), "rand_new");
147+
if (!rng) {
148148
task->fail();
149149
return NULL;
150150
}
151-
isaac_init(thread->kernel, rctx, NULL);
152-
return rctx;
151+
rng_init(thread->kernel, rng, NULL);
152+
return rng;
153153
}
154154

155155
extern "C" CDECL void *
156156
rand_new_seeded(rust_vec_box* seed) {
157157
rust_task *task = rust_get_current_task();
158158
rust_sched_loop *thread = task->sched_loop;
159-
randctx *rctx = (randctx *) task->malloc(sizeof(randctx),
160-
"rand_new_seeded");
161-
if (!rctx) {
159+
rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng),
160+
"rand_new_seeded");
161+
if (!rng) {
162162
task->fail();
163163
return NULL;
164164
}
165-
isaac_init(thread->kernel, rctx, seed);
166-
return rctx;
165+
rng_init(thread->kernel, rng, seed);
166+
return rng;
167167
}
168168

169169
extern "C" CDECL void *
170170
rand_new_seeded2(rust_vec_box** seed) {
171171
return rand_new_seeded(*seed);
172172
}
173173

174-
extern "C" CDECL size_t
175-
rand_next(randctx *rctx) {
176-
return isaac_rand(rctx);
174+
extern "C" CDECL uint32_t
175+
rand_next(rust_rng *rng) {
176+
rust_task *task = rust_get_current_task();
177+
return rng_gen_u32(task->kernel, rng);
177178
}
178179

179180
extern "C" CDECL void
180-
rand_free(randctx *rctx) {
181+
rand_free(rust_rng *rng) {
181182
rust_task *task = rust_get_current_task();
182-
task->free(rctx);
183+
task->free(rng);
183184
}
184185

185186

Diff for: src/rt/rust_globals.h

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
#include <math.h>
3838
#include <assert.h>
3939

40-
#include "rand.h"
4140
#include "uthash.h"
4241

4342
#if defined(__WIN32__)

Diff for: src/rt/rust_rng.cpp

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#include "rust_globals.h"
12+
#include "rust_rng.h"
13+
#include "rust_util.h"
14+
15+
// Initialization helpers for ISAAC RNG
16+
17+
void
18+
rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size) {
19+
#ifdef __WIN32__
20+
HCRYPTPROV hProv;
21+
kernel->win32_require
22+
(_T("CryptAcquireContext"),
23+
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
24+
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
25+
kernel->win32_require
26+
(_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest));
27+
kernel->win32_require
28+
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
29+
#else
30+
int fd = open("/dev/urandom", O_RDONLY);
31+
if (fd == -1)
32+
kernel->fatal("error opening /dev/urandom: %s", strerror(errno));
33+
size_t amount = 0;
34+
do {
35+
ssize_t ret = read(fd, dest+amount, size-amount);
36+
if (ret < 0)
37+
kernel->fatal("error reading /dev/urandom: %s", strerror(errno));
38+
else if (ret == 0)
39+
kernel->fatal("somehow hit eof reading from /dev/urandom");
40+
amount += (size_t)ret;
41+
} while (amount < size);
42+
int ret = close(fd);
43+
// FIXME #3697: Why does this fail sometimes?
44+
if (ret != 0)
45+
kernel->log(log_warn, "error closing /dev/urandom: %s",
46+
strerror(errno));
47+
#endif
48+
}
49+
50+
static void
51+
isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed) {
52+
memset(rctx, 0, sizeof(randctx));
53+
54+
char *env_seed = kernel->env->rust_seed;
55+
if (user_seed != NULL) {
56+
// ignore bytes after the required length
57+
size_t seed_len = user_seed->body.fill < sizeof(rctx->randrsl)
58+
? user_seed->body.fill : sizeof(rctx->randrsl);
59+
memcpy(&rctx->randrsl, user_seed->body.data, seed_len);
60+
} else if (env_seed != NULL) {
61+
ub4 seed = (ub4) atoi(env_seed);
62+
for (size_t i = 0; i < RANDSIZ; i ++) {
63+
memcpy(&rctx->randrsl[i], &seed, sizeof(ub4));
64+
seed = (seed + 0x7ed55d16) + (seed << 12);
65+
}
66+
} else {
67+
rng_gen_seed(kernel, (uint8_t*)&rctx->randrsl, sizeof(rctx->randrsl));
68+
}
69+
70+
randinit(rctx, 1);
71+
}
72+
73+
void
74+
rng_init(rust_kernel* kernel, rust_rng* rng, rust_vec_box* user_seed) {
75+
isaac_init(kernel, &rng->rctx, user_seed);
76+
rng->reseedable = !user_seed && !kernel->env->rust_seed;
77+
}
78+
79+
static void
80+
rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) {
81+
// If this RNG has generated more than 32KB of random data and was not
82+
// seeded by the user or RUST_SEED, then we should reseed now.
83+
const size_t RESEED_THRESHOLD = 32 * 1024;
84+
size_t bytes_generated = rng->rctx.randc * sizeof(ub4);
85+
if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) {
86+
return;
87+
}
88+
89+
uint32_t new_seed[RANDSIZ];
90+
rng_gen_seed(kernel, (uint8_t*) new_seed, RANDSIZ * sizeof(uint32_t));
91+
92+
// Stir new seed into PRNG's entropy pool.
93+
for (size_t i = 0; i < RANDSIZ; i++) {
94+
rng->rctx.randrsl[i] ^= new_seed[i];
95+
}
96+
97+
randinit(&rng->rctx, 1);
98+
}
99+
100+
uint32_t
101+
rng_gen_u32(rust_kernel* kernel, rust_rng* rng) {
102+
uint32_t x = isaac_rand(&rng->rctx);
103+
rng_maybe_reseed(kernel, rng);
104+
return x;
105+
}
106+
107+
//
108+
// Local Variables:
109+
// mode: C++
110+
// fill-column: 78;
111+
// indent-tabs-mode: nil
112+
// c-basic-offset: 4
113+
// buffer-file-coding-system: utf-8-unix
114+
// End:
115+
//

Diff for: src/rt/rust_rng.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#ifndef RUST_RNG_H
12+
#define RUST_RNG_H
13+
14+
#include "rand.h"
15+
16+
class rust_kernel;
17+
struct rust_vec_box;
18+
19+
// Initialization helpers for ISAAC RNG
20+
21+
struct rust_rng {
22+
randctx rctx;
23+
bool reseedable;
24+
};
25+
26+
void rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size);
27+
void rng_init(rust_kernel *kernel, rust_rng *rng, rust_vec_box* user_seed);
28+
uint32_t rng_gen_u32(rust_kernel *kernel, rust_rng *rng);
29+
30+
//
31+
// Local Variables:
32+
// mode: C++
33+
// fill-column: 78;
34+
// indent-tabs-mode: nil
35+
// c-basic-offset: 4
36+
// buffer-file-coding-system: utf-8-unix
37+
// End:
38+
//
39+
40+
#endif

Diff for: src/rt/rust_sched_loop.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) :
4141
name("main")
4242
{
4343
LOGPTR(this, "new dom", (uintptr_t)this);
44-
isaac_init(kernel, &rctx, NULL);
44+
rng_init(kernel, &rng, NULL);
4545

4646
if (!tls_initialized)
4747
init_tls();
@@ -150,10 +150,10 @@ rust_sched_loop::release_task(rust_task *task) {
150150
rust_task *
151151
rust_sched_loop::schedule_task() {
152152
lock.must_have_lock();
153-
if (running_tasks.length() > 0) {
154-
size_t k = isaac_rand(&rctx);
155-
size_t i = k % running_tasks.length();
156-
return (rust_task *)running_tasks[i];
153+
size_t tasks = running_tasks.length();
154+
if (tasks > 0) {
155+
size_t i = (tasks > 1) ? (rng_gen_u32(kernel, &rng) % tasks) : 0;
156+
return running_tasks[i];
157157
}
158158
return NULL;
159159
}

Diff for: src/rt/rust_sched_loop.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "rust_globals.h"
1515
#include "rust_log.h"
16+
#include "rust_rng.h"
1617
#include "rust_stack.h"
1718
#include "rust_signal.h"
1819
#include "context.h"
@@ -61,7 +62,7 @@ struct rust_sched_loop
6162
#endif
6263

6364
context c_context;
64-
65+
rust_rng rng;
6566
bool should_exit;
6667

6768
stk_seg *cached_c_stack;
@@ -102,7 +103,6 @@ struct rust_sched_loop
102103
size_t min_stack_size;
103104
memory_region local_region;
104105

105-
randctx rctx;
106106
const char *const name; // Used for debugging
107107

108108
// Only a pointer to 'name' is kept, so it must live as long as this

0 commit comments

Comments
 (0)