git: d6e382c17691 - releng/14.3 - posixshm: Disallow truncation of largepage objects

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 30 Jun 2026 17:20:36 UTC
The branch releng/14.3 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=d6e382c17691eee21f7b4907ffd41d622af4200b

commit d6e382c17691eee21f7b4907ffd41d622af4200b
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-06-23 22:47:02 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-06-30 02:32:01 +0000

    posixshm: Disallow truncation of largepage objects
    
    We correctly handled ftruncate(), but not open(O_TRUNC).
    
    Add a regression test.
    
    Approved by:    so
    Security:       FreeBSD-SA-26:44.posixshm
    Security:       CVE-2026-49428
    Reported by:    Chris Jarrett-Davies <chrisjd@openai.com>
    Reviewed by:    kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57831
---
 sys/kern/uipc_shm.c                |  8 +++-----
 tests/sys/posixshm/posixshm_test.c | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 5849569f2dfc..b3dd7a91d473 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -824,7 +824,7 @@ shm_dotruncate_largepage(struct shmfd *shmfd, off_t length, void *rl_cookie)
 	vm_pindex_t oldobjsz __unused;
 	int aflags, error, i, psind, try;
 
-	KASSERT(length >= 0, ("shm_dotruncate: length < 0"));
+	KASSERT(length >= 0, ("shm_dotruncate_largepage: length < 0"));
 	object = shmfd->shm_object;
 	VM_OBJECT_ASSERT_WLOCKED(object);
 	rangelock_cookie_assert(rl_cookie, RA_WLOCKED);
@@ -1344,15 +1344,13 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
 			if (error == 0 &&
 			    (flags & (O_ACCMODE | O_TRUNC)) ==
 			    (O_RDWR | O_TRUNC)) {
-				VM_OBJECT_WLOCK(shmfd->shm_object);
 #ifdef MAC
 				error = mac_posixshm_check_truncate(
-					td->td_ucred, fp->f_cred, shmfd);
+				    td->td_ucred, fp->f_cred, shmfd);
 				if (error == 0)
 #endif
-					error = shm_dotruncate_locked(shmfd, 0,
+					error = shm_dotruncate_cookie(shmfd, 0,
 					    rl_cookie);
-				VM_OBJECT_WUNLOCK(shmfd->shm_object);
 			}
 			if (error == 0) {
 				/*
diff --git a/tests/sys/posixshm/posixshm_test.c b/tests/sys/posixshm/posixshm_test.c
index dfcb5a72fefb..c792a85de9e3 100644
--- a/tests/sys/posixshm/posixshm_test.c
+++ b/tests/sys/posixshm/posixshm_test.c
@@ -2151,6 +2151,43 @@ ATF_TC_BODY(largepage_reopen, tc)
 	    "close failed; errno=%d", errno);
 }
 
+ATF_TC_WITHOUT_HEAD(largepage_truncate);
+ATF_TC_BODY(largepage_truncate, tc)
+{
+	size_t ps[MAXPAGESIZES];
+	int fd, psind;
+
+	(void)pagesizes(ps);
+	psind = 1;
+
+	gen_test_path();
+	fd = shm_create_largepage(test_path, O_CREAT | O_RDWR, psind,
+	    SHM_LARGEPAGE_ALLOC_DEFAULT, 0600);
+	if (fd < 0 && errno == ENOTTY)
+		atf_tc_skip("no large page support");
+	ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; error=%d", errno);
+
+	ATF_REQUIRE_MSG(ftruncate(fd, ps[psind]) == 0,
+	    "ftruncate failed; error=%d", errno);
+
+	ATF_REQUIRE_MSG(close(fd) == 0, "close failed; error=%d", errno);
+
+	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0);
+	ATF_REQUIRE_MSG(fd == -1, "shm_open(O_TRUNC) should have failed");
+	ATF_REQUIRE_ERRNO(ENOTSUP, fd == -1);
+
+	fd = shm_open(test_path, O_RDWR, 0);
+	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; error=%d", errno);
+
+	ATF_REQUIRE_MSG(ftruncate(fd, ps[psind]) == 0,
+	    "ftruncate to same size failed; error=%d", errno);
+
+	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
+	    "shm_unlink failed; errno=%d", errno);
+	ATF_REQUIRE_MSG(close(fd) == 0,
+	    "close failed; errno=%d", errno);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 	ATF_TP_ADD_TC(tp, remap_object);
@@ -2202,6 +2239,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, largepage_pkru);
 #endif
 	ATF_TP_ADD_TC(tp, largepage_reopen);
+	ATF_TP_ADD_TC(tp, largepage_truncate);
 
 	return (atf_no_error());
 }