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 56f37d5ba44 net/local: fix integer overflow in sendpacket and SCM leak 
in sendmsg
56f37d5ba44 is described below

commit 56f37d5ba443006884d72d80e4f3be065a1bcfe9
Author: Swatantra Yadav <[email protected]>
AuthorDate: Thu Nov 5 17:24:40 2026 +0530

    net/local: fix integer overflow in sendpacket and SCM leak in sendmsg
    
    1. In local_send_preamble(), packet length was accumulated into
       lc_size_t pktlen (uint16_t when CONFIG_DEV_PIPE_MAXSIZE <= 65535).
       If the sum of iov_len values exceeded 65535, pktlen silently wrapped
       around before checking against rcvsize, allowing oversized datagrams
       to corrupt FIFO packet framing. Accumulate total into size_t and
       validate against payload space before adding.
    2. In local_send_packet(), sendlen was typed lc_size_t. Stream socket
       writes (SOCK_STREAM) larger than 64 KB wrapped around modulo 65536.
       Change sendlen and function return type to ssize_t, and handle zero
       iovec count by returning 0.
    3. In local_sendmsg(), the return value of local_sendto() / local_send()
       was assigned to size_t len, making if (len < 0 && count > 0) dead
       code and leaking SCM file descriptors on error. Use ssize_t ret.
    4. In local_sendmsg(), reject stream socket sends (SOCK_STREAM) with
       control messages (SCM_RIGHTS) when total payload length is zero with
       -EINVAL (matching Linux unix(7)) to avoid queuing orphaned descriptors
       when no data is written to wake up the receiver.
    
    Signed-off-by: Swatantra Yadav <[email protected]>
    Assisted-by: Google Gemini
---
 net/local/local.h            |  5 +++--
 net/local/local_sendmsg.c    | 33 +++++++++++++++++++++++-------
 net/local/local_sendpacket.c | 48 ++++++++++++++++++++++++++++----------------
 3 files changed, 60 insertions(+), 26 deletions(-)

diff --git a/net/local/local.h b/net/local/local.h
index e1549c2118b..7d6e65e38a8 100644
--- a/net/local/local.h
+++ b/net/local/local.h
@@ -523,8 +523,9 @@ int local_send_preamble(FAR struct local_conn_s *conn,
  *
  ****************************************************************************/
 
-int local_send_packet(FAR struct file *filep, FAR const struct iovec *buf,
-                      size_t len);
+ssize_t local_send_packet(FAR struct file *filep,
+                          FAR const struct iovec *buf,
+                          size_t len);
 
 /****************************************************************************
  * Name: local_recvmsg
diff --git a/net/local/local_sendmsg.c b/net/local/local_sendmsg.c
index 73e4b2f8556..ba522adab15 100644
--- a/net/local/local_sendmsg.c
+++ b/net/local/local_sendmsg.c
@@ -458,7 +458,8 @@ ssize_t local_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
   FAR const struct sockaddr *to = msg->msg_name;
   FAR const struct iovec *buf = msg->msg_iov;
   socklen_t tolen = msg->msg_namelen;
-  size_t len = msg->msg_iovlen;
+  size_t iovlen = msg->msg_iovlen;
+  ssize_t ret;
 
 #ifdef CONFIG_NET_LOCAL_SCM
   FAR struct local_conn_s *conn = psock->s_conn;
@@ -467,6 +468,24 @@ ssize_t local_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
   if (msg->msg_control &&
       msg->msg_controllen > sizeof(struct cmsghdr))
     {
+      /* Stream sockets require data to be sent with control messages */
+
+      if (psock->s_type == SOCK_STREAM)
+        {
+          size_t total = 0;
+          size_t i;
+
+          for (i = 0; i < iovlen; i++)
+            {
+              total += buf[i].iov_len;
+            }
+
+          if (total == 0)
+            {
+              return -EINVAL;
+            }
+        }
+
       count = local_sendctl(conn, msg);
       if (count < 0)
         {
@@ -474,19 +493,19 @@ ssize_t local_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
         }
     }
 
