This is an automated email from the ASF dual-hosted git repository.
casaroli 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 7e5e08c1b74 fs/tmpfs: zero-fill the hole created by a seek-past-EOF
write.
7e5e08c1b74 is described below
commit 7e5e08c1b745c26cf1b26f56b1ccfe58403ef2cc
Author: Junbo Zheng <[email protected]>
AuthorDate: Mon Oct 26 21:26:38 2026 +0800
fs/tmpfs: zero-fill the hole created by a seek-past-EOF write.
A write that starts past EOF grows the file storage with realloc(),
which leaves the gap below the write offset filled with stale heap
contents instead of zeros, so a reader of the file can observe
kernel heap residue. tmpfs_truncate() already zeroes the region it
grows; make the write path do the same for the gap.
Testing:
Built and ran sim:nsh with tmpfs enabled:
cmake -B build -DBOARD_CONFIG=sim:nsh
(set CONFIG_FS_TMPFS=y and its guard/blocksize sub-options in
build/.config)
cmake --build build -j
printf 'hello\npoweroff\n' | ./build/nuttx
Test vehicle (applied to apps/examples/hello/hello_main.c):
--- a/apps/examples/hello/hello_main.c
+++ b/apps/examples/hello/hello_main.c
@@ -23,7 +23,11 @@
****************************************************************************/
#include <nuttx/config.h>
+
+#include <fcntl.h>
#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
/****************************************************************************
* Public Functions
@@ -35,6 +39,32 @@
int main(int argc, FAR char *argv[])
{
- printf("Hello, World!!\n");
+ unsigned char buf[256];
+ ssize_t n;
+ int fd;
+ int dirty;
+ int i;
+
+ fd = open("/tmp/f1", O_CREAT | O_WRONLY | O_TRUNC, 0644);
+ lseek(fd, 100, SEEK_SET);
+ write(fd, "X", 1);
+ close(fd);
+
+ fd = open("/tmp/f1", O_RDONLY);
+ memset(buf, 0, sizeof(buf));
+ n = read(fd, buf, sizeof(buf));
+ close(fd);
+
+ dirty = 0;
+ for (i = 0; i < 100; i++)
+ {
+ if (buf[i] != 0)
+ {
+ dirty++;
+ }
+ }
+
+ printf("sparse write: size=%zd dirty-gap-bytes=%d (expect 0)\n",
+ n, dirty);
return 0;
}
Observed before the fix (stale heap bytes leak into the file; the
exact count varies with heap state, 10-12 across runs):
sparse write: size=101 dirty-gap-bytes=12
and after the fix (deterministic, the gap is zeroed):
sparse write: size=101 dirty-gap-bytes=0
Signed-off-by: Junbo Zheng <[email protected]>
---
fs/tmpfs/fs_tmpfs.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/tmpfs/fs_tmpfs.c b/fs/tmpfs/fs_tmpfs.c
index 51173964ed7..e9fcbcdad50 100644
--- a/fs/tmpfs/fs_tmpfs.c
+++ b/fs/tmpfs/fs_tmpfs.c
@@ -1942,11 +1942,22 @@ static ssize_t tmpfs_write(FAR struct file *filep, FAR
const char *buffer,
{
/* Reallocate the file to handle the write past the end of the file. */
+ size_t oldsize = tfo->tfo_size;
+
ret = tmpfs_realloc_file(tfo, (size_t)endpos);
if (ret < 0)
{
goto errout_with_lock;
}
+
+ /* A seek past EOF followed by a write leaves a hole that must read
+ * back as zeros; realloc() leaves the gap unzeroed.
+ */
+
+ if (startpos > oldsize)
+ {
+ memset(&tfo->tfo_data[oldsize], 0, startpos - oldsize);
+ }
}
/* Copy data from the memory object to the user buffer */