diff --git a/core/shared/platform/linux-sgx/platform_internal.h b/core/shared/platform/linux-sgx/platform_internal.h index 4ce7ee356..3d782ca1c 100644 --- a/core/shared/platform/linux-sgx/platform_internal.h +++ b/core/shared/platform/linux-sgx/platform_internal.h @@ -28,6 +28,7 @@ #include "sgx_time.h" #include "sgx_socket.h" #include "sgx_signal.h" +#include "sgx_trts.h" #ifdef __cplusplus extern "C" { diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c index 240c4a780..f71249fcc 100644 --- a/core/shared/platform/linux-sgx/sgx_file.c +++ b/core/shared/platform/linux-sgx/sgx_file.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 diff --git a/core/shared/platform/linux-sgx/sgx_file.h b/core/shared/platform/linux-sgx/sgx_file.h index 83be395bf..c35c22469 100644 --- a/core/shared/platform/linux-sgx/sgx_file.h +++ b/core/shared/platform/linux-sgx/sgx_file.h @@ -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); diff --git a/core/shared/platform/linux-sgx/sgx_wamr.edl b/core/shared/platform/linux-sgx/sgx_wamr.edl index a5ce1897d..3e16aaf8b 100644 --- a/core/shared/platform/linux-sgx/sgx_wamr.edl +++ b/core/shared/platform/linux-sgx/sgx_wamr.edl @@ -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, diff --git a/core/shared/platform/linux-sgx/untrusted/file.c b/core/shared/platform/linux-sgx/untrusted/file.c index 4da4be2d3..22abe7d88 100644 --- a/core/shared/platform/linux-sgx/untrusted/file.c +++ b/core/shared/platform/linux-sgx/untrusted/file.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -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() {