-  len = to ? local_sendto(psock, buf, len, flags, to, tolen) :
-             local_send(psock, buf, len, flags);
+  ret = to ? local_sendto(psock, buf, iovlen, flags, to, tolen) :
+             local_send(psock, buf, iovlen, flags);
 
-  if (len < 0 && count > 0)
+  if (ret < 0 && count > 0)
     {
       local_lock();
       local_freectl(conn, count);
       local_unlock();
     }
 #else
-  len = to ? local_sendto(psock, buf, len, flags, to, tolen) :
-             local_send(psock, buf, len, flags);
+  ret = to ? local_sendto(psock, buf, iovlen, flags, to, tolen) :
+             local_send(psock, buf, iovlen, flags);
 #endif
 
-  return len;
+  return ret;
 }
diff --git a/net/local/local_sendpacket.c b/net/local/local_sendpacket.c
index 54bb1632aba..3b49810423d 100644
--- a/net/local/local_sendpacket.c
+++ b/net/local/local_sendpacket.c
@@ -59,8 +59,9 @@
  *
  ****************************************************************************/
 
-static int local_fifo_write(FAR struct file *filep, FAR const uint8_t *buf,
-                            size_t len)
+static ssize_t local_fifo_write(FAR struct file *filep,
+                                FAR const uint8_t *buf,
+                                size_t len)
 {
   ssize_t nwritten = 0;
   ssize_t ret = 0;
@@ -120,21 +121,27 @@ int local_send_preamble(FAR struct local_conn_s *conn,
 {
   FAR const struct iovec *end = buf + len;
   FAR const struct iovec *iov;
-  int ret;
+  ssize_t ret;
   lc_size_t pathlen;
   lc_size_t pktlen;
+  size_t total = 0;
 
-  /* Send the packet length */
-
-  for (pktlen = 0, iov = buf; iov != end; iov++)
+  if (rcvsize <= sizeof(lc_size_t))
     {
-      pktlen += iov->iov_len;
+      return -EMSGSIZE;
     }
 
-  if (pktlen > rcvsize - sizeof(lc_size_t))
+  /* Send the packet length */
+
+  for (iov = buf; iov != end; iov++)
     {
-      nerr("ERROR: Packet is too big: %d\n", pktlen);
-      return -EMSGSIZE;
+      if (iov->iov_len > rcvsize - sizeof(lc_size_t) - total)
+        {
+          nerr("ERROR: Packet is too big\n");
+          return -EMSGSIZE;
+        }
+
+      total += iov->iov_len;
     }
 
   pathlen = strlen(conn->lc_path);
@@ -142,10 +149,11 @@ int local_send_preamble(FAR struct local_conn_s *conn,
                          sizeof(lc_size_t));
   if (ret != sizeof(lc_size_t))
     {
-      nerr("ERROR: local send path length failed ret: %d\n", ret);
+      nerr("ERROR: local send path length failed ret: %zd\n", ret);
       return ret;
     }
 
+  pktlen = total;
   ret = local_fifo_write(filep, (FAR const uint8_t *)&pktlen,
                          sizeof(lc_size_t));
   if (ret != sizeof(lc_size_t))
@@ -174,22 +182,28 @@ int local_send_preamble(FAR struct local_conn_s *conn,
  *
  ****************************************************************************/
 
-int local_send_packet(FAR struct file *filep, FAR const struct iovec *buf,
-                      size_t len)
+ssize_t local_send_packet(FAR struct file *filep,
+                          FAR const struct iovec *buf,
+                          size_t len)
 {
   FAR const struct iovec *end = buf + len;
   FAR const struct iovec *iov;
-  int ret = -EINVAL;
-  lc_size_t sendlen;
+  ssize_t ret = 0;
+  ssize_t sendlen = 0;
+
+  if (len == 0)
+    {
+      return 0;
+    }
 
-  for (sendlen = 0, iov = buf; iov != end; iov++)
+  for (iov = buf; iov != end; iov++)
     {
       ret = local_fifo_write(filep, iov->iov_base, iov->iov_len);
       if (ret < 0)
         {
           if (ret != -EAGAIN)
             {
-              nerr("ERROR: local send packet failed ret: %d\n", ret);
+              nerr("ERROR: local send packet failed ret: %zd\n", ret);
             }
 
           break;

Reply via email to