[PATCH 1/2] fs: fix llseek() result for files with unsigned offsets
From: Stian Halseth
Date: Thu Sep 17 2026 - 11:31:08 EST
sys_llseek() treats a negative result from vfs_llseek() as an error and
returns it truncated to int instead of storing it in *result. For a
file with FOP_UNSIGNED_OFFSET a valid offset can have the top bit set,
so the seek succeeds but userspace gets a bogus return value and an
untouched result buffer. ksys_lseek() has no such check and returns
the offset as is.
Store the offset when the file has unsigned offsets too, still treating
a value in the errno range as an error so a real failure from
->llseek() is reported.
On sparc64, where userspace is mapped above 2^63 and glibc's lseek()
uses _llseek, this makes lseek() on /proc/PID/mem return the offset it
seeked to instead of its low 32 bits.
Signed-off-by: Stian Halseth <stian@xxxxxx>
---
fs/read_write.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/read_write.c b/fs/read_write.c
index e8c14e2..36f3d8e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -441,7 +441,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
whence);
retval = (int)offset;
- if (offset >= 0) {
+ if (offset >= 0 || (unsigned_offsets(fd_file(f)) && offset < -MAX_ERRNO)) {
retval = -EFAULT;
if (!copy_to_user(result, &offset, sizeof(offset)))
retval = 0;
--
2.43.0