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

acassis 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 0554575de00 net/socket: Limit the kernel copy of an address to its 
size.
0554575de00 is described below

commit 0554575de00f9c1adff1d2e8718a5de146135b40
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Nov 6 11:03:22 2026 +0100

    net/socket: Limit the kernel copy of an address to its size.
    
    In a kernel build, sendto() and recvfrom() keep the address in a struct
    sockaddr_storage on the kernel stack.  sendto() copied tolen bytes to it, 
and
    tolen comes from the program, so a large tolen wrote over the kernel stack.
    recvfrom() copied *fromlen bytes from it back to the program, so a large
    *fromlen read past it.  Also, a socket type that returns no address left the
    structure as the stack had it, and the program got these bytes.
    
    sendto() now returns EINVAL when tolen is larger than the structure, as 
other
    systems do.  recvfrom() clears the structure and uses its own copy of the
    length, which is at most the size of the structure.  It copies back at most
    that length, also when the socket gives a longer length (usrsock gives the
    length before truncation).  It writes the length only when fromlen is not
    NULL.
    
    Flat and protected builds have no such copy and do not change.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 net/socket/recvfrom.c | 28 ++++++++++++++++++++++++++--
 net/socket/sendto.c   |  8 ++++++++
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c
index 6aa59dec38c..91b1b3ab963 100644
--- a/net/socket/recvfrom.c
+++ b/net/socket/recvfrom.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <sys/param.h>
 #include <assert.h>
 #include <errno.h>
 #include <string.h>
@@ -162,6 +163,9 @@ ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int 
flags,
 #ifdef CONFIG_BUILD_KERNEL
   struct sockaddr_storage kaddr;
   FAR struct sockaddr *ufrom;
+  FAR socklen_t *ufromlen;
+  socklen_t kfromlen = 0;
+  socklen_t kfromsize = 0;
   FAR void *kbuf;
   FAR void *ubuf;
 #endif
@@ -187,9 +191,23 @@ ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, 
int flags,
 
   /* Copy the address data to kernel, store the original user pointer */
 
+  ufromlen = fromlen;
   if ((ufrom = from) != NULL)
     {
+      /* A socket type can return no address, and the kernel copy of the
+       * address has a fixed size.  The program can also change its length
+       * while this call waits.
+       */
+
+      memset(&kaddr, 0, sizeof(kaddr));
+      if (fromlen != NULL)
+        {
+          kfromlen = MIN(*fromlen, sizeof(kaddr));
+          kfromsize = kfromlen;
+        }
+
       from = (FAR struct sockaddr *)&kaddr;
+      fromlen = &kfromlen;
     }
 #endif
 
@@ -213,11 +231,17 @@ ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, 
int flags,
 
   kmm_free(kbuf);
 
-  /* Copy the address back to user */
+  /* Copy the address back to user.  The length that the socket gives can
+   * be larger than the buffer: then the address is cut, as in a flat build.
+   */
 
   if (ret >= 0 && ufrom)
     {
-      memcpy(ufrom, &kaddr, *fromlen);
+      memcpy(ufrom, &kaddr, MIN(kfromlen, kfromsize));
+      if (ufromlen != NULL)
+        {
+          *ufromlen = kfromlen;
+        }
     }
 
 errout_with_cancelpt:
diff --git a/net/socket/sendto.c b/net/socket/sendto.c
index 462dfb7badc..3058a188701 100644
--- a/net/socket/sendto.c
+++ b/net/socket/sendto.c
@@ -213,6 +213,14 @@ ssize_t sendto(int sockfd, FAR const void *buf, size_t 
len, int flags,
   enter_cancellation_point();
 
 #ifdef CONFIG_BUILD_KERNEL
+  /* The kernel copy of the address has a fixed size */
+
+  if (to != NULL && tolen > sizeof(kaddr))
+    {
+      ret = -EINVAL;
+      goto errout_with_cancelpt;
+    }
+
   /* Allocate memory and copy user buffer to kernel */
 
   kbuf = kmm_malloc(len);

Reply via email to