@@ -655,27 +655,66 @@ static ssize_t _epoll_read(oe_fd_t* epoll_, void* buf, size_t count)

oe_errno = 0;

if (!file)
/*
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html for
* for more detail.
*/
if (!file || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_read_ocall(&ret, file->host_fd, buf, count) != OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
}

static ssize_t _epoll_write(oe_fd_t* epoll_, const void* buf, size_t count)
{
ssize_t ret = -1;
epoll_t* epoll = _cast_epoll(epoll_);
epoll_t* file = _cast_epoll(epoll_);

oe_errno = 0;

/*
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html for
* for more detail.
*/
if (!file || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_write_ocall(&ret, epoll->host_fd, buf, count) != OE_OK)
if (oe_syscall_write_ocall(&ret, file->host_fd, buf, count) != OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
@@ -690,21 +729,43 @@ static ssize_t _epoll_readv(
epoll_t* file = _cast_epoll(desc);
void* buf = NULL;
size_t buf_size = 0;
size_t data_size = 0;

if (!file || (iovcnt && !iov) || iovcnt < 0 || iovcnt > OE_IOV_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Flatten the IO vector into contiguous heap memory. */
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size) != 0)
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size, &data_size) != 0)
OE_RAISE_ERRNO(OE_ENOMEM);

/*
* According to the POSIX specification, when the data_size is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html for
* for more detail.
*/
if (data_size > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_readv_ocall(&ret, file->host_fd, buf, iovcnt, buf_size) !=
OE_OK)
{
OE_RAISE_ERRNO(OE_EINVAL);
}

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed data_size.
*/
if (ret > (ssize_t)data_size)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

/* Synchronize data read with IO vector. */
if (oe_iov_sync(iov, iovcnt, buf, buf_size) != 0)
OE_RAISE_ERRNO(OE_EINVAL);
@@ -726,21 +787,43 @@ static ssize_t _epoll_writev(
epoll_t* file = _cast_epoll(desc);
void* buf = NULL;
size_t buf_size = 0;
size_t data_size = 0;

if (!file || (iovcnt && !iov) || iovcnt < 0 || iovcnt > OE_IOV_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Flatten the IO vector into contiguous heap memory. */
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size) != 0)
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size, &data_size) != 0)
OE_RAISE_ERRNO(OE_ENOMEM);

/*
* According to the POSIX specification, when the data_size is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html
* for more detail.
*/
if (data_size > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_writev_ocall(&ret, file->host_fd, buf, iovcnt, buf_size) !=
OE_OK)
{
OE_RAISE_ERRNO(OE_EINVAL);
}

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed data_size.
*/
if (ret > (ssize_t)data_size)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:

if (buf)
@@ -538,13 +538,31 @@ static ssize_t _hostfs_read(oe_fd_t* desc, void* buf, size_t count)
ssize_t ret = -1;
file_t* file = _cast_file(desc);

if (!file)
/*
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html for
* for more detail.
*/
if (!file || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host to perform the read(). */
if (oe_syscall_read_ocall(&ret, file->host_fd, buf, count) != OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
}
@@ -598,14 +616,32 @@ static ssize_t _hostfs_write(oe_fd_t* desc, const void* buf, size_t count)
ssize_t ret = -1;
file_t* file = _cast_file(desc);

/* Check parameters. */
if (!file || (count && !buf))
/*
* Check parameters.
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html for
* for more detail.
*/
if (!file || (count && !buf) || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_write_ocall(&ret, file->host_fd, buf, count) != OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
}
@@ -619,21 +655,43 @@ static ssize_t _hostfs_readv(
file_t* file = _cast_file(desc);
void* buf = NULL;
size_t buf_size = 0;
size_t data_size = 0;

if (!file || (!iov && iovcnt) || iovcnt < 0 || iovcnt > OE_IOV_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Flatten the IO vector into contiguous heap memory. */
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size) != 0)
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size, &data_size) != 0)
OE_RAISE_ERRNO(OE_ENOMEM);

/*
* According to the POSIX specification, when the data_size is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html for
* for more detail.
*/
if (data_size > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_readv_ocall(&ret, file->host_fd, buf, iovcnt, buf_size) !=
OE_OK)
{
OE_RAISE_ERRNO(OE_EINVAL);
}

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed data_size.
*/
if (ret > (ssize_t)data_size)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

