[PATCH 1/2] fs: statmount: don't copy strings past the caller's buffer
From: fujo
Date: Wed Oct 21 2026 - 13:54:23 EST
statmount(2) collects all strings in a kernel buffer and copies them to
the user buffer after struct statmount. copy_statmount_to_user() copies
seq->count bytes at buf + sizeof(struct statmount), but only
statmount_string() checks whether they fit: it returns early when the
producer emitted nothing, before the size check.
If no producer emits anything -- for example STATMOUNT_MNT_UIDMAP on a
mount that is not idmapped -- the reserved empty string is the only
thing left in seq->buf. statmount(2) then copies that single NUL at
offset 512 even when the caller passed a smaller bufsize, and returns
success with size = 101 for bufsize = 100. The write is beyond the
buffer the caller declared; if the following page is unmapped the
syscall fails with EFAULT instead. The same request with a producer
that does emit data correctly returns EOVERFLOW.
Validate that the string area fits into s->bufsize before copying it
and return EOVERFLOW otherwise.
Reported-by: shaos <shawnq1@xxxxxxx>
Link: https://lore.kernel.org/all/20261020110747.959829-1-shawnq1@xxxxxxx/
Signed-off-by: fujo <hooyan2024@xxxxxxxxx>
---
fs/namespace.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index c30f06374..c8aceeff6 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -5831,8 +5831,18 @@ static int copy_statmount_to_user(struct kstatmount *s)
char __user *str = ((char __user *)s->buf) + sizeof(*sm);
size_t copysize = min_t(size_t, s->bufsize, sizeof(*sm));
- if (seq->count && copy_to_user(str, seq->buf, seq->count))
- return -EFAULT;
+ if (seq->count) {
+ /*
+ * The string area starts after the struct and must fit into the
+ * caller-provided buffer. A request that emitted no strings
+ * still leaves the reserved empty string in seq->buf.
+ */
+ if (s->bufsize < sizeof(*sm) ||
+ seq->count > s->bufsize - sizeof(*sm))
+ return -EOVERFLOW;
+ if (copy_to_user(str, seq->buf, seq->count))
+ return -EFAULT;
+ }
/* Return the number of bytes copied to the buffer */
sm->size = copysize + seq->count;
--
2.53.0