Use next generation crypto API on Windows (#2769)

CryptGenRandom is deprecated by Microsoft and may be removed in future
releases. They recommend to use the next generation API instead. See
https://learn.microsoft.com/en-us/windows/win32/seccng/cng-portal for
more details. Also, refactor the random functions to return error codes
rather than aborting the program if they fail.
This commit is contained in:
zoraaver 2023-11-17 10:40:29 +00:00 committed by GitHub
parent 2d0d4a0be9
commit b39fd516d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 41 deletions

View File

@ -614,14 +614,21 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in,
} }
// Picks an unused slot from the file descriptor table. // Picks an unused slot from the file descriptor table.
static __wasi_fd_t static __wasi_errno_t
fd_table_unused(struct fd_table *ft) REQUIRES_SHARED(ft->lock) fd_table_unused(struct fd_table *ft, __wasi_fd_t *out) REQUIRES_SHARED(ft->lock)
{ {
assert(ft->size > ft->used && "File descriptor table has no free slots"); assert(ft->size > ft->used && "File descriptor table has no free slots");
for (;;) { for (;;) {
__wasi_fd_t fd = (__wasi_fd_t)random_uniform(ft->size); uintmax_t random_fd = 0;
if (ft->entries[fd].object == NULL) __wasi_errno_t error = random_uniform(ft->size, &random_fd);
return fd;
if (error != __WASI_ESUCCESS)
return error;
if (ft->entries[(__wasi_fd_t)random_fd].object == NULL) {
*out = (__wasi_fd_t)random_fd;
return error;
}
} }
} }
@ -641,10 +648,14 @@ fd_table_insert(wasm_exec_env_t exec_env, struct fd_table *ft,
return convert_errno(errno); return convert_errno(errno);
} }
*out = fd_table_unused(ft); __wasi_errno_t error = fd_table_unused(ft, out);
if (error != __WASI_ESUCCESS)
return error;
fd_table_attach(ft, *out, fo, rights_base, rights_inheriting); fd_table_attach(ft, *out, fo, rights_base, rights_inheriting);
rwlock_unlock(&ft->lock); rwlock_unlock(&ft->lock);
return 0; return error;
} }
// Inserts a numerical file descriptor into the file descriptor table. // Inserts a numerical file descriptor into the file descriptor table.
@ -2282,8 +2293,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds,
__wasi_errno_t __wasi_errno_t
wasmtime_ssp_random_get(void *buf, size_t nbyte) wasmtime_ssp_random_get(void *buf, size_t nbyte)
{ {
random_buf(buf, nbyte); return random_buf(buf, nbyte);
return 0;
} }
__wasi_errno_t __wasi_errno_t

View File

