diff options
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c')
-rw-r--r-- | fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c | 1117 |
1 files changed, 1117 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c new file mode 100644 index 000000000..a8ae8d2f9 --- /dev/null +++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c @@ -0,0 +1,1117 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "sgx_error.h" +#include "sgx_file.h" + +#if WASM_ENABLE_SGX_IPFS != 0 +#include "sgx_ipfs.h" +#endif + +#ifndef SGX_DISABLE_WASI + +#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__) +#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__) + +/** fd **/ +int +ocall_open(int *p_fd, const char *pathname, int flags, bool has_mode, + unsigned mode); + +int +ocall_openat(int *p_fd, int dirfd, const char *pathname, int flags, + bool has_mode, unsigned mode); + +int +ocall_read(ssize_t *p_ret, int fd, void *buf, size_t read_size); + +int +ocall_close(int *p_ret, int fd); + +int +ocall_lseek(off_t *p_ret, int fd, off_t offset, int whence); + +int +ocall_ftruncate(int *p_ret, int fd, off_t length); + +int +ocall_fsync(int *p_ret, int fd); + +int +ocall_fdatasync(int *p_ret, int fd); + +int +ocall_isatty(int *p_ret, int fd); +/** fd end **/ + +/** DIR **/ +int +ocall_fdopendir(int fd, void **p_dirp); + +int +ocall_readdir(void **p_dirent, void *dirp); + +int +ocall_rewinddir(void *dirp); + +int +ocall_seekdir(void *dirp, long loc); + +int +ocall_telldir(long *p_dir, void *dirp); + +int +ocall_closedir(int *p_ret, void *dirp); +/** DIR end **/ + +/** stat **/ +int +ocall_stat(int *p_ret, const char *pathname, void *buf, unsigned int buf_len); +int +ocall_fstat(int *p_ret, int fd, void *buf, unsigned int buf_len); +int +ocall_fstatat(int *p_ret, int dirfd, const char *pathname, void *buf, + unsigned int buf_len, int flags); +/** stat end **/ + +/** link **/ +int +ocall_mkdirat(int *p_ret, int dirfd, const char *pathname, unsigned mode); +int +ocall_link(int *p_ret, const char *oldpath, const char *newpath); +int +ocall_linkat(int *p_ret, int olddirfd, const char *oldpath, int newdirfd, + const char *newpath, int flags); +int +ocall_unlinkat(int *p_ret, int dirfd, const char *pathname, int flags); +int +ocall_readlink(ssize_t *p_ret, const char *pathname, char *buf, size_t bufsiz); +int +ocall_readlinkat(ssize_t *p_ret, int dirfd, const char *pathname, char *buf, + size_t bufsiz); +int +ocall_renameat(int *p_ret, int olddirfd, const char *oldpath, int newdirfd, + const char *newpath); +int +ocall_symlinkat(int *p_ret, const char *target, int newdirfd, + const char *linkpath); +/** link end **/ + +/** control **/ +int +ocall_ioctl(int *p_ret, int fd, unsigned long request, void *arg, + unsigned int arg_len); +int +ocall_fcntl(int *p_ret, int fd, int cmd); +int +ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg); +/** control end **/ + +/** **/ +int +ocall_realpath(int *p_ret, const char *path, char *buf, unsigned int buf_len); +int +ocall_posix_fallocate(int *p_ret, int fd, off_t offset, off_t len); +int +ocall_poll(int *p_ret, void *fds, unsigned nfds, int timeout, + unsigned int fds_len); +int +ocall_getopt(int *p_ret, int argc, char *argv_buf, unsigned int argv_buf_len, + const char *optstring); +int +ocall_sched_yield(int *p_ret); + +/** struct iovec **/ +ssize_t +ocall_readv(ssize_t *p_ret, int fd, char *iov_buf, unsigned int buf_size, + int iovcnt, bool has_offset, off_t offset); +ssize_t +ocall_writev(ssize_t *p_ret, int fd, char *iov_buf, unsigned int buf_size, + int iovcnt, bool has_offset, off_t offset); +/** iovec end **/ + +int +ocall_get_errno(int *p_ret); + +int +open(const char *pathname, int flags, ...) +{ + int fd; + bool has_mode = false; + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + has_mode = true; + } + + if (SGX_SUCCESS != ocall_open(&fd, pathname, flags, has_mode, mode)) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (fd >= 0 && (flags & O_CLOEXEC)) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (fd == -1) + errno = get_errno(); + return fd; +} + +int +openat(int dirfd, const char *pathname, int flags, ...) +{ + int fd; + bool has_mode = false; + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + has_mode = true; + } + + if (SGX_SUCCESS + != ocall_openat(&fd, dirfd, pathname, flags, has_mode, mode)) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (fd >= 0 && (flags & O_CLOEXEC)) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (fd == -1) + errno = get_errno(); + +#if WASM_ENABLE_SGX_IPFS != 0 + struct stat sb; + int ret = fstatat(dirfd, pathname, &sb, 0); + if (ret < 0) { + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return -1; + } + + // Ony files are managed by SGX IPFS + if (S_ISREG(sb.st_mode)) { + // When WAMR uses Intel SGX IPFS to enabled, it opens a second + // file descriptor to interact with the secure file. + // The first file descriptor opened earlier is used to interact + // with the metadata of the file (e.g., time, flags, etc.). + void *file_ptr = ipfs_fopen(fd, flags); + if (file_ptr == NULL) { + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return -1; + } + } +#endif + + return fd; +} + +int +close(int fd) +{ + int ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + // Close the IPFS file pointer in addition of the file descriptor + ret = ipfs_close(fd); + if (ret == -1) + errno = get_errno(); +#endif + + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t +read(int fd, void *buf, size_t size) +{ + ssize_t ret; + int size_read_max = 2048, size_read, total_size_read = 0, count, i; + char *p = buf; + + if (buf == NULL) { + TRACE_FUNC(); + return -1; + } + + count = (size + size_read_max - 1) / size_read_max; + for (i = 0; i < count; i++) { + size_read = (i < count - 1) ? size_read_max : size - size_read_max * i; + + if (ocall_read(&ret, fd, p, size_read) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) { + /* read failed */ + errno = get_errno(); + return -1; + } + + p += ret; + total_size_read += ret; + + if (ret < size_read) + /* end of file */ + break; + } + return total_size_read; +} + +DIR * +fdopendir(int fd) +{ + DIR *result = NULL; + + result = (DIR *)BH_MALLOC(sizeof(DIR)); + if (!result) + return NULL; + + if (ocall_fdopendir(fd, (void **)result) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(result); + return NULL; + } + + if ((void *)*result == NULL) { /* opendir failed */ + TRACE_FUNC(); + BH_FREE(result); + errno = get_errno(); + return NULL; + } + + return result; +} + +struct dirent * +readdir(DIR *dirp) +{ + struct dirent *result; + + if (dirp == NULL) + return NULL; + + if (ocall_readdir((void **)&result, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return NULL; + } + + if (!result) + errno = get_errno(); + return result; +} + +void +rewinddir(DIR *dirp) +{ + if (ocall_rewinddir((void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } +} + +void +seekdir(DIR *dirp, long loc) +{ + if (ocall_seekdir((void *)*dirp, loc) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } +} + +long +telldir(DIR *dirp) +{ + long ret; + + if (ocall_telldir(&ret, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +closedir(DIR *dirp) +{ + int ret; + + if (ocall_closedir(&ret, (void *)*dirp) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + BH_FREE(dirp); + if (ret == -1) + errno = get_errno(); + return ret; +} + +static ssize_t +readv_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset) +{ + ssize_t ret, size_left; + struct iovec *iov1; + int i; + char *p; + uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt; + + if (iov == NULL || iovcnt < 1) + return -1; + + for (i = 0; i < iovcnt; i++) { + total_size += iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + +#if WASM_ENABLE_SGX_IPFS != 0 + if (fd > 2) { + return ipfs_read(fd, iov, iovcnt, has_offset, offset); + } +#endif + + iov1 = BH_MALLOC((uint32)total_size); + + if (iov1 == NULL) + return -1; + + memset(iov1, 0, (uint32)total_size); + + p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + for (i = 0; i < iovcnt; i++) { + iov1[i].iov_len = iov[i].iov_len; + iov1[i].iov_base = p; + p += iov[i].iov_len; + } + + if (ocall_readv(&ret, fd, (char *)iov1, (uint32)total_size, iovcnt, + has_offset, offset) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(iov1); + return -1; + } + + p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + size_left = ret; + for (i = 0; i < iovcnt; i++) { + if (size_left > iov[i].iov_len) { + memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1, + iov[i].iov_len); + p += iov[i].iov_len; + size_left -= iov[i].iov_len; + } + else { + memcpy(iov[i].iov_base, (uintptr_t)p + (char *)iov1, size_left); + break; + } + } + + BH_FREE(iov1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +static ssize_t +writev_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset, + off_t offset) +{ + ssize_t ret; + struct iovec *iov1; + int i; + char *p; + uint64 total_size = sizeof(struct iovec) * (uint64)iovcnt; + + if (iov == NULL || iovcnt < 1) + return -1; + + for (i = 0; i < iovcnt; i++) { + total_size += iov[i].iov_len; + } + + if (total_size >= UINT32_MAX) + return -1; + +#if WASM_ENABLE_SGX_IPFS != 0 + if (fd > 2) { + return ipfs_write(fd, iov, iovcnt, has_offset, offset); + } +#endif + + iov1 = BH_MALLOC((uint32)total_size); + + if (iov1 == NULL) + return -1; + + memset(iov1, 0, (uint32)total_size); + + p = (char *)(uintptr_t)(sizeof(struct iovec) * iovcnt); + + for (i = 0; i < iovcnt; i++) { + iov1[i].iov_len = iov[i].iov_len; + iov1[i].iov_base = p; + memcpy((uintptr_t)p + (char *)iov1, iov[i].iov_base, iov[i].iov_len); + p += iov[i].iov_len; + } + + if (ocall_writev(&ret, fd, (char *)iov1, (uint32)total_size, iovcnt, + has_offset, offset) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(iov1); + return -1; + } + + BH_FREE(iov1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t +readv(int fd, const struct iovec *iov, int iovcnt) +{ + return readv_internal(fd, iov, iovcnt, false, 0); +} + +ssize_t +writev(int fd, const struct iovec *iov, int iovcnt) +{ + return writev_internal(fd, iov, iovcnt, false, 0); +} + +ssize_t +preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + return readv_internal(fd, iov, iovcnt, true, offset); +} + +ssize_t +pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + return writev_internal(fd, iov, iovcnt, true, offset); +} + +off_t +lseek(int fd, off_t offset, int whence) +{ + off_t ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_lseek(fd, offset, whence); +#else + if (ocall_lseek(&ret, fd, (long)offset, whence) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); +#endif + + return ret; +} + +int +ftruncate(int fd, off_t length) +{ + int ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_ftruncate(fd, length); +#else + if (ocall_ftruncate(&ret, fd, length) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); +#endif + + return ret; +} + +int +stat(const char *pathname, struct stat *statbuf) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_stat(&ret, pathname, (void *)statbuf, sizeof(struct stat)) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +fstat(int fd, struct stat *statbuf) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_fstat(&ret, fd, (void *)statbuf, sizeof(struct stat)) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags) +{ + int ret; + + if (statbuf == NULL) + return -1; + + if (ocall_fstatat(&ret, dirfd, pathname, (void *)statbuf, + sizeof(struct stat), flags) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +fsync(int fd) +{ + int ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_fflush(fd); +#else + if (ocall_fsync(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); +#endif + + return ret; +} + +int +fdatasync(int fd) +{ + int ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_fflush(fd); +#else + if (ocall_fdatasync(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); +#endif + + return ret; +} + +int +mkdirat(int dirfd, const char *pathname, mode_t mode) +{ + int ret; + + if (ocall_mkdirat(&ret, dirfd, pathname, mode) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +link(const char *oldpath, const char *newpath) +{ + int ret; + + if (ocall_link(&ret, oldpath, newpath) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, + int flags) +{ + int ret; + + if (ocall_linkat(&ret, olddirfd, oldpath, newdirfd, newpath, flags) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +unlinkat(int dirfd, const char *pathname, int flags) +{ + int ret; + + if (ocall_unlinkat(&ret, dirfd, pathname, flags) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz) +{ + ssize_t ret; + + if (buf == NULL) + return -1; + + if (ocall_readlink(&ret, pathname, buf, bufsiz) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t +readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) +{ + ssize_t ret; + + if (buf == NULL) + return -1; + + if (ocall_readlinkat(&ret, dirfd, pathname, buf, bufsiz) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +symlinkat(const char *target, int newdirfd, const char *linkpath) +{ + int ret; + + if (ocall_symlinkat(&ret, target, newdirfd, linkpath) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) +{ + int ret; + + if (ocall_renameat(&ret, olddirfd, oldpath, newdirfd, newpath) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +ioctl(int fd, unsigned long request, ...) +{ + int ret; + va_list args; + + switch (request) { + case FIONREAD: + va_start(args, request); + int *arg = (int *)va_arg(args, int *); + if (ocall_ioctl(&ret, fd, request, arg, sizeof(*arg)) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + va_end(args); + return -1; + } + va_end(args); + break; + + default: + os_printf("ioctl failed: unknown request", request); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +fcntl(int fd, int cmd, ... /* arg */) +{ + int ret; + va_list args; + + switch (cmd) { + case F_GETFD: + case F_GETFL: + if (ocall_fcntl(&ret, fd, cmd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + break; + + case F_DUPFD: + case F_SETFD: + case F_SETFL: + va_start(args, cmd); + long arg_1 = (long)va_arg(args, long); + if (ocall_fcntl_long(&ret, fd, cmd, arg_1) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + va_end(args); + return -1; + } + va_end(args); + break; + + default: + os_printf("fcntl failed: unknown cmd %d.\n", cmd); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +isatty(int fd) +{ + int ret; + + if (ocall_isatty(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == 0) + errno = get_errno(); + return ret; +} + +char * +realpath(const char *path, char *resolved_path) +{ + int ret; + char buf[PATH_MAX] = { 0 }; + + if (ocall_realpath(&ret, path, buf, PATH_MAX) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return (char *)NULL; + } + + if (ret != 0) + return (char *)NULL; + + if (resolved_path) { + strcpy(resolved_path, buf); + } + else { + resolved_path = BH_MALLOC(strlen(buf) + 1); + if (resolved_path == NULL) + return NULL; + strcpy(resolved_path, buf); + } + + return resolved_path; +} + +int +posix_fallocate(int fd, off_t offset, off_t len) +{ + int ret; + +#if WASM_ENABLE_SGX_IPFS != 0 + ret = ipfs_posix_fallocate(fd, offset, len); +#else + if (ocall_posix_fallocate(&ret, fd, offset, len) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } +#endif + + return ret; +} + +int +poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + int ret; + + if (fds == NULL) + return -1; + + if (ocall_poll(&ret, fds, nfds, timeout, sizeof(*fds) * nfds) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +getopt(int argc, char *const argv[], const char *optstring) +{ + int ret; + char **argv1; + char *p; + int i; + uint64 total_size = sizeof(char *) * (uint64)argc; + + for (i = 0; i < argc; i++) { + total_size += strlen(argv[i]) + 1; + } + + if (total_size >= UINT32_MAX) + return -1; + + argv1 = BH_MALLOC((uint32)total_size); + + if (argv1 == NULL) + return -1; + + p = (char *)(uintptr_t)(sizeof(char *) * argc); + + for (i = 0; i < argc; i++) { + argv1[i] = p; + strcpy((char *)argv1 + (uintptr_t)p, argv[i]); + p += ((uintptr_t)strlen(argv[i]) + 1); + } + + if (ocall_getopt(&ret, argc, (char *)argv1, total_size, optstring) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + BH_FREE(argv1); + return -1; + } + + BH_FREE(argv1); + if (ret == -1) + errno = get_errno(); + return ret; +} + +int +sched_yield(void) +{ + int ret; + + if (ocall_sched_yield(&ret) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + if (ret == -1) + errno = get_errno(); + return ret; +} + +ssize_t +getrandom(void *buf, size_t buflen, unsigned int flags) +{ + sgx_status_t ret; + + if (!buf || buflen > INT32_MAX || flags != 0) { + errno = EINVAL; + return -1; + } + + 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) +{ + uint32 size; + + if (!buffer || length > INT32_MAX) { + errno = EINVAL; + return -1; + } + + if (length == 0) { + return 0; + } + + size = rdrand_get_bytes(buffer, (uint32)length); + if (size != length) { + errno = EFAULT; + return -1; + } + + return 0; +} + +int +get_errno(void) +{ + int ret; + + if (ocall_get_errno(&ret) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + return ret; +} + +#endif |