CVE-2020-15224 (published 2020-10-14T19:15Z)

In Open Enclave before version 0.12.0, an information disclosure vulnerability exists when an enclave application using the syscalls provided by the sockets.edl is loaded by a malicious host application. An attacker who successfully exploited the vulnerability could read privileged data from the enclave heap across trust boundaries. To exploit this vulnerability, an attacker would have to log on to an affected system and run a specially crafted application. The vulnerability would not allow an attacker to elevate user rights directly, but it could be used to obtain information otherwise considered confidential in an enclave, which could be used in further compromises. The issue has been addressed in version 0.12.0 and the current master branch. Users will need to to recompile their applications against the patched libraries to be protected from this vulnerability.

Severity: LOW
CVSS v2 base score: 2.7 (AV:A/AC:L/Au:S/C:P/I:N/A:N)
CVSS v3 base score: 6.8, MEDIUM (CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N)

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/openenclave/openenclave
commit_details: repo_url: https://github.com/openenclave/openenclave
author: Ming-Wei Shih
author_date: 2020-10-12 13:40:03-07:00
msg: Merge pull request from GHSA-525h-wxcc-f66m

Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
repository: repo_url: https://github.com/openenclave/openenclave
repo_name: openenclave/openenclave
description: SDK for developing enclaves
repo_language: C
owner: openenclave
file_changes: filename: socket.edl
change_type: ModificationType.MODIFY
diff: @@ -18,8 +18,6 @@
 
 enclave
 {
-
-
     // Headers needed for integral types
     include "openenclave/corelibc/bits/types.h"
     include "openenclave/bits/edl/syscall_types.h"
@@ -73,7 +71,7 @@ enclave
 
         oe_host_fd_t oe_syscall_accept_ocall(
             oe_host_fd_t sockfd,
-            [in, out, size=addrlen_in] struct oe_sockaddr* addr,
+            [out, size=addrlen_in] struct oe_sockaddr* addr,
             oe_socklen_t addrlen_in,
             [out, count=1] oe_socklen_t* addrlen_out)
             propagate_errno;
@@ -117,7 +115,7 @@ enclave
 
         ssize_t oe_syscall_recv_ocall(
             oe_host_fd_t sockfd,
-            [in, out, size=len] void* buf,
+            [out, size=len] void* buf,
             size_t len,
             int flags)
             propagate_errno;
@@ -127,7 +125,7 @@ enclave
             [out, size=len] void* buf,
             size_t len,
             int flags,
-            [in, out, size=addrlen_in] struct oe_sockaddr* src_addr,
+            [out, size=addrlen_in] struct oe_sockaddr* src_addr,
             oe_socklen_t addrlen_in,
             [out, count=1] oe_socklen_t* addrlen_out)
             propagate_errno;
@@ -186,14 +184,14 @@ enclave
 
         int oe_syscall_getsockname_ocall(
             oe_host_fd_t sockfd,
-            [in, out, size=addrlen_in] struct oe_sockaddr* addr,
+            [out, size=addrlen_in] struct oe_sockaddr* addr,
             oe_socklen_t addrlen_in,
             [out, size=1] oe_socklen_t* addrlen_out)
             propagate_errno;
 
         int oe_syscall_getpeername_ocall(
             oe_host_fd_t sockfd,
-            [in, out, size=addrlen_in] struct oe_sockaddr* addr,
+            [out, size=addrlen_in] struct oe_sockaddr* addr,
             oe_socklen_t addrlen_in,
             [out, size=1] oe_socklen_t* addrlen_out)
             propagate_errno;

programming_language: Lua
filename: fd.h
change_type: ModificationType.MODIFY
diff: @@ -110,7 +110,7 @@ typedef struct _oe_socket_ops
         void* buf,
         size_t len,
         int flags,
-        const struct oe_sockaddr* src_addr,
+        struct oe_sockaddr* src_addr,
         oe_socklen_t* addrlen);
 
     ssize_t (*sendmsg)(oe_fd_t* sock, const struct oe_msghdr* msg, int flags);