@ -13,14 +13,16 @@
#include "ssp_config.h" #include "ssp_config.h"
#include "bh_platform.h" #include "bh_platform.h"
#include "libc_errno.h"
#include "random.h" #include "random.h"
#if CONFIG_HAS_ARC4RANDOM_BUF #if CONFIG_HAS_ARC4RANDOM_BUF
void __wasi_errno_t
random_buf(void *buf, size_t len) random_buf(void *buf, size_t len)
{ {
arc4random_buf(buf, len); arc4random_buf(buf, len);
return __WASI_ESUCCESS;
} }
#elif CONFIG_HAS_GETRANDOM #elif CONFIG_HAS_GETRANDOM
@ -29,7 +31,7 @@ random_buf(void *buf, size_t len)
#include <sys/random.h> #include <sys/random.h>
#endif #endif
void __wasi_errno_t
random_buf(void *buf, size_t len) random_buf(void *buf, size_t len)
{ {
for (;;) { for (;;) {
@ -37,57 +39,71 @@ random_buf(void *buf, size_t len)
if (x < 0) { if (x < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
os_printf("getrandom failed: %s", strerror(errno)); return convert_errno(errno);
abort();
} }
if ((size_t)x == len) if ((size_t)x == len)
return; break;
buf = (void *)((unsigned char *)buf + x); buf = (void *)((unsigned char *)buf + x);
len -= (size_t)x; len -= (size_t)x;
} }
return __WASI_ESUCCESS;
} }
#elif defined(BH_PLATFORM_WINDOWS) #elif defined(BH_PLATFORM_WINDOWS)
#include <wincrypt.h> #include <bcrypt.h>
#pragma comment(lib, "Bcrypt.lib")
void __wasi_errno_t
random_buf(void *buf, size_t len) random_buf(void *buf, size_t len)
{ {
static int crypt_initialized = 0; NTSTATUS ret =
static HCRYPTPROV provider; BCryptGenRandom(NULL, buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (!crypt_initialized) {
CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, // Since we pass NULL for the algorithm handle, the only way BCryptGenRandom
CRYPT_VERIFYCONTEXT); // can fail is if one of the parameters is invalid
crypt_initialized = 1; // (STATUS_INVALID_PARAMETER).
} return ret ? __WASI_EINVAL : __WASI_ESUCCESS;
CryptGenRandom(provider, len, buf);
} }
#else #else
static int urandom; static int urandom = -1;
static __wasi_errno_t urandom_error = __WASI_ESUCCESS;
static void static void
open_urandom(void) open_urandom(void)
{ {
urandom = open("/dev/urandom", O_RDONLY); urandom = open("/dev/urandom", O_RDONLY);
if (urandom < 0) { if (urandom < 0)
os_printf("Failed to open /dev/urandom\n"); urandom_error = convert_errno(errno);
abort();
}
} }
void __wasi_errno_t
random_buf(void *buf, size_t len) random_buf(void *buf, size_t len)
{ {
static pthread_once_t open_once = PTHREAD_ONCE_INIT; static pthread_once_t open_once = PTHREAD_ONCE_INIT;
pthread_once(&open_once, open_urandom); int pthread_ret = pthread_once(&open_once, open_urandom);
if ((size_t)read(urandom, buf, len) != len) { if (pthread_ret != 0)
os_printf("Short read on /dev/urandom\n"); return convert_errno(pthread_ret);
abort();
if (urandom < 0)
return urandom_error;
size_t bytes_read = 0;
while (bytes_read < len) {
ssize_t bytes_read_now =
read(urandom, buf + bytes_read, len - bytes_read);
if (bytes_read_now < 0)
return convert_errno(errno);
bytes_read += (size_t)bytes_read_now;
} }
return __WASI_ESUCCESS;
} }
#endif #endif
@ -99,8 +115,8 @@ random_buf(void *buf, size_t len)
// arc4random() until it lies within the range [2^k % upper, 2^k). As // 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 // this range has length k * upper, we can safely obtain a number
// without any modulo bias. // without any modulo bias.
uintmax_t __wasi_errno_t
random_uniform(uintmax_t upper) random_uniform(uintmax_t upper, uintmax_t *out)
{ {
// Compute 2^k % upper // Compute 2^k % upper
// == (2^k - upper) % upper // == (2^k - upper) % upper
@ -108,8 +124,14 @@ random_uniform(uintmax_t upper)
uintmax_t lower = -upper % upper; uintmax_t lower = -upper % upper;
for (;;) { for (;;) {
uintmax_t value; uintmax_t value;
random_buf(&value, sizeof(value)); __wasi_errno_t error = random_buf(&value, sizeof(value));
if (value >= lower)
return value % upper; if (error != __WASI_ESUCCESS)
return error;
if (value >= lower) {
*out = value % upper;
return error;
}
} }
} }

View File

@ -14,8 +14,12 @@
#ifndef RANDOM_H #ifndef RANDOM_H
#define RANDOM_H #define RANDOM_H
void #include "bh_platform.h"
__wasi_errno_t
random_buf(void *, size_t); random_buf(void *, size_t);
uintmax_t random_uniform(uintmax_t);
__wasi_errno_t
random_uniform(uintmax_t upper, uintmax_t *out);
#endif #endif