This is an automated email from the ASF dual-hosted git repository.
linguini1 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 1ceda8c02f6 fs/pseudofile: fix buffer sizing and sparse growth.
1ceda8c02f6 is described below
commit 1ceda8c02f66658ba9b3ff27b1ae877e4f84fb9d
Author: ywhkkx <[email protected]>
AuthorDate: Thu Aug 6 17:42:27 2026 +0800
fs/pseudofile: fix buffer sizing and sparse growth.
Grow the in-memory pseudofile buffer by doubling instead of
1<<LOG2_CEIL, which can under-allocate on 32-bit targets for large
expand sizes. Also:
* reject size_t wrap before expand on write (-EFBIG)
* clear newly addressed bytes when the file grows
* route truncate growth through the same expand path
Impact: CONFIG_PSEUDOFS_FILE expand/write/truncate only; no API or
build-system change.
Testing: host arithmetic PoC blocked; WSL sim:pseudofile-poc
(SIM_M32+KASAN) write returns -ENOMEM instead of SIGSEGV in memcpy.
Signed-off-by: ywhkkx <[email protected]>
---
fs/vfs/fs_pseudofile.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 63 insertions(+), 5 deletions(-)
diff --git a/fs/vfs/fs_pseudofile.c b/fs/vfs/fs_pseudofile.c
index e5204b0641b..c1d8294caa9 100644
--- a/fs/vfs/fs_pseudofile.c
+++ b/fs/vfs/fs_pseudofile.c
@@ -27,6 +27,7 @@
#include <nuttx/config.h>
#include <stdio.h>
+#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
@@ -36,7 +37,6 @@
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/ioctl.h>
-#include <nuttx/lib/math32.h>
#include "inode/inode.h"
#include "fs_heap.h"
@@ -169,25 +169,67 @@ static int pseudofile_close(FAR struct file *filep)
return OK;
}
+/* Grow allocation by doubling until it covers the requested size. */
+
+static size_t pseudofile_buffersize(FAR struct fs_pseudofile_s *pf,
+ size_t size)
+{
+ size_t alloc = 0;
+
+ if (pf->content != NULL)
+ {
+ alloc = fs_heap_malloc_size(pf->content);
+ }
+
+ if (alloc == 0)
+ {
+ alloc = 1;
+ }
+
+ while (alloc < size)
+ {
+ if (alloc > (SIZE_MAX >> 1))
+ {
+ return size;
+ }
+
+ alloc <<= 1;
+ }
+
+ return alloc;
+}
+
static int pseudofile_expand(FAR struct inode *node,
size_t size)
{
FAR struct fs_pseudofile_s *pf = node->i_private;
FAR void *tmp;
+ size_t oldsize = node->i_size;
- if (pf->content && fs_heap_malloc_size(pf->content) >= size)
+ if (pf->content != NULL && fs_heap_malloc_size(pf->content) >= size)
{
+ if (size > oldsize)
+ {
+ memset(pf->content + oldsize, 0, size - oldsize);
+ }
+
node->i_size = size;
return 0;
}
- tmp = fs_heap_realloc(pf->content, 1 << LOG2_CEIL(size));
+ tmp = fs_heap_realloc(pf->content, pseudofile_buffersize(pf, size));
if (tmp == NULL)
{
return -ENOMEM;
}
pf->content = tmp;
+
+ if (size > oldsize)
+ {
+ memset(pf->content + oldsize, 0, size - oldsize);
+ }
+
node->i_size = size;
return 0;
}
@@ -207,6 +249,12 @@ static ssize_t pseudofile_write(FAR struct file *filep,
if (filep->f_oflags & O_APPEND)
{
+ if (buflen > SIZE_MAX - node->i_size)
+ {
+ nxmutex_unlock(&pf->lock);
+ return -EFBIG;
+ }
+
ret = pseudofile_expand(node, node->i_size + buflen);
if (ret < 0)
{
@@ -218,6 +266,12 @@ static ssize_t pseudofile_write(FAR struct file *filep,
}
else
{
+ if (filep->f_pos > SIZE_MAX - buflen)
+ {
+ nxmutex_unlock(&pf->lock);
+ return -EFBIG;
+ }
+
ret = pseudofile_expand(node, filep->f_pos + buflen);
if (ret < 0)
{
@@ -392,6 +446,12 @@ static int pseudofile_truncate(FAR struct file *filep,
off_t length)
return ret;
}
+ if (length < 0)
+ {
+ ret = -EINVAL;
+ goto out;
+ }
+
if (length < node->i_size)
{
FAR void *tmp;
@@ -413,8 +473,6 @@ static int pseudofile_truncate(FAR struct file *filep,
off_t length)
{
goto out;
}
-
- memset(pf->content + node->i_size, 0, length - node->i_size);
}
#ifdef CONFIG_PSEUDOFS_ATTRIBUTES