/* Synchronize data read with IO vector. */
if (ret > 0)
{
@@ -658,21 +716,43 @@ static ssize_t _hostfs_writev(
file_t* file = _cast_file(desc);
void* buf = NULL;
size_t buf_size = 0;
size_t data_size = 0;

if (!file || !iov || iovcnt < 0 || iovcnt > OE_IOV_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Flatten the IO vector into contiguous heap memory. */
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size) != 0)
if (oe_iov_pack(iov, iovcnt, &buf, &buf_size, &data_size) != 0)
OE_RAISE_ERRNO(OE_ENOMEM);

/*
* According to the POSIX specification, when the data_size is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html
* for more detail.
*/
if (data_size > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

/* Call the host. */
if (oe_syscall_writev_ocall(&ret, file->host_fd, buf, iovcnt, buf_size) !=
OE_OK)
{
OE_RAISE_ERRNO(OE_EINVAL);
}

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed data_size.
*/
if (ret > (ssize_t)data_size)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:

if (buf)
@@ -756,13 +836,31 @@ static ssize_t _hostfs_pread(
ssize_t ret = -1;
file_t* file = _cast_file(desc);

if (!file)
/*
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html for
* for more detail.
*/
if (!file || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

if (oe_syscall_pread_ocall(&ret, file->host_fd, buf, count, offset) !=
OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
}
@@ -776,13 +874,31 @@ static ssize_t _hostfs_pwrite(
ssize_t ret = -1;
file_t* file = _cast_file(desc);

if (!file)
/*
* According to the POSIX specification, when the count is greater
* than SSIZE_MAX, the result is implementation-defined. OE raises an
* error in this case.
* Refer to
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
* for more detail.
*/
if (!file || count > OE_SSIZE_MAX)
OE_RAISE_ERRNO(OE_EINVAL);

if (oe_syscall_pwrite_ocall(&ret, file->host_fd, buf, count, offset) !=
OE_OK)
OE_RAISE_ERRNO(OE_EINVAL);

/*
* Guard the special case that a host sets an arbitrarily large value.
* The returned value should not exceed count.
*/
if (ret > (ssize_t)count)
{
ret = -1;
OE_RAISE_ERRNO(OE_EINVAL);
}

done:
return ret;
}
@@ -11,6 +11,7 @@
#include <openenclave/internal/syscall/raise.h>
#include <openenclave/internal/syscall/sys/socket.h>
#include <openenclave/internal/syscall/netdb.h>
#include <openenclave/internal/syscall/netinet/in.h>
#include <openenclave/internal/syscall/resolver.h>
#include <openenclave/internal/safemath.h>
#include <openenclave/internal/calls.h>
@@ -24,6 +25,14 @@

#define RESOLV_MAGIC 0x536f636b

/*
* The definition of AF_INET6 on Windows (i.e., 23) is different from that of on
* Linux (i.e., 10). Given that the internal socket.h conforms to the
* implementation of Linux, we explicitly define the Windows-specific value
* here for being compatible with a Windows host.
*/
#define OE_AF_INET6_WIN 23

// The host resolver is not actually a device in the file descriptor sense.
typedef struct _resolver
{
@@ -116,27 +125,25 @@ static int _hostresolver_getaddrinfo(
for (;;)
{
int retval = 0;
size_t canonnamelen = 0;
size_t canonnamelen_in = 0;
size_t canonnamelen_out = 0;
struct oe_addrinfo p_out;

if (!(p = oe_calloc(1, sizeof(struct oe_addrinfo))))
{
ret = OE_EAI_MEMORY;
goto done;
}
memset(&p_out, 0, sizeof(struct oe_addrinfo));

/* Determine required size ai_addr and ai_canonname buffers. */
if (oe_syscall_getaddrinfo_read_ocall(
&retval,
handle,
&p->ai_flags,
&p->ai_family,
&p->ai_socktype,
&p->ai_protocol,
p->ai_addrlen,
&p->ai_addrlen,
&p_out.ai_flags,
&p_out.ai_family,
&p_out.ai_socktype,
&p_out.ai_protocol,
p_out.ai_addrlen,
&p_out.ai_addrlen,
NULL,
canonnamelen,
&canonnamelen,
canonnamelen_in,
&canonnamelen_out,
NULL) != OE_OK)
{
ret = OE_EAI_SYSTEM;
@@ -154,36 +161,96 @@ static int _hostresolver_getaddrinfo(
OE_RAISE_ERRNO(oe_errno);
}

if (p->ai_addrlen && !(p->ai_addr = oe_calloc(1, p->ai_addrlen)))
/*
* Guard the special case that a host sets an arbitrarily large value.
* Based on the implementation of MUSL, the ai_addrlen can only be
* sizeof(struct sockaddr_in) when the family is AF_INET or
* sizeof(struct sockaddr_in6) when the family is AF_INET6.
* When the family is AF_UNSPEC, OE checks the ai_addrlen against
* sizeof(struct sockaddr_in6) as it should cover AF_INET and
* AF_INET6 cases. Besides, OE errors out other family types.
*/
switch (p_out.ai_family)
{
case OE_AF_INET:
if (p_out.ai_addrlen != sizeof(struct oe_sockaddr))
{
ret = OE_EAI_FAIL;
goto done;
}
break;
case OE_AF_INET6:
case OE_AF_INET6_WIN:
case OE_AF_UNSPEC:
if (p_out.ai_addrlen != sizeof(struct oe_sockaddr_in6))
{
ret = OE_EAI_FAIL;
goto done;
}
break;
default:
ret = OE_EAI_FAIL;
goto done;
}

if (!(p = oe_calloc(1, sizeof(struct oe_addrinfo))))
{
ret = OE_EAI_MEMORY;
goto done;
}

if (p_out.ai_addrlen && !(p->ai_addr = oe_calloc(1, p_out.ai_addrlen)))
{
ret = OE_EAI_MEMORY;
goto done;
}

if (canonnamelen && !(p->ai_canonname = oe_calloc(1, canonnamelen)))
if (canonnamelen_out &&
!(p->ai_canonname = oe_calloc(1, canonnamelen_out)))
{
ret = OE_EAI_MEMORY;
goto done;
}

/* Set canonnamelen_in to the expected length of p->ai_cannonname
* returned by the host. */
canonnamelen_in = canonnamelen_out;

if (oe_syscall_getaddrinfo_read_ocall(
&retval,
handle,
&p->ai_flags,
&p->ai_family,
&p->ai_socktype,
&p->ai_protocol,
p->ai_addrlen,
p_out.ai_addrlen,
&p->ai_addrlen,
p->ai_addr,
canonnamelen,
&canonnamelen,
canonnamelen_in,
&canonnamelen_out,
p->ai_canonname) != OE_OK)
{
ret = OE_EAI_SYSTEM;
OE_RAISE_ERRNO(OE_EINVAL);
}

/*
* Lock down the out parameters, which are expected
* to be the same as the first invocation. Also,
* p->ai_cannonname is expected to be NULL-terminated.
*/
if ((p->ai_flags != p_out.ai_flags) ||
(p->ai_family != p_out.ai_family) ||
(p->ai_socktype != p_out.ai_socktype) ||
(p->ai_protocol != p_out.ai_protocol) ||
(p->ai_addrlen != p_out.ai_addrlen) ||
(canonnamelen_out != canonnamelen_in) ||
(canonnamelen_out && p->ai_canonname[canonnamelen_out - 1] != '\0'))
{
ret = OE_EAI_FAIL;
goto done;
}

/* Append to the list. */
if (tail)
{

Large diffs are not rendered by default.

@@ -17,7 +17,8 @@ int oe_iov_pack(
const struct oe_iovec* iov,
int iovcnt,
void** buf_out,
size_t* buf_size_out)
size_t* buf_size_out,
size_t* data_size_out)
{
int ret = -1;
struct oe_iovec* buf = NULL;
@@ -30,8 +31,12 @@ int oe_iov_pack(
if (buf_size_out)
*buf_size_out = 0;

if (data_size_out)
*data_size_out = 0;

/* Reject invalid parameters. */
if (iovcnt < 0 || (iovcnt > 0 && !iov) || !buf_out || !buf_size_out)
if (iovcnt < 0 || (iovcnt > 0 && !iov) || !buf_out || !buf_size_out ||
!data_size_out)
goto done;

/* Handle zero-sized iovcnt up front. */
@@ -47,6 +52,7 @@ int oe_iov_pack(

*buf_out = buf;
*buf_size_out = buf_size;
*data_size_out = data_size;
buf = NULL;
ret = 0;
goto done;
@@ -97,6 +103,7 @@ int oe_iov_pack(

*buf_out = buf;
*buf_size_out = buf_size;
*data_size_out = data_size;
buf = NULL;
ret = 0;

@@ -155,7 +162,8 @@ int oe_iov_sync(
if (src_size != dest_size)
goto done;

if (src < (uint8_t*)buf || src > (uint8_t*)buf + buf_size)
if (src < (uint8_t*)buf || src + src_size < src ||
src + src_size > (uint8_t*)buf + buf_size)
goto done;

if (oe_memcpy_s(dest, dest_size, src, src_size) != OE_OK)
@@ -197,7 +197,7 @@ ssize_t oe_recvfrom(
void* buf,
size_t len,
int flags,
const struct oe_sockaddr* src_addr,
struct oe_sockaddr* src_addr,
oe_socklen_t* addrlen)
{
ssize_t ret = -1;
@@ -617,8 +617,7 @@ static long _syscall(
void* buf = (void*)arg2;
size_t len = (size_t)arg3;
int flags = (int)arg4;
const struct oe_sockaddr* dest_add =
(const struct oe_sockaddr*)arg5;
struct oe_sockaddr* dest_add = (struct oe_sockaddr*)arg5;
oe_socklen_t* addrlen = (oe_socklen_t*)arg6;

ret = oe_recvfrom(sockfd, buf, len, flags, dest_add, addrlen);