programming_language: C
filename: iov.h
change_type: ModificationType.MODIFY
diff: @@ -15,7 +15,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 oe_iov_sync(
     const struct oe_iovec* iov,

programming_language: C++
filename: socket.h
change_type: ModificationType.MODIFY
diff: @@ -133,6 +133,9 @@ OE_EXTERNC_BEGIN
 #define OE_SO_BSDCOMPAT 14
 #define OE_SO_REUSEPORT 15
 
+/* Socket message flags. */
+#define OE_MSG_CTRUNC 0x0008
+
 /* oe_shutdown() options. */
 #define OE_SHUT_RD 0
 #define OE_SHUT_WR 1
@@ -204,7 +207,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 oe_sendmsg(int sockfd, const struct oe_msghdr* buf, int flags);

programming_language: C++
filename: consolefs.c
change_type: ModificationType.MODIFY
diff: @@ -205,12 +205,30 @@ static ssize_t _consolefs_read(oe_fd_t* file_, void* buf, size_t count)
     ssize_t ret = -1;
     file_t* file = _cast_file(file_);
 
-    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);
 
     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;
 }
@@ -220,12 +238,30 @@ static ssize_t _consolefs_write(oe_fd_t* file_, const void* buf, size_t count)
     ssize_t ret = -1;
     file_t* file = _cast_file(file_);
 
-    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/write.html for
+     * for more detail.
+     */
+    if (!file || count > OE_SSIZE_MAX)
         OE_RAISE_ERRNO(OE_EINVAL);
 
     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;
 }
@@ -239,14 +275,26 @@ static ssize_t _consolefs_readv(
     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/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)
@@ -254,6 +302,16 @@ static ssize_t _consolefs_readv(
         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);
@@ -275,14 +333,26 @@ static ssize_t _consolefs_writev(
     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/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)
@@ -290,6 +360,16 @@ static ssize_t _consolefs_writev(
         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)

programming_language: C++
filename: hostepoll.c
change_type: ModificationType.MODIFY
diff: @@ -655,13 +655,31 @@ 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;
 }
@@ -669,13 +687,34 @@ done:
 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,14 +729,26 @@ 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)
@@ -705,6 +756,16 @@ static ssize_t _epoll_readv(
         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,14 +787,26 @@ 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)
@@ -741,6 +814,16 @@ static ssize_t _epoll_writev(
         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)

programming_language: C
filename: hostfs.c
change_type: ModificationType.MODIFY
diff: @@ -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,14 +655,26 @@ 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)
@@ -634,6 +682,16 @@ static ssize_t _hostfs_readv(
         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,14 +716,26 @@ 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)
@@ -673,6 +743,16 @@ static ssize_t _hostfs_writev(
         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;
 }

