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