[PATCH 1/2] fs: __read: fix EOF count clamping for negative file sizes

Stefan Kerkmann s.kerkmann at pengutronix.de
Thu Sep 3 09:29:13 PDT 2026


__read() clamps count to the bytes remaining until EOF, but compared
the signed 64-bit f->f_pos/f->f_size (loff_t) against count (size_t),
which is 32-bit on 32-bit arches and 64-bit on 64-bit arches.

This made the comparison type targent dependent, breaking it for
negative file sizes except for the FILE_SIZE_STREAM sentinel.

- On 32-bit arches count is converted to the signed 64-bit type of
  f->f_pos, so for e.g. f->f_size = -512 the comparison f->f_pos + count
  > f->f_size evaluated true. The clamp then assigned the negative
  difference of f->f_size - f->f_pos to the unsigned count, wrapping it
  to a value near 2^32 and turning a small read into a huge out of
  bounds read request.

- On 64-bit arches size_t cannot be represented by signed 64-bit, so the
  arithmetic C conversions turned the whole comparison unsigned:
  f->f_size = -512 was reinterpreted as a value near 2^64, the
  comparison stayed false and the clamp never ran, leaving count
  unclamped and the bogus size undetected.

__read() now rejects negative file sizes (except for the
FILE_SIZE_STREAM sentinel) with -EINVAL. Reads at or past the end of the
file (reachable via pread() with an offset beyond EOF) now return 0.
Remaining reads are clamped to the bytes left until EOF.

Signed-off-by: Stefan Kerkmann <s.kerkmann at pengutronix.de>
---
 fs/fs.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index dc6c30802d..a8f2b78294 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -427,8 +427,16 @@ static ssize_t __read(struct file *f, void *buf, size_t count)
 	if (fsdrv != ramfs_driver)
 		assert_command_context();
 
-	if (f->f_size != FILE_SIZE_STREAM && f->f_pos + count > f->f_size)
-		count = f->f_size - f->f_pos;
+	if (f->f_size != FILE_SIZE_STREAM) {
+		if (f->f_size < 0) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (f->f_pos > f->f_size)
+			count = 0;
+		else
+			count = min_t(u64, (u64)f->f_size - (u64)f->f_pos, count);
+	}
 
 	if (!count)
 		return 0;

-- 
2.47.3




More information about the barebox mailing list