programming_language: C++
filename: hostresolver.c
change_type: ModificationType.MODIFY
diff: @@ -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,18 +161,61 @@ 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,
@@ -173,17 +223,34 @@ static int _hostresolver_getaddrinfo(
                 &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)
         {

programming_language: C++
filename: hostsock.c
change_type: ModificationType.MODIFY
diff: @@ -349,7 +349,15 @@ static ssize_t _hostsock_recv(
 
     oe_errno = 0;
 
-    if (!sock || (count && !buf))
+    /*
+     * 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/recv.html
+     * for more detail.
+     */
+    if (!sock || (count && !buf) || count > OE_SSIZE_MAX)
         OE_RAISE_ERRNO(OE_EINVAL);
 
     if (buf)
@@ -361,6 +369,16 @@ static ssize_t _hostsock_recv(
     if (oe_syscall_recv_ocall(&ret, sock->host_fd, buf, count, flags) != OE_OK)
         OE_RAISE_ERRNO(OE_EINVAL);
 
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed count.
+     */
+    if (ret > (ssize_t)count)
+    {
+        ret = -1;
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
 done:
     return ret;
 }
@@ -370,19 +388,32 @@ static ssize_t _hostsock_recvfrom(
     void* buf,
     size_t count,
     int flags,
-    const struct oe_sockaddr* src_addr,
+    struct oe_sockaddr* src_addr,
     oe_socklen_t* addrlen)
 {
     ssize_t ret = -1;
     sock_t* sock = _cast_sock(sock_);
     oe_socklen_t addrlen_in = 0;
+    oe_socklen_t addrlen_out = 0;
 
     oe_errno = 0;
 
-    if (!sock || (count && !buf))
+    /*
+     * 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/recvfrom.html
+     * for more detail.
+     */
+    if (!sock || (count && !buf) || count > OE_SSIZE_MAX)
         OE_RAISE_ERRNO(OE_EINVAL);
 
-    if (addrlen)
+    /*
+     * Update the addrlen_in to the value pointed by addrlen
+     * only if both src_addr and addrlen are not NULL.
+     */
+    if (src_addr && addrlen)
         addrlen_in = *addrlen;
 
     if (oe_syscall_recvfrom_ocall(
@@ -391,10 +422,40 @@ static ssize_t _hostsock_recvfrom(
             buf,
             count,
             flags,
-            (struct oe_sockaddr*)src_addr,
+            src_addr,
             addrlen_in,
-            addrlen) != OE_OK)
+            &addrlen_out) != OE_OK)
+    {
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
+    /*
+     * Update the value pointed by addrlen based on the host-set
+     * addrlen_out only if both src_addr and addrlen are not NULL.
+     */
+    if (src_addr && addrlen)
+    {
+        /*
+         * Error out the case if the addrlen_out is greater than the size
+         * of sockaddr_storage.
+         */
+        if (addrlen_out > sizeof(struct oe_sockaddr_storage))
+            OE_RAISE_ERRNO(OE_EINVAL);
+
+        /*
+         * Note that the returned value can still exceed the supplied one,
+         * which indicates a truncation.
+         */
+        *addrlen = addrlen_out;
+    }
+
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed count.
+     */
+    if (ret > (ssize_t)count)
     {
+        ret = -1;
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
@@ -412,15 +473,31 @@ static ssize_t _hostsock_recvmsg(
     oe_errno = 0;
     void* buf = NULL;
     size_t buf_size = 0;
+    size_t data_size = 0;
+    oe_socklen_t namelen_out = 0;
+    size_t controllen_out = 0;
 
     /* Check the parameters. */
     if (!sock || !msg || (msg->msg_iovlen && !msg->msg_iov))
         OE_RAISE_ERRNO(OE_EINVAL);
 
     /* Flatten the IO vector into contiguous heap memory. */
-    if (oe_iov_pack(msg->msg_iov, (int)msg->msg_iovlen, &buf, &buf_size) != 0)
+    if (oe_iov_pack(
+            msg->msg_iov, (int)msg->msg_iovlen, &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/recvmsg.html
+     * for more detail.
+     */
+    if (data_size > OE_SSIZE_MAX)
+        OE_RAISE_ERRNO(OE_EINVAL);
+
     /* Call the host. */
     {
         if (oe_syscall_recvmsg_ocall(
@@ -428,13 +505,13 @@ static ssize_t _hostsock_recvmsg(
                 sock->host_fd,
                 msg->msg_name,
                 msg->msg_namelen,
-                &msg->msg_namelen,
+                &namelen_out,
                 buf,
                 msg->msg_iovlen,
                 buf_size,
                 msg->msg_control,
                 msg->msg_controllen,
-                &msg->msg_controllen,
+                &controllen_out,
                 flags) != OE_OK)
         {
             OE_RAISE_ERRNO(OE_EINVAL);
@@ -444,6 +521,51 @@ static ssize_t _hostsock_recvmsg(
             OE_RAISE_ERRNO(oe_errno);
     }
 
+    if (!msg->msg_name)
+        msg->msg_namelen = 0;
+    else
+    {
+        /*
+         * Error out the case if the namelen_out is greater than the size
+         * of sockaddr_storage.
+         */
+        if (namelen_out > sizeof(struct oe_sockaddr_storage))
+            OE_RAISE_ERRNO(OE_EINVAL);
+
+        /*
+         * Note that the returned value can still exceed the supplied one,
+         * which indicates a truncation.
+         */
+        if (msg->msg_namelen >= namelen_out)
+            msg->msg_namelen = namelen_out;
+    }
+
+    if (!msg->msg_control)
+        msg->msg_controllen = 0;
+    else
+    {
+        /*
+         * Update the msg_controllen only if the supplied value is greater than
+         * or equal to the returned value. Otherwise, keep the msg_controllen
+         * unchanged, which indicates a truncation. In addition, explicitly
+         * setting the MSG_CTRUNC flag when the truncation occurs.
+         */
+        if (msg->msg_controllen >= controllen_out)
+            msg->msg_controllen = controllen_out;
+        else
+            msg->msg_flags |= OE_MSG_CTRUNC;
+    }
+
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return 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(msg->msg_iov, (int)msg->msg_iovlen, buf, buf_size) != 0)
         OE_RAISE_ERRNO(OE_EINVAL);
@@ -467,12 +589,30 @@ static ssize_t _hostsock_send(
 
     oe_errno = 0;
 
-    if (!sock || (count && !buf))
+    /*
+     * 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/send.html for
+     * for more detail.
+     */
+    if (!sock || (count && !buf) || count > OE_SSIZE_MAX)
         OE_RAISE_ERRNO(OE_EINVAL);
 
     if (oe_syscall_send_ocall(&ret, sock->host_fd, buf, count, flags) != OE_OK)
         OE_RAISE_ERRNO(OE_EINVAL);
 
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed count.
+     */
+    if (ret > (ssize_t)count)
+    {
+        ret = -1;
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
 done:
     return ret;
 }
@@ -490,7 +630,15 @@ static ssize_t _hostsock_sendto(
 
     oe_errno = 0;
 
-    if (!sock || (count && !buf))
+    /*
+     * 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/sendto.html
+     * for more detail.
+     */
+    if (!sock || (count && !buf) || count > OE_SSIZE_MAX)
         OE_RAISE_ERRNO(OE_EINVAL);
 
     if (oe_syscall_sendto_ocall(
@@ -505,6 +653,16 @@ static ssize_t _hostsock_sendto(
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed count.
+     */
+    if (ret > (ssize_t)count)
+    {
+        ret = -1;
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
 done:
     return ret;
 }
@@ -518,6 +676,7 @@ static ssize_t _hostsock_sendmsg(
     sock_t* sock = _cast_sock(sock_);
     void* buf = NULL;
     size_t buf_size = 0;
+    size_t data_size = 0;
 
     oe_errno = 0;
 
@@ -526,9 +685,22 @@ static ssize_t _hostsock_sendmsg(
         OE_RAISE_ERRNO(OE_EINVAL);
 
     /* Flatten the IO vector into contiguous heap memory. */
-    if (oe_iov_pack(msg->msg_iov, (int)msg->msg_iovlen, &buf, &buf_size) != 0)
+    if (oe_iov_pack(
+            msg->msg_iov, (int)msg->msg_iovlen, &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/sendmsg.html
+     * for more detail.
+     */
+    if (data_size > OE_SSIZE_MAX)
+        OE_RAISE_ERRNO(OE_EINVAL);
+
     /* Call the host. */
     if (oe_syscall_sendmsg_ocall(
             &ret,
@@ -545,6 +717,16 @@ static ssize_t _hostsock_sendmsg(
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed data_size.
+     */
+    if (ret > (ssize_t)data_size)
+    {
+        ret = -1;
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
 done:
 
     if (buf)
@@ -686,22 +868,42 @@ static int _hostsock_getsockopt(
     int ret = -1;
     sock_t* sock = _cast_sock(sock_);
     oe_socklen_t optlen_in = 0;
+    oe_socklen_t optlen_out = 0;
 
     oe_errno = 0;
 
-    if (!sock)
+    if (!sock || !optval || !optlen)
         OE_RAISE_ERRNO(OE_EINVAL);
 
-    if (optlen)
-        optlen_in = *optlen;
+    optlen_in = *optlen;
 
     if (oe_syscall_getsockopt_ocall(
-            &ret, sock->host_fd, level, optname, optval, optlen_in, optlen) !=
-        OE_OK)
+            &ret,
+            sock->host_fd,
+            level,
+            optname,
+            optval,
+            optlen_in,
+            &optlen_out) != OE_OK)
     {
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * The POSIX specification for getsockopt states that if the size of optval
+     * is greater than the input optlen, then the value stored in the object
+     * pointed to by the optval argument shall be silently truncated. We do this
+     * in the enclave to ensure that the untrusted host has not returned an
+     * arbitrarily large optlen value.
+     * Refer to
+     * https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html
+     * for more detail.
+     */
+    if (optlen_out > optlen_in)
+        optlen_out = optlen_in;
+
+    *optlen = optlen_out;
+
 done:
 
     return ret;
@@ -760,25 +962,42 @@ static int _hostsock_getpeername(
     int ret = -1;
     sock_t* sock = _cast_sock(sock_);
     oe_socklen_t addrlen_in = 0;
+    oe_socklen_t addrlen_out = 0;
 
     oe_errno = 0;
 
-    if (!sock)
+    if (!sock || !addr || !addrlen)
         OE_RAISE_ERRNO(OE_EINVAL);
 
-    if (addrlen)
-        addrlen_in = *addrlen;
+    addrlen_in = *addrlen;
+    if (addrlen_in < 0)
+        OE_RAISE_ERRNO(OE_EINVAL);
 
     if (oe_syscall_getpeername_ocall(
             &ret,
             sock->host_fd,
             (struct oe_sockaddr*)addr,
             addrlen_in,
-            addrlen) != OE_OK)
+            &addrlen_out) != OE_OK)
     {
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * Error out the case if the addrlen_out is greater than the size
+     * of sockaddr_storage.
+     */
+    if (addrlen_out > sizeof(struct oe_sockaddr_storage))
+        OE_RAISE_ERRNO(OE_EINVAL);
+
+    /*
+     * Note that the returned value can still exceed the supplied one,
+     * which indicates a truncation. Refer to
+     * https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html
+     * for more detail.
+     */
+    *addrlen = addrlen_out;
+
 done:
 
     return ret;
@@ -792,25 +1011,39 @@ static int _hostsock_getsockname(
     int ret = -1;
     sock_t* sock = _cast_sock(sock_);
     oe_socklen_t addrlen_in = 0;
+    oe_socklen_t addrlen_out = 0;
 
     oe_errno = 0;
 
-    if (!sock)
+    if (!sock || !addr || !addrlen)
         OE_RAISE_ERRNO(OE_EINVAL);
 
-    if (addrlen)
-        addrlen_in = *addrlen;
+    addrlen_in = *addrlen;
+    if (addrlen_in < 0)
+        OE_RAISE_ERRNO(OE_EINVAL);
 
     if (oe_syscall_getsockname_ocall(
-            &ret,
-            sock->host_fd,
-            (struct oe_sockaddr*)addr,
-            addrlen_in,
-            addrlen) != OE_OK)
+            &ret, sock->host_fd, addr, addrlen_in, &addrlen_out) != OE_OK)
     {
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * Error out the case if the addrlen_out is greater than the size
+     * of sockaddr_storage.
+     */
+    if (addrlen_out > sizeof(struct oe_sockaddr_storage))
+        OE_RAISE_ERRNO(OE_EINVAL);
+
+    /*
+     * Note that the returned value can still exceed the supplied one, which
+     * indicates a truncation. Refer to
+     * https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html
+     * for more detail.
+     */
+    if (addrlen_in >= addrlen_out)
+        *addrlen = addrlen_out;
+
 done:
 
     return ret;
@@ -835,14 +1068,26 @@ static ssize_t _hostsock_readv(
     sock_t* sock = _cast_sock(desc);
     void* buf = NULL;
     size_t buf_size = 0;
+    size_t data_size = 0;
 
     if (!sock || (!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 more detail.
+     */
+    if (data_size > OE_SSIZE_MAX)
+        OE_RAISE_ERRNO(OE_EINVAL);
+
     /* Call the host. */
     if (oe_syscall_recvv_ocall(&ret, sock->host_fd, buf, iovcnt, buf_size) !=
         OE_OK)
@@ -850,6 +1095,16 @@ static ssize_t _hostsock_readv(
         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)
     {
@@ -874,14 +1129,26 @@ static ssize_t _hostsock_writev(
     sock_t* sock = _cast_sock(desc);
     void* buf = NULL;
     size_t buf_size = 0;
+    size_t data_size = 0;
 
     if (!sock || !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_sendv_ocall(&ret, sock->host_fd, buf, iovcnt, buf_size) !=
         OE_OK)
@@ -889,6 +1156,16 @@ static ssize_t _hostsock_writev(
         OE_RAISE_ERRNO(OE_EINVAL);
     }
 
+    /*
+     * Guard the special case that a host sets an arbitrarily large value.
+     * The return value should not exceed data_size.
+     */
+    if (ret > (ssize_t)data_size)
+    {
+        ret = -1;
+        OE_RAISE_ERRNO(OE_EINVAL);
+    }
+
 done:
 
     if (buf)

programming_language: C++
filename: iov.c
change_type: ModificationType.MODIFY
diff: @@ -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)

programming_language: C++
filename: socket.c
change_type: ModificationType.MODIFY
diff: @@ -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;

programming_language: C++
filename: syscall.c
change_type: ModificationType.MODIFY
diff: @@ -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);

programming_language: C++