Files
wasmtime/crates/wasi-c/sandboxed-system-primitives/src/random.c

93 lines
2.2 KiB
C

// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://github.com/bytecodealliance/wasmtime/blob/master/LICENSE for license information.
//
// Significant parts of this file are derived from cloudabi-utils. See
// https://github.com/bytecodealliance/wasmtime/blob/master/lib/wasi/sandboxed-system-primitives/src/LICENSE
// for license information.
//
// The upstream file contains the following copyright notice:
//
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
#include "config.h"
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "random.h"
#if CONFIG_HAS_ARC4RANDOM_BUF
void random_buf(void *buf, size_t len) {
arc4random_buf(buf, len);
}
#elif CONFIG_HAS_GETRANDOM
#include <sys/random.h>
void random_buf(void *buf, size_t len) {
for (;;) {
ssize_t x = getrandom(buf, len, 0);
if (x < 0) {
if (errno == EINTR)
continue;
fprintf(stderr, "getrandom failed: %s", strerror(errno));
abort();
}
if (x == len)
return;
buf = (void *)((unsigned char *)buf + x);
len -= x;
}
}
#else
static int urandom;
static void open_urandom(void) {
urandom = open("/dev/urandom", O_RDONLY);
if (urandom < 0) {
fputs("Failed to open /dev/urandom\n", stderr);
abort();
}
}
void random_buf(void *buf, size_t len) {
static pthread_once_t open_once = PTHREAD_ONCE_INIT;
pthread_once(&open_once, open_urandom);
if (read(urandom, buf, len) != len) {
fputs("Short read on /dev/urandom\n", stderr);
abort();
}
}
#endif
// Calculates a random number within the range [0, upper - 1] without
// any modulo bias.
//
// The function below repeatedly obtains a random number from
// arc4random() until it lies within the range [2^k % upper, 2^k). As
// this range has length k * upper, we can safely obtain a number
// without any modulo bias.
uintmax_t random_uniform(uintmax_t upper) {
// Compute 2^k % upper
// == (2^k - upper) % upper
// == -upper % upper.
uintmax_t lower = -upper % upper;
for (;;) {
uintmax_t value;
random_buf(&value, sizeof(value));
if (value >= lower)
return value % upper;
}
}