mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-11 12:11:14 +00:00
Implement SGX getrandom/getentropy without ocall (#1176)
Implement SGX getrandom with sgx_read_rand and getentropy with `rdseed` instruction instead of ocall to improve the security.
This commit is contained in:
parent
c72501781a
commit
37cc6eac3b
|
@ -28,6 +28,7 @@
|
|||
#include "sgx_time.h"
|
||||
#include "sgx_socket.h"
|
||||
#include "sgx_signal.h"
|
||||
#include "sgx_trts.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -116,10 +116,6 @@ int
|
|||
ocall_getopt(int *p_ret, int argc, char *argv_buf, unsigned int argv_buf_len,
|
||||
const char *optstring);
|
||||
int
|
||||
ocall_getrandom(ssize_t *p_ret, void *buf, size_t buflen, unsigned int flags);
|
||||
int
|
||||
ocall_getentropy(int *p_ret, void *buffer, size_t length);
|
||||
int
|
||||
ocall_sched_yield(int *p_ret);
|
||||
|
||||
/** struct iovec **/
|
||||
|
@ -891,29 +887,124 @@ sched_yield(void)
|
|||
ssize_t
|
||||
getrandom(void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
sgx_status_t ret;
|
||||
|
||||
if (ocall_getrandom(&ret, buf, buflen, flags) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
if (!buf || buflen > INT32_MAX || flags != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
return ret;
|
||||
|
||||
ret = sgx_read_rand(buf, buflen);
|
||||
if (ret != SGX_SUCCESS) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (ssize_t)buflen;
|
||||
}
|
||||
|
||||
#define RDRAND_RETRIES 3
|
||||
|
||||
static int
|
||||
rdrand64_step(uint64 *seed)
|
||||
{
|
||||
uint8 ok;
|
||||
__asm__ volatile("rdseed %0; setc %1" : "=r"(*seed), "=qm"(ok));
|
||||
return (int)ok;
|
||||
}
|
||||
|
||||
static int
|
||||
rdrand64_retry(uint64 *rand, uint32 retries)
|
||||
{
|
||||
uint32 count = 0;
|
||||
|
||||
while (count++ <= retries) {
|
||||
if (rdrand64_step(rand)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32
|
||||
rdrand_get_bytes(uint8 *dest, uint32 n)
|
||||
{
|
||||
uint8 *head_start = dest, *tail_start = NULL;
|
||||
uint64 *block_start;
|
||||
uint32 count, ltail, lhead, lblock;
|
||||
uint64 i, temp_rand;
|
||||
|
||||
/* Get the address of the first 64-bit aligned block in the
|
||||
destination buffer. */
|
||||
if (((uintptr_t)head_start & (uintptr_t)7) == 0) {
|
||||
/* already 8-byte aligned */
|
||||
block_start = (uint64 *)head_start;
|
||||
lhead = 0;
|
||||
lblock = n & ~7;
|
||||
}
|
||||
else {
|
||||
/* next 8-byte aligned */
|
||||
block_start = (uint64 *)(((uintptr_t)head_start + 7) & ~(uintptr_t)7);
|
||||
lhead = (uint32)((uintptr_t)block_start - (uintptr_t)head_start);
|
||||
lblock = (n - lhead) & ~7;
|
||||
}
|
||||
|
||||
/* Compute the number of 64-bit blocks and the remaining number
|
||||
of bytes (the tail) */
|
||||
ltail = n - lblock - lhead;
|
||||
if (ltail > 0) {
|
||||
tail_start = (uint8 *)block_start + lblock;
|
||||
}
|
||||
|
||||
/* Populate the starting, mis-aligned section (the head) */
|
||||
if (lhead > 0) {
|
||||
if (!rdrand64_retry(&temp_rand, RDRAND_RETRIES)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(head_start, &temp_rand, lhead);
|
||||
}
|
||||
|
||||
/* Populate the central, aligned blocks */
|
||||
count = lblock / 8;
|
||||
for (i = 0; i < count; i++, block_start++) {
|
||||
if (!rdrand64_retry(block_start, RDRAND_RETRIES)) {
|
||||
return i * 8 + lhead;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the tail */
|
||||
if (ltail > 0) {
|
||||
if (!rdrand64_retry(&temp_rand, RDRAND_RETRIES)) {
|
||||
return count * 8 + lhead;
|
||||
}
|
||||
|
||||
memcpy(tail_start, &temp_rand, ltail);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
getentropy(void *buffer, size_t length)
|
||||
{
|
||||
int ret;
|
||||
uint32 size;
|
||||
|
||||
if (ocall_getentropy(&ret, buffer, length) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
if (!buffer || length > INT32_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
return ret;
|
||||
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = rdrand_get_bytes(buffer, (uint32)length);
|
||||
if (size != length) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -250,6 +250,7 @@ sched_yield(void);
|
|||
|
||||
ssize_t
|
||||
getrandom(void *buf, size_t buflen, unsigned int flags);
|
||||
|
||||
int
|
||||
getentropy(void *buffer, size_t length);
|
||||
|
||||
|
|
|
@ -77,9 +77,6 @@ enclave {
|
|||
[in, size=argv_buf_len]char *argv_buf,
|
||||
unsigned int argv_buf_len,
|
||||
[in, string]const char *optstring);
|
||||
ssize_t ocall_getrandom([out, size=buflen]void *buf, size_t buflen,
|
||||
unsigned int flags);
|
||||
int ocall_getentropy([out, size=length]void *buffer, size_t length);
|
||||
ssize_t ocall_readv(int fd,
|
||||
[in, out, size=buf_size]char *iov_buf,
|
||||
unsigned int buf_size, int iovcnt,
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/uio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -303,18 +302,6 @@ ocall_getopt(int argc, char *argv_buf, unsigned int argv_buf_len,
|
|||
return getopt(argc, argv, optstring);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ocall_getrandom(void *buf, size_t buflen, unsigned int flags)
|
||||
{
|
||||
return getrandom(buf, buflen, flags);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_getentropy(void *buffer, size_t length)
|
||||
{
|
||||
return getentropy(buffer, length);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_sched_yield()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user