This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new b5b8c36b22c libs/libc: validate iovcnt bounds and iov_len overflow in 
preadv/pwritev
b5b8c36b22c is described below

commit b5b8c36b22ca31b243465cd9ea1dedc195225122
Author: Swatantra Yadav <[email protected]>
AuthorDate: Sun Nov 8 13:06:09 2026 +0530

    libs/libc: validate iovcnt bounds and iov_len overflow in preadv/pwritev
    
    Add POSIX-mandated validation to preadv() and pwritev():
    
    1. Reject iovcnt <= 0 or iovcnt > IOV_MAX with ERROR (errno = EINVAL).
    2. Reject iov == NULL with ERROR (errno = EFAULT).
    3. Reject offset < 0 with ERROR (errno = EINVAL).
    4. Validate that total iov_len does not overflow SSIZE_MAX with ERROR
       (errno = EINVAL).
    5. Validate non-NULL iov_base for non-zero iov_len entries with ERROR
       (errno = EFAULT).
    6. In preadv(), fix partial read error handling to preserve the count of
       bytes already transferred (return ntotal > 0 ? ntotal : ERROR),
       aligning with pwritev().
    7. Include <errno.h> and <limits.h> in lib_preadv.c and lib_pwritev.c.
    
    Reference: POSIX.1-2024 (IEEE Std 1003.1-2024) preadv/pwritev [EINVAL].
    
    Assisted-by: gemini-3.8-flash
    Signed-off-by: Swatantra Yadav <[email protected]>
---
 libs/libc/uio/lib_preadv.c  | 44 +++++++++++++++++++++++++++++++++++++++++++-
 libs/libc/uio/lib_pwritev.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/libs/libc/uio/lib_preadv.c b/libs/libc/uio/lib_preadv.c
index 709f89648f1..c402eecd7ea 100644
--- a/libs/libc/uio/lib_preadv.c
+++ b/libs/libc/uio/lib_preadv.c
@@ -24,6 +24,8 @@
  * Included Files
  ****************************************************************************/
 
+#include <errno.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
@@ -47,9 +49,49 @@ ssize_t preadv(int fildes, FAR const struct iovec *iov, int 
iovcnt,
   ssize_t ntotal;
   ssize_t nread;
   size_t remaining;
+  size_t len = 0;
   FAR uint8_t *buffer;
   int i;
 
+  /* Check buffer count and pointer for iovec */
+
+  if (iovcnt <= 0 || iovcnt > IOV_MAX)
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  if (iov == NULL)
+    {
+      set_errno(EFAULT);
+      return ERROR;
+    }
+
+  if (offset < 0)
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  /* Verify each iovec entry and check for total length overflow */
+
+  for (i = 0; i < iovcnt; i++)
+    {
+      if (SSIZE_MAX - len < iov[i].iov_len)
+        {
+          set_errno(EINVAL);
+          return ERROR;
+        }
+
+      len += iov[i].iov_len;
+
+      if (iov[i].iov_base == NULL && iov[i].iov_len != 0)
+        {
+          set_errno(EFAULT);
+          return ERROR;
+        }
+    }
+
   /* Process each entry in the struct iovec array */
 
   for (i = 0, ntotal = 0; i < iovcnt; i++)
@@ -73,7 +115,7 @@ ssize_t preadv(int fildes, FAR const struct iovec *iov, int 
iovcnt,
 
               if (nread < 0)
                 {
-                  return nread;
+                  return ntotal > 0 ? ntotal : ERROR;
                 }
 
               /* Check for an end-of-file condition */
diff --git a/libs/libc/uio/lib_pwritev.c b/libs/libc/uio/lib_pwritev.c
index 2cd195eff94..256971e7cbd 100644
--- a/libs/libc/uio/lib_pwritev.c
+++ b/libs/libc/uio/lib_pwritev.c
@@ -24,10 +24,11 @@
  * Included Files
  ****************************************************************************/
 
+#include <errno.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
-#include <errno.h>
 
 /****************************************************************************
  * Public Functions
@@ -48,9 +49,49 @@ ssize_t pwritev(int fildes, FAR const struct iovec *iov, int 
iovcnt,
   ssize_t ntotal;
   ssize_t nwritten;
   size_t remaining;
+  size_t len = 0;
   FAR uint8_t *buffer;
   int i;
 
+  /* Check buffer count and pointer for iovec */
+
+  if (iovcnt <= 0 || iovcnt > IOV_MAX)
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  if (iov == NULL)
+    {
+      set_errno(EFAULT);
+      return ERROR;
+    }
+
+  if (offset < 0)
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  /* Verify each iovec entry and check for total length overflow */
+
+  for (i = 0; i < iovcnt; i++)
+    {
+      if (SSIZE_MAX - len < iov[i].iov_len)
+        {
+          set_errno(EINVAL);
+          return ERROR;
+        }
+
+      len += iov[i].iov_len;
+
+      if (iov[i].iov_base == NULL && iov[i].iov_len != 0)
+        {
+          set_errno(EFAULT);
+          return ERROR;
+        }
+    }
+
   /* Process each entry in the struct iovec array */
 
   for (i = 0, ntotal = 0; i < iovcnt; i++)
@@ -74,7 +115,7 @@ ssize_t pwritev(int fildes, FAR const struct iovec *iov, int 
iovcnt,
 
               if (nwritten < 0)
                 {
-                  return ntotal ? ntotal : ERROR;
+                  return ntotal > 0 ? ntotal : ERROR;
                 }
 
               /* Update pointers and counts in order to handle partial

Reply via email to