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:
Jämes Ménétrey
2022-03-25 10:46:29 +01:00
committed by GitHub
parent 5264ce4118
commit 106974d915
7 changed files with 543 additions and 38 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
};
};

View File

@ -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);
}