Implement Berkeley Socket API for Intel SGX (#1061)
Implement Berkeley Socket API for Intel SGX - bring Berkeley socket API in Intel SGX enclaves, - adapt the documentation of the socket API to mention Intel SGX enclaves, - adapt _iwasm_ in the mini-product _linux-sgx_ to support the same option as the one for _linux_, - tested on the socket sample as provided by WAMR (the TCP client/server).
This commit is contained in:
@ -9,21 +9,194 @@
|
||||
|
||||
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
|
||||
|
||||
/** OCALLs prototypes **/
|
||||
int
|
||||
ocall_socket(int *p_ret, int domain, int type, int protocol);
|
||||
ocall_accept(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
|
||||
uint32_t addr_size);
|
||||
|
||||
int
|
||||
ocall_bind(int *p_ret, int sockfd, const void *addr, uint32_t addrlen);
|
||||
|
||||
int
|
||||
ocall_close(int *p_ret, int fd);
|
||||
|
||||
int
|
||||
ocall_connect(int *p_ret, int sockfd, void *addr, uint32_t addrlen);
|
||||
|
||||
int
|
||||
ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg);
|
||||
|
||||
int
|
||||
ocall_getsockname(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
|
||||
uint32_t addr_size);
|
||||
|
||||
int
|
||||
ocall_getsockopt(int *p_ret, int sockfd, int level, int optname, void *val_buf,
|
||||
unsigned int val_buf_size, void *len_buf);
|
||||
|
||||
int
|
||||
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
ocall_listen(int *p_ret, int sockfd, int backlog);
|
||||
|
||||
int
|
||||
ocall_recv(int *p_ret, int sockfd, void *buf, size_t len, int flags);
|
||||
|
||||
int
|
||||
ocall_recvmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
|
||||
int
|
||||
ocall_send(int *p_ret, int sockfd, const void *buf, size_t len, int flags);
|
||||
|
||||
int
|
||||
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
|
||||
int
|
||||
ocall_setsockopt(int *p_ret, int sockfd, int level, int optname, void *optval,
|
||||
unsigned int optlen);
|
||||
|
||||
int
|
||||
ocall_shutdown(int *p_ret, int sockfd, int how);
|
||||
|
||||
int
|
||||
ocall_socket(int *p_ret, int domain, int type, int protocol);
|
||||
/** OCALLs prototypes end **/
|
||||
|
||||
/** In-enclave implementation of POSIX functions **/
|
||||
static bool
|
||||
is_little_endian()
|
||||
{
|
||||
long i = 0x01020304;
|
||||
unsigned char *c = (unsigned char *)&i;
|
||||
return (*c == 0x04) ? true : false;
|
||||
}
|
||||
|
||||
static void
|
||||
swap32(uint8 *pData)
|
||||
{
|
||||
uint8 value = *pData;
|
||||
*pData = *(pData + 3);
|
||||
*(pData + 3) = value;
|
||||
|
||||
value = *(pData + 1);
|
||||
*(pData + 1) = *(pData + 2);
|
||||
*(pData + 2) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
swap16(uint8 *pData)
|
||||
{
|
||||
uint8 value = *pData;
|
||||
*(pData) = *(pData + 1);
|
||||
*(pData + 1) = value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
htonl(uint32 value)
|
||||
{
|
||||
uint32 ret;
|
||||
if (is_little_endian()) {
|
||||
ret = value;
|
||||
swap32((uint8 *)&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
ntohl(uint32 value)
|
||||
{
|
||||
return htonl(value);
|
||||
}
|
||||
|
||||
static uint16
|
||||
htons(uint16 value)
|
||||
{
|
||||
uint16 ret;
|
||||
if (is_little_endian()) {
|
||||
ret = value;
|
||||
swap16((uint8 *)&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint16
|
||||
ntohs(uint16 value)
|
||||
{
|
||||
return htons(value);
|
||||
}
|
||||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
__inet_aton(const char *s0, struct in_addr *dest)
|
||||
{
|
||||
const char *s = s0;
|
||||
unsigned char *d = (void *)dest;
|
||||
unsigned long a[4] = { 0 };
|
||||
char *z;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
a[i] = strtoul(s, &z, 0);
|
||||
if (z == s || (*z && *z != '.') || !isdigit(*s))
|
||||
return 0;
|
||||
if (!*z)
|
||||
break;
|
||||
s = z + 1;
|
||||
}
|
||||
if (i == 4)
|
||||
return 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
a[1] = a[0] & 0xffffff;
|
||||
a[0] >>= 24;
|
||||
case 1:
|
||||
a[2] = a[1] & 0xffff;
|
||||
a[1] >>= 16;
|
||||
case 2:
|
||||
a[3] = a[2] & 0xff;
|
||||
a[2] >>= 8;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (a[i] > 255)
|
||||
return 0;
|
||||
d[i] = a[i];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
inet_addr(const char *p)
|
||||
{
|
||||
struct in_addr a;
|
||||
if (!__inet_aton(p, &a))
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
|
||||
static int
|
||||
inet_network(const char *p)
|
||||
{
|
||||
return ntohl(inet_addr(p));
|
||||
}
|
||||
/** In-enclave implementation of POSIX functions end **/
|
||||
|
||||
static int
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
|
||||
{
|
||||
assert(textual);
|
||||
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(port);
|
||||
out->sin_addr.s_addr = inet_addr(textual);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
@ -232,67 +405,219 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
||||
unsigned int *addrlen)
|
||||
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
struct sockaddr addr_tmp;
|
||||
unsigned int len = sizeof(struct sockaddr);
|
||||
|
||||
if (ocall_accept(sock, server_sock, &addr_tmp, &len, len) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*sock < 0) {
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
int
|
||||
os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
struct sockaddr_in addr;
|
||||
struct linger ling;
|
||||
unsigned int socklen;
|
||||
int ret;
|
||||
|
||||
assert(host);
|
||||
assert(port);
|
||||
|
||||
ling.l_onoff = 1;
|
||||
ling.l_linger = 0;
|
||||
|
||||
if (ocall_fcntl_long(&ret, socket, F_SETFD, FD_CLOEXEC) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ocall_setsockopt(&ret, socket, SOL_SOCKET, SO_LINGER, &ling,
|
||||
sizeof(ling))
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(*port);
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
if (ocall_bind(&ret, socket, &addr, sizeof(addr)) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
socklen = sizeof(addr);
|
||||
|
||||
if (ocall_getsockname(&ret, socket, (void *)&addr, &socklen, socklen)
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
|
||||
return BHT_OK;
|
||||
|
||||
fail:
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_close(bh_socket_t socket)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_close(&ret, socket) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_connect(bh_socket_t socket, const char *addr, int port)
|
||||
{}
|
||||
{
|
||||
struct sockaddr_in addr_in = { 0 };
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = textual_addr_to_sockaddr(addr, port, &addr_in)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ocall_connect(&ret, socket, &addr_in, addr_len) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (1 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sock == -1) {
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (!cp)
|
||||
return BHT_ERROR;
|
||||
|
||||
*out = inet_network(cp);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_listen(bh_socket_t socket, int max_client)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_listen(&ret, socket, max_client) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_recv(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_send(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_shutdown(bh_socket_t socket)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return shutdown(socket, O_RDWR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -14,11 +14,12 @@ extern "C" {
|
||||
|
||||
#define SOL_SOCKET 1
|
||||
|
||||
#define SO_TYPE 3
|
||||
#define SO_LINGER 13
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
#define SO_TYPE 3
|
||||
|
||||
#define MSG_OOB 0x0001
|
||||
#define MSG_PEEK 0x0002
|
||||
#define MSG_DONTROUTE 0x0004
|
||||
@ -44,6 +45,16 @@ extern "C" {
|
||||
#define SHUT_WR 1
|
||||
#define SHUT_RDWR 2
|
||||
|
||||
/* Address families. */
|
||||
#define AF_INET 2 /* IP protocol family. */
|
||||
|
||||
/* Standard well-defined IP protocols. */
|
||||
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */
|
||||
|
||||
/* Types of sockets. */
|
||||
#define SOCK_DGRAM \
|
||||
2 /* Connectionless, unreliable datagrams of fixed maximum length. */
|
||||
|
||||
struct msghdr {
|
||||
void *msg_name;
|
||||
socklen_t msg_namelen;
|
||||
@ -54,6 +65,36 @@ struct msghdr {
|
||||
int msg_flags;
|
||||
};
|
||||
|
||||
/* Internet address. */
|
||||
struct in_addr {
|
||||
uint32_t s_addr;
|
||||
};
|
||||
typedef struct in_addr in_addr_t;
|
||||
|
||||
/* Structure describing an Internet socket address. */
|
||||
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
|
||||
struct sockaddr_in {
|
||||
uint16_t sin_family;
|
||||
uint16_t sin_port; /* Port number. */
|
||||
struct in_addr sin_addr; /* Internet address. */
|
||||
|
||||
/* Pad to size of `struct sockaddr'. */
|
||||
unsigned char__pad[__SOCK_SIZE__ - sizeof(uint16_t) - sizeof(uint16_t)
|
||||
- sizeof(struct in_addr)];
|
||||
};
|
||||
|
||||
/* Structure used to manipulate the SO_LINGER option. */
|
||||
struct linger {
|
||||
int l_onoff; /* Nonzero to linger on close. */
|
||||
int l_linger; /* Time to linger. */
|
||||
};
|
||||
|
||||
/* Structure describing a generic socket address. */
|
||||
struct sockaddr {
|
||||
unsigned short int sa_family; /* Common data: address family and length. */
|
||||
char sa_data[14]; /* Address data. */
|
||||
};
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
|
||||
|
||||
@ -118,19 +118,34 @@ enclave {
|
||||
int ocall_pthread_rwlock_unlock([user_check]void *rwlock);
|
||||
|
||||
int ocall_get_errno();
|
||||
int ocall_socket(int domain, int type, int protocol);
|
||||
|
||||
/* sockets */
|
||||
int ocall_accept(int sockfd, [in, size=addr_size]void *addr,
|
||||
[in, size=4] uint32_t *addrlen, uint32_t addr_size);
|
||||
int ocall_bind(int sockfd, [in, size=addrlen]const void *addr,
|
||||
uint32_t addrlen);
|
||||
int ocall_connect(int sockfd, [in, size=addrlen]void *addr, uint32_t addrlen);
|
||||
int ocall_getsockname(int sockfd, [in, size=addr_size]void *addr,
|
||||
[in, out, size=4]uint32_t *addrlen, uint32_t addr_size);
|
||||
int ocall_getsockopt(int sockfd, int level, int optname,
|
||||
[out, size=val_buf_size]void *val_buf,
|
||||
unsigned int val_buf_size,
|
||||
[in, out, size=4]void *len_buf);
|
||||
ssize_t ocall_sendmsg(int sockfd,
|
||||
[in, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_listen(int sockfd, int backlog);
|
||||
int ocall_recv(int sockfd, [out, size=len]void *buf, size_t len, int flags);
|
||||
ssize_t ocall_recvmsg(int sockfd,
|
||||
[in, out, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_send(int sockfd, [in, size=len]const void *buf, size_t len, int flags);
|
||||
ssize_t ocall_sendmsg(int sockfd,
|
||||
[in, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_setsockopt(int sockfd, int level, int optname,
|
||||
[in, size=optlen]void *optval,
|
||||
unsigned int optlen);
|
||||
int ocall_shutdown(int sockfd, int how);
|
||||
int ocall_socket(int domain, int type, int protocol);
|
||||
};
|
||||
};
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int
|
||||
ocall_socket(int domain, int type, int protocol)
|
||||
@ -72,4 +74,53 @@ int
|
||||
ocall_shutdown(int sockfd, int how)
|
||||
{
|
||||
return shutdown(sockfd, how);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_setsockopt(int sockfd, int level, int optname, void *optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
return setsockopt(sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_bind(int sockfd, const void *addr, uint32_t addrlen)
|
||||
{
|
||||
return bind(sockfd, (const struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_getsockname(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
|
||||
{
|
||||
return getsockname(sockfd, (struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_listen(int sockfd, int backlog)
|
||||
{
|
||||
return listen(sockfd, backlog);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_accept(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
|
||||
{
|
||||
return accept(sockfd, (struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_recv(int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
return recv(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_send(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
return send(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_connect(int sockfd, void *addr, uint32_t addrlen)
|
||||
{
|
||||
return connect(sockfd, (const struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
Reference in New Issue
Block a user