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;