The branch main has been updated by kevans:

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

commit 6b49d119489944abbef87b5892c21f65e7a7055e
Author:     Kyle Evans <kev...@freebsd.org>
AuthorDate: 2025-07-14 23:28:35 +0000
Commit:     Kyle Evans <kev...@freebsd.org>
CommitDate: 2025-07-26 21:31:40 +0000

    kern: allow kern_shm_open2 of an anonymous preconstructed shmfd
    
    The motivation here is for future changes to the coredump code to be
    able to build up a coredump into a shmfd instead of a vnode, which then
    gets tapped out to userland via a character device.  This also opens up
    the possibility that it's useful for the kernel to be able to construct
    a shmfd and pass it out to a process that shouldn't need to write to it.
    
    Reviewed by:    emaste, kib, markj
    Differential Revision:  https://reviews.freebsd.org/D51336
---
 sys/compat/linux/linux_file.c |  2 +-
 sys/kern/uipc_shm.c           | 50 +++++++++++++++++++++++++++++--------------
 sys/sys/syscallsubr.h         |  3 ++-
 3 files changed, 37 insertions(+), 18 deletions(-)

diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 86834a7ecea8..a4be5313aa96 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -1792,7 +1792,7 @@ linux_memfd_create(struct thread *td, struct 
linux_memfd_create_args *args)
        if ((flags & MFD_ALLOW_SEALING) != 0)
                shmflags |= SHM_ALLOW_SEALING;
        return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL,
-           memfd_name));
+           memfd_name, NULL));
 }
 
 int
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 6f83b875a6b6..85fe48ddd466 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -1134,10 +1134,10 @@ shm_doremove(struct shm_mapping *map)
 
 int
 kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
-    int shmflags, struct filecaps *fcaps, const char *name __unused)
+    int shmflags, struct filecaps *fcaps, const char *name __unused,
+    struct shmfd *shmfd)
 {
        struct pwddesc *pdp;
-       struct shmfd *shmfd;
        struct file *fp;
        char *path;
        void *rl_cookie;
@@ -1214,23 +1214,41 @@ kern_shm_open2(struct thread *td, const char *userpath, 
int flags, mode_t mode,
        if (error != 0)
                goto outnofp;
 
-       /* A SHM_ANON path pointer creates an anonymous object. */
+       /*
+        * A SHM_ANON path pointer creates an anonymous object.  We allow other
+        * parts of the kernel to pre-populate a shmfd and then materialize an
+        * fd for it here as a means to pass data back up to userland.  This
+        * doesn't really make sense for named shm objects, but it makes plenty
+        * of sense for anonymous objects.
+        */
        if (userpath == SHM_ANON) {
-               /* A read-only anonymous object is pointless. */
-               if ((flags & O_ACCMODE) == O_RDONLY) {
-                       error = EINVAL;
-                       goto out;
-               }
-               shmfd = shm_alloc(td->td_ucred, cmode, largepage);
-               if (shmfd == NULL) {
-                       error = ENOMEM;
-                       goto out;
+               if (shmfd != NULL) {
+                       shm_hold(shmfd);
+               } else {
+                       /*
+                        * A read-only anonymous object is pointless, unless it
+                        * was pre-populated by the kernel with the expectation
+                        * that a shmfd would later be created for userland to
+                        * access it through.
+                        */
+                       if ((flags & O_ACCMODE) == O_RDONLY) {
+                               error = EINVAL;
+                               goto out;
+                       }
+                       shmfd = shm_alloc(td->td_ucred, cmode, largepage);
+                       if (shmfd == NULL) {
+                               error = ENOMEM;
+                               goto out;
+                       }
+
+                       shmfd->shm_seals = initial_seals;
+                       shmfd->shm_flags = shmflags;
                }
-               shmfd->shm_seals = initial_seals;
-               shmfd->shm_flags = shmflags;
        } else {
                fnv = fnv_32_str(path, FNV1_32_INIT);
                sx_xlock(&shm_dict_lock);
+
+               MPASS(shmfd == NULL);
                shmfd = shm_lookup(path, fnv);
                if (shmfd == NULL) {
                        /* Object does not yet exist, create it if requested. */
@@ -2173,7 +2191,7 @@ kern_shm_open(struct thread *td, const char *path, int 
flags, mode_t mode,
     struct filecaps *caps)
 {
 
-       return (kern_shm_open2(td, path, flags, mode, 0, caps, NULL));
+       return (kern_shm_open2(td, path, flags, mode, 0, caps, NULL, NULL));
 }
 
 /*
@@ -2191,7 +2209,7 @@ sys_shm_open2(struct thread *td, struct shm_open2_args 
*uap)
 {
 
        return (kern_shm_open2(td, uap->path, uap->flags, uap->mode,
-           uap->shmflags, NULL, uap->name));
+           uap->shmflags, NULL, uap->name, NULL));
 }
 
 int
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index fd183ffbc7a4..8237165b84ce 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -60,6 +60,7 @@ struct rusage;
 struct sched_param;
 struct sembuf;
 union semun;
+struct shmfd;
 struct sockaddr;
 struct spacectl_range;
 struct stat;
@@ -337,7 +338,7 @@ int kern_shm_open(struct thread *td, const char *userpath, 
int flags,
            mode_t mode, struct filecaps *fcaps);
 int    kern_shm_open2(struct thread *td, const char *path, int flags,
            mode_t mode, int shmflags, struct filecaps *fcaps,
-           const char *name);
+           const char *name, struct shmfd *shmfd);
 int    kern_shmat(struct thread *td, int shmid, const void *shmaddr,
            int shmflg);
 int    kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,

Reply via email to