git: b112232e4fb9 - main - uipc_shm: Copyin userpath for ktrace(2)

From: Jake Freeland <jfree_at_FreeBSD.org>
Date: Wed, 10 Apr 2024 02:21:00 UTC
The branch main has been updated by jfree:

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

commit b112232e4fb931ebafae9d79fbc970e3df020b57
Author:     Jake Freeland <jfree@FreeBSD.org>
AuthorDate: 2024-04-10 02:17:11 +0000
Commit:     Jake Freeland <jfree@FreeBSD.org>
CommitDate: 2024-04-10 02:17:11 +0000

    uipc_shm: Copyin userpath for ktrace(2)
    
    If userpath is not SHM_ANON, then copy it in early so ktrace(2) can
    record it. Without this change, ktrace(2) will attempt to strcpy a
    userspace string and trigger a page fault.
    
    Reported by:    syzbot+490b9c2a89f53b1b9779@syzkaller.appspotmail.com
    Fixes:          0cd9cde767c3
    Approved by:    markj (mentor)
    Reviewed by:    markj
    MFC after:      1 month
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D44702
---
 sys/kern/uipc_shm.c | 44 +++++++++++++++++++++++---------------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 5347378c2b4d..14fe43524935 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -1173,18 +1173,6 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
 	if ((shmflags & SHM_ALLOW_SEALING) != 0)
 		initial_seals &= ~F_SEAL_SEAL;
 
-#ifdef CAPABILITY_MODE
-	/*
-	 * shm_open(2) is only allowed for anonymous objects.
-	 */
-	if (userpath != SHM_ANON) {
-		if (CAP_TRACING(td))
-			ktrcapfail(CAPFAIL_NAMEI, userpath);
-		if (IN_CAPABILITY_MODE(td))
-			return (ECAPMODE);
-	}
-#endif
-
 	AUDIT_ARG_FFLAGS(flags);
 	AUDIT_ARG_MODE(mode);
 
@@ -1209,6 +1197,26 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
 	if ((initial_seals & ~F_SEAL_SEAL) != 0)
 		return (EINVAL);
 
+	if (userpath != SHM_ANON) {
+		error = shm_copyin_path(td, userpath, &path);
+		if (error != 0)
+			return (error);
+
+#ifdef CAPABILITY_MODE
+		/*
+		 * shm_open(2) is only allowed for anonymous objects.
+		 */
+		if (CAP_TRACING(td))
+			ktrcapfail(CAPFAIL_NAMEI, path);
+		if (IN_CAPABILITY_MODE(td)) {
+			free(path, M_SHMFD);
+			return (ECAPMODE);
+		}
+#endif
+
+		AUDIT_ARG_UPATH1_CANON(path);
+	}
+
 	pdp = td->td_proc->p_pd;
 	cmode = (mode & ~pdp->pd_cmask) & ACCESSPERMS;
 
@@ -1220,8 +1228,10 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
 	 * in sys_shm_open() to keep this implementation compliant.
 	 */
 	error = falloc_caps(td, &fp, &fd, flags & O_CLOEXEC, fcaps);
-	if (error)
+	if (error) {
+		free(path, M_SHMFD);
 		return (error);
+	}
 
 	/* A SHM_ANON path pointer creates an anonymous object. */
 	if (userpath == SHM_ANON) {
@@ -1235,14 +1245,6 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
 		shmfd->shm_seals = initial_seals;
 		shmfd->shm_flags = shmflags;
 	} else {
-		error = shm_copyin_path(td, userpath, &path);
-		if (error != 0) {
-			fdclose(td, fp, fd);
-			fdrop(fp, td);
-			return (error);
-		}
-
-		AUDIT_ARG_UPATH1_CANON(path);
 		fnv = fnv_32_str(path, FNV1_32_INIT);
 		sx_xlock(&shm_dict_lock);
 		shmfd = shm_lookup(path, fnv);