git: 1065a7ebdeb8 - stable/14 - posixshm: Fix range locking in shm_write()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 24 Apr 2025 13:21:18 UTC
The branch stable/14 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=1065a7ebdeb8fb16ab6a5112cc4845b66c467eb9
commit 1065a7ebdeb8fb16ab6a5112cc4845b66c467eb9
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-04-06 22:51:53 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-04-24 13:20:52 +0000
posixshm: Fix range locking in shm_write()
There is a somewhat strange case where when writing to a POSIX shm
object, the object is not allowed to grow, and the I/O offset+length
overflows. In that case we simply truncate the I/O to the object size.
Later we write-lock the range [offset, objsize). However, we were not
checking whether offset > objsize, in which case we're writing zero
bytes but locking an invalid range.
Modify the range locking in shm_write() to take this possibility into
account. While here, rename a variable to make its purpose a bit more
clear, and add an assertion against negative offsets (which is supposed
to be enforced by the caller of fo_write for I/O to files that aren't
character devices).
Reported by: syzkaller
Reviewed by: kevans, kib
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D49673
(cherry picked from commit 82d8c609cfb7c6d8a9da8e30efa54240f293359e)
---
sys/kern/uipc_shm.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index e159c802795b..c8d5521c5ab1 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -481,7 +481,10 @@ shm_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
struct shmfd *shmfd;
void *rl_cookie;
int error;
- off_t size;
+ off_t newsize;
+
+ KASSERT((flags & FOF_OFFSET) == 0 || uio->uio_offset >= 0,
+ ("%s: negative offset", __func__));
shmfd = fp->f_data;
#ifdef MAC
@@ -503,21 +506,23 @@ shm_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
return (EFBIG);
}
- size = shmfd->shm_size;
+ newsize = atomic_load_64(&shmfd->shm_size);
} else {
- size = uio->uio_offset + uio->uio_resid;
+ newsize = uio->uio_offset + uio->uio_resid;
}
if ((flags & FOF_OFFSET) == 0)
rl_cookie = shm_rangelock_wlock(shmfd, 0, OFF_MAX);
else
- rl_cookie = shm_rangelock_wlock(shmfd, uio->uio_offset, size);
+ rl_cookie = shm_rangelock_wlock(shmfd, uio->uio_offset,
+ MAX(newsize, uio->uio_offset));
if ((shmfd->shm_seals & F_SEAL_WRITE) != 0) {
error = EPERM;
} else {
error = 0;
if ((shmfd->shm_flags & SHM_GROW_ON_WRITE) != 0 &&
- size > shmfd->shm_size) {
- error = shm_dotruncate_cookie(shmfd, size, rl_cookie);
+ newsize > shmfd->shm_size) {
+ error = shm_dotruncate_cookie(shmfd, newsize,
+ rl_cookie);
}
if (error == 0)
error = uiomove_object(shmfd->shm_object,