Skip to content

Issue #4709 RFC: reseed task_rng #4885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/rt/rust_sched_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "rust_globals.h"
#include "rust_sched_driver.h"
#include "rust_sched_loop.h"
#include "rust_util.h"

rust_sched_driver::rust_sched_driver(rust_sched_loop *sched_loop)
: sched_loop(sched_loop),
Expand Down Expand Up @@ -51,6 +52,13 @@ rust_sched_driver::start_main_loop() {

if (state == sched_loop_state_block) {
scoped_lock with(lock);
if (!signalled) {
// Release the lock while do idle work to avoid blocking the
// signalling thread. Check signalled again after idle work.
lock.unlock();
sched_loop->idle();
lock.lock();
}
if (!signalled) {
DLOG(sched_loop, dom, "blocking scheduler");
lock.wait();
Expand Down
22 changes: 20 additions & 2 deletions src/rt/rust_sched_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) :
dead_task(NULL),
killed(killed),
pump_signal(NULL),
idle_randcnt(RANDSIZ),
kernel(sched->kernel),
sched(sched),
log_lvl(log_debug),
Expand Down Expand Up @@ -150,10 +151,15 @@ rust_sched_loop::release_task(rust_task *task) {
rust_task *
rust_sched_loop::schedule_task() {
lock.must_have_lock();
if (running_tasks.length() > 0) {
size_t tasks = running_tasks.length();
if (tasks == 1) {
// Don't consume RNG entropy if we only have one runnable task.
return running_tasks[0];
}
if (tasks > 0) {
size_t k = isaac_rand(&rctx);
size_t i = k % running_tasks.length();
return (rust_task *)running_tasks[i];
return running_tasks[i];
}
return NULL;
}
Expand Down Expand Up @@ -269,6 +275,18 @@ rust_sched_loop::run_single_turn() {
}
}

void
rust_sched_loop::idle() {
// Reseed task_rng if we have drained its entropy pool, i.e. randcnt
// rolled over from 0 to RANDSIZ. This check is just an approximation
// because randcnt could, in theory, rollover multiple times before
// this idle function gets a chance to check.
if (rctx.randcnt > idle_randcnt && kernel->env->rust_seed == NULL) {
isaac_reseed(kernel, &rctx);
}
idle_randcnt = rctx.randcnt;
}

rust_task *
rust_sched_loop::create_task(rust_task *spawner, const char *name) {
rust_task *task =
Expand Down
4 changes: 3 additions & 1 deletion src/rt/rust_sched_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ struct rust_sched_loop
bool killed;

rust_signal *pump_signal;
randctx rctx;
uint32_t idle_randcnt;

void prepare_c_stack(rust_task *task);
void unprepare_c_stack();
Expand Down Expand Up @@ -102,7 +104,6 @@ struct rust_sched_loop
size_t min_stack_size;
memory_region local_region;

randctx rctx;
const char *const name; // Used for debugging

// Only a pointer to 'name' is kept, so it must live as long as this
Expand All @@ -119,6 +120,7 @@ struct rust_sched_loop

void on_pump_loop(rust_signal *signal);
rust_sched_loop_state run_single_turn();
void idle();

void log_state();

Expand Down
73 changes: 72 additions & 1 deletion src/rt/rust_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#include "rust_util.h"
#include "rust_type.h"


// A hardcoded type descriptor for strings, since the runtime needs to
// be able to create them.

Expand All @@ -25,6 +25,77 @@ struct type_desc str_body_tydesc = {
NULL, // shape_tables
};

// Initialization helpers for ISAAC RNG

void isaac_seed(rust_kernel* kernel, uint8_t* dest, size_t size)
{
#ifdef __WIN32__
HCRYPTPROV hProv;
kernel->win32_require
(_T("CryptAcquireContext"),
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
kernel->win32_require
(_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest));
kernel->win32_require
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
#else
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
kernel->fatal("error opening /dev/urandom: %s", strerror(errno));
size_t amount = 0;
do {
ssize_t ret = read(fd, dest+amount, size-amount);
if (ret < 0)
kernel->fatal("error reading /dev/urandom: %s", strerror(errno));
else if (ret == 0)
kernel->fatal("somehow hit eof reading from /dev/urandom");
amount += (size_t)ret;
} while (amount < size);
int ret = close(fd);
// FIXME #3697: Why does this fail sometimes?
if (ret != 0)
kernel->log(log_warn, "error closing /dev/urandom: %s",
strerror(errno));
#endif
}

void isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed)
{
memset(rctx, 0, sizeof(randctx));

const char *env_seed = kernel->env->rust_seed;
if (user_seed != NULL) {
// ignore bytes after the required length
size_t seed_len = user_seed->body.fill < sizeof(rctx->randrsl)
? user_seed->body.fill : sizeof(rctx->randrsl);
memcpy(&rctx->randrsl, user_seed->body.data, seed_len);
} else if (env_seed != NULL) {
ub4 seed = (ub4) atoi(env_seed);
for (size_t i = 0; i < RANDSIZ; i++) {
memcpy(&rctx->randrsl[i], &seed, sizeof(ub4));
seed = (seed + 0x7ed55d16) + (seed << 12);
}
} else {
isaac_seed(kernel, (uint8_t*) &rctx->randrsl, sizeof(rctx->randrsl));
}

randinit(rctx, 1);
}

void isaac_reseed(rust_kernel *kernel, randctx *rctx)
{
uint32_t new_seed[RANDSIZ];
isaac_seed(kernel, (uint8_t*) new_seed, RANDSIZ * sizeof(uint32_t));

// Stir new seed into PRNG's entropy pool.
for (size_t i = 0; i < RANDSIZ; i++) {
rctx->randrsl[i] ^= new_seed[i];
}

randinit(rctx, 1);
}

//
// Local Variables:
// mode: C++
Expand Down
59 changes: 3 additions & 56 deletions src/rt/rust_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,62 +138,9 @@ inline size_t get_box_size(size_t body_size, size_t body_align) {

// Initialization helpers for ISAAC RNG

inline void isaac_seed(rust_kernel* kernel, uint8_t* dest, size_t size)
{
#ifdef __WIN32__
HCRYPTPROV hProv;
kernel->win32_require
(_T("CryptAcquireContext"),
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
kernel->win32_require
(_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest));
kernel->win32_require
(_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0));
#else
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
kernel->fatal("error opening /dev/urandom: %s", strerror(errno));
size_t amount = 0;
do {
ssize_t ret = read(fd, dest+amount, size-amount);
if (ret < 0)
kernel->fatal("error reading /dev/urandom: %s", strerror(errno));
else if (ret == 0)
kernel->fatal("somehow hit eof reading from /dev/urandom");
amount += (size_t)ret;
} while (amount < size);
int ret = close(fd);
// FIXME #3697: Why does this fail sometimes?
if (ret != 0)
kernel->log(log_warn, "error closing /dev/urandom: %s",
strerror(errno));
#endif
}

inline void
isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed)
{
memset(rctx, 0, sizeof(randctx));

char *env_seed = kernel->env->rust_seed;
if (user_seed != NULL) {
// ignore bytes after the required length
size_t seed_len = user_seed->body.fill < sizeof(rctx->randrsl)
? user_seed->body.fill : sizeof(rctx->randrsl);
memcpy(&rctx->randrsl, user_seed->body.data, seed_len);
} else if (env_seed != NULL) {
ub4 seed = (ub4) atoi(env_seed);
for (size_t i = 0; i < RANDSIZ; i ++) {
memcpy(&rctx->randrsl[i], &seed, sizeof(ub4));
seed = (seed + 0x7ed55d16) + (seed << 12);
}
} else {
isaac_seed(kernel, (uint8_t*) &rctx->randrsl, sizeof(rctx->randrsl));
}

randinit(rctx, 1);
}
void isaac_seed(rust_kernel* kernel, uint8_t* dest, size_t size);
void isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed);
void isaac_reseed(rust_kernel *kernel, randctx *rctx);

//
// Local Variables:
Expand Down