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

commit 30ccba1acc13494fb7e84a2e4e26de0cb9ecd9ad
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 12 05:20:30 2026 +0200

    fs/v9fs: Truncate the readlink() target, and keep the reply off the stack.
    
    v9fs_client_readlink() returned ENAMETOOLONG when the target was longer
    than the buffer, but readlink() must return the first bytes of the
    target.  It also kept the whole reply, PATH_MAX bytes, on the stack,
    which is too much for a small kernel stack.  Read the reply into a
    temporary buffer and copy as much of the target as fits.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 fs/v9fs/client.c | 38 +++++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/fs/v9fs/client.c b/fs/v9fs/client.c
index 8a4f857d22e..c63d24d7a51 100644
--- a/fs/v9fs/client.c
+++ b/fs/v9fs/client.c
@@ -408,7 +408,7 @@ begin_packed_struct struct v9fs_rreadlink_s
 {
   struct v9fs_header_s header;
   uint16_t target_len;
-  uint8_t target[PATH_MAX];
+  uint8_t target[];
 } end_packed_struct;
 
 struct v9fs_map_s
@@ -2381,15 +2381,27 @@ ssize_t v9fs_client_readlink(FAR struct v9fs_client_s 
*client, uint32_t fid,
                              FAR char *buffer, size_t buflen)
 {
   struct v9fs_readlink_s request;
-  struct v9fs_rreadlink_s response;
+  FAR struct v9fs_rreadlink_s *response;
   struct iovec wiov[1];
   struct iovec riov[1];
+  FAR char *rbuf;
+  size_t len;
   int ret;
 
   /* size[4] Treadlink tag[2] fid[4]
    * size[4] Rreadlink tag[2] target[s]
+   *
+   * The response is too big for the stack.
    */
 
+  rbuf = lib_get_tempbuffer(sizeof(struct v9fs_rreadlink_s) + PATH_MAX);
+  if (rbuf == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  response = (FAR struct v9fs_rreadlink_s *)rbuf;
+
   request.fid = fid;
   request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ;
   request.header.type = V9FS_TREADLINK;
@@ -2397,22 +2409,30 @@ ssize_t v9fs_client_readlink(FAR struct v9fs_client_s 
*client, uint32_t fid,
 
   wiov[0].iov_base = &request;
   wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
-  riov[0].iov_base = &response;
-  riov[0].iov_len = sizeof(response);
+  riov[0].iov_base = response;
+  riov[0].iov_len = sizeof(struct v9fs_rreadlink_s) + PATH_MAX;
 
   ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
                         request.header.tag);
   if (ret < 0)
     {
-      return ret;
+      goto out;
     }
 
-  if (response.target_len > buflen)
+  if (response->target_len > PATH_MAX)
     {
-      return -ENAMETOOLONG;
+      ret = -EIO;
+      goto out;
     }
 
-  memcpy(buffer, response.target, response.target_len);
-  return response.target_len;
+  /* Like readlink(), truncate the target to the size of the buffer */
+
+  len = MIN(response->target_len, buflen);
+  memcpy(buffer, response->target, len);
+  ret = len;
+
+out:
+  lib_put_tempbuffer(rbuf);
+  return ret;
 }
 #endif

Reply via email to