untrusted comment: verify with openbsd-78-base.pub RWS3/nvFmk4SWc2HkJR/iuR3biz1GHymiHmqE0rj7B0aj2XUjN+GzSQM5CPO95TCvUIAndThUh6bdMubOJdHf+1+WTjpSZo3rwk= OpenBSD 7.8 errata 041, July 16, 2026: Fix numerous problems in the System V (sem, msg, ipc) system call layers. Apply by doing: signify -Vep /etc/signify/openbsd-78-base.pub -x 041_sysv.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/kern/kern_sysctl.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sysctl.c,v diff -u -p -r1.483 kern_sysctl.c --- sys/kern/kern_sysctl.c 23 Sep 2025 08:00:48 -0000 1.483 +++ sys/kern/kern_sysctl.c 13 Jul 2026 18:31:15 -0000 @@ -2657,6 +2657,24 @@ sysctl_diskinit(int update, struct proc } #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM) +/* + * In-kernel semaphore implementation + */ +struct semid_ds_kern { + struct ipc_perm sem_perm; /* operation permission struct */ + struct sem *sem_base; /* pointer to first semaphore in set */ + unsigned short sem_nsems; /* number of sems in set */ + time_t sem_otime; /* last operation time */ + time_t sem_ctime; /* last change time */ + /* Times measured in secs since */ + /* 00:00:00 GMT, Jan. 1, 1970 */ + struct refcnt sem_refcnt; +}; + +/* rename sema for stable as it is declared as struct semid_ds in sem.h */ +extern struct semid_ds_kern **sema_kern; +#define sema sema_kern + int sysctl_sysvipc(int *name, u_int namelen, void *where, size_t *sizep) { @@ -2746,20 +2764,26 @@ sysctl_sysvipc(int *name, u_int namelen, switch (*name) { #ifdef SYSVSEM case KERN_SYSVIPC_SEM_INFO: - if (sema[i] != NULL) - memcpy(&semsi->semids[i], sema[i], - dssize); - else - memset(&semsi->semids[i], 0, dssize); + if (sema[i] != NULL) { + semsi->semids[i].sem_perm = + sema[i]->sem_perm; + semsi->semids[i].sem_nsems = + sema[i]->sem_nsems; + semsi->semids[i].sem_otime = + sema[i]->sem_otime; + semsi->semids[i].sem_ctime = + sema[i]->sem_ctime; + } break; #endif #ifdef SYSVSHM case KERN_SYSVIPC_SHM_INFO: - if (shmsegs[i] != NULL) - memcpy(&shmsi->shmids[i], shmsegs[i], - dssize); - else - memset(&shmsi->shmids[i], 0, dssize); + if (shmsegs[i] != NULL) { + memcpy(&shmsi->shmids[i], shmsegs[i], + dssize); + shmsi->shmids[i].shm_internal = NULL; + } + break; #endif } Index: sys/kern/sysv_msg.c =================================================================== RCS file: /cvs/src/sys/kern/sysv_msg.c,v diff -u -p -r1.41 sysv_msg.c --- sys/kern/sysv_msg.c 11 Apr 2023 00:45:09 -0000 1.41 +++ sys/kern/sysv_msg.c 13 Jul 2026 18:31:15 -0000 @@ -56,11 +56,22 @@ void msg_free(struct msg *); void msg_enqueue(struct que *, struct msg *, struct proc *); void msg_dequeue(struct que *, struct msg *, struct proc *); struct msg *msg_lookup(struct que *, int); -int msg_copyin(struct msg *, const char *, size_t, struct proc *); -int msg_copyout(struct msg *, char *, size_t *, struct proc *); +int msg_copyin(struct msg *, const char *, size_t); +int msg_copyout(struct msg *, char *, size_t *, int); + +#define MSGQ_RCVWAIT 0x40 +#define MSGQ_RCVWAITING 0x80 struct pool sysvmsgpl; -struct msginfo msginfo; + +struct msginfo msginfo = { + .msgmax = MSGMAX, + .msgmni = MSGMNI, + .msgmnb = MSGMNB, + .msgtql = MSGTQL, + .msgssz = MSGSSZ, + .msgseg = MSGSEG, +}; TAILQ_HEAD(, que) msg_queues; @@ -72,13 +83,6 @@ int maxmsgs; void msginit(void) { - msginfo.msgmax = MSGMAX; - msginfo.msgmni = MSGMNI; - msginfo.msgmnb = MSGMNB; - msginfo.msgtql = MSGTQL; - msginfo.msgssz = MSGSSZ; - msginfo.msgseg = MSGSEG; - pool_init(&sysvmsgpl, sizeof(struct msg), 0, IPL_NONE, PR_WAITOK, "sysvmsgpl", NULL); @@ -280,7 +284,7 @@ sys_msgsnd(struct proc *p, void *v, regi } /* msg_copyin frees msg on error */ - if ((error = msg_copyin(msg, (const char *)SCARG(uap, msgp), msgsz, p))) + if ((error = msg_copyin(msg, (const char *)SCARG(uap, msgp), msgsz))) goto out; msg_enqueue(que, msg, p); @@ -326,27 +330,47 @@ sys_msgrcv(struct proc *p, void *v, regi QREF(que); +again: /* msg_lookup handles matching; sleeping gets handled here */ while ((msg = msg_lookup(que, msgtyp)) == NULL) { if (SCARG(uap, msgflg) & IPC_NOWAIT) { error = ENOMSG; - goto out; + goto rele; } que->que_flags |= MSGQ_READERS; if ((error = tsleep_nsec(que, PZERO|PCATCH, "msgwait", INFSLP))) - goto out; + goto rele; /* make sure the queue still alive */ if (que->que_flags & MSGQ_DYING) { error = EIDRM; - goto out; + goto rele; + } + } + + /* acquired message could be delivering by concurrent thread */ + if (que->que_flags & MSGQ_RCVWAIT) { + que->que_flags |= MSGQ_RCVWAITING; + error = tsleep_nsec(&que->que_flags, PZERO | PCATCH, + "msgrcv", INFSLP); + if (error) + goto rele; + + /* make sure the queue still alive */ + if (que->que_flags & MSGQ_DYING) { + error = EIDRM; + goto rele; } + + goto again; } + que->que_flags |= MSGQ_RCVWAIT; + /* if msg_copyout fails, keep the message around so it isn't lost */ - if ((error = msg_copyout(msg, msgp, &msgsz, p))) + if ((error = msg_copyout(msg, msgp, &msgsz, SCARG(uap, msgflg)))) goto out; msg_dequeue(que, msg, p); @@ -365,6 +389,16 @@ sys_msgrcv(struct proc *p, void *v, regi *retval = msgsz; out: + que->que_flags &= ~MSGQ_RCVWAIT; + + if (que->que_flags & MSGQ_RCVWAITING) { + que->que_flags &= ~MSGQ_RCVWAITING; + if (que->que_flags & MSGQ_DYING) + wakeup(&que->que_flags); + else + wakeup_one(&que->que_flags); + } +rele: QRELE(que); return (error); @@ -565,7 +599,7 @@ msg_dequeue(struct que *que, struct msg */ int -msg_copyin(struct msg *msg, const char *ubuf, size_t len, struct proc *p) +msg_copyin(struct msg *msg, const char *ubuf, size_t len) { struct mbuf **mm, *m; size_t xfer; @@ -574,7 +608,8 @@ msg_copyin(struct msg *msg, const char * if (msg == NULL) panic ("msg NULL"); - if ((error = copyin(ubuf, &msg->msg_type, sizeof(long)))) { + /* msg->msg_type size is not included to `len' */ + if ((error = copyin(ubuf, &msg->msg_type, sizeof(msg->msg_type)))) { msg_free(msg); return (error); } @@ -584,18 +619,18 @@ msg_copyin(struct msg *msg, const char * return (EINVAL); } - ubuf += sizeof(long); + ubuf += sizeof(msg->msg_type); msg->msg_len = 0; mm = &msg->msg_data; while (msg->msg_len < len) { m = m_get(M_WAIT, MT_DATA); - if (len >= MINCLSIZE) { + if ((xfer = len - msg->msg_len) >= MINCLSIZE) { MCLGET(m, M_WAIT); - xfer = min(len, MCLBYTES); + xfer = min(xfer, MCLBYTES); } else { - xfer = min(len, MLEN); + xfer = min(xfer, MLEN); } m->m_len = xfer; msg->msg_len += xfer; @@ -615,10 +650,10 @@ msg_copyin(struct msg *msg, const char * } int -msg_copyout(struct msg *msg, char *ubuf, size_t *len, struct proc *p) +msg_copyout(struct msg *msg, char *ubuf, size_t *len, int msgflg) { struct mbuf *m; - size_t xfer; + size_t total, done, xfer; int error; #ifdef DIAGNOSTIC @@ -626,19 +661,24 @@ msg_copyout(struct msg *msg, char *ubuf, panic("SysV message longer than MSGMAX"); #endif - /* silently truncate messages too large for user buffer */ - xfer = min(*len, msg->msg_len); + if ((total = min(*len, msg->msg_len)) < msg->msg_len) { + if ((msgflg & MSG_NOERROR) == 0) + return (E2BIG); + } - if ((error = copyout(&msg->msg_type, ubuf, sizeof(long)))) + if ((error = copyout(&msg->msg_type, ubuf, sizeof(msg->msg_type)))) return (error); - ubuf += sizeof(long); - *len = xfer; + ubuf += sizeof(msg->msg_type); + *len = total; - for (m = msg->msg_data; m; m = m->m_next) { - if ((error = copyout(mtod(m, void *), ubuf, m->m_len))) + for (done = 0, m = msg->msg_data; m; m = m->m_next) { + if ((xfer = min(m->m_len, total - done)) == 0) + break; + if ((error = copyout(mtod(m, void *), ubuf, xfer))) return (error); - ubuf += m->m_len; + ubuf += xfer; + done += xfer; } return (0); @@ -649,7 +689,7 @@ sysctl_sysvmsg(int *name, u_int namelen, { struct msg_sysctl_info *info; struct que *que; - size_t infolen, infolen0; + size_t infolen; int error; switch (*name) { @@ -666,10 +706,10 @@ sysctl_sysvmsg(int *name, u_int namelen, * message queues; for now, emulate this behavior * until a more thorough fix can be made. */ - infolen0 = sizeof(msginfo) + + infolen = sizeof(msginfo) + msginfo.msgmni * sizeof(struct msqid_ds); if (where == NULL) { - *sizep = infolen0; + *sizep = infolen; return (0); } @@ -682,17 +722,10 @@ sysctl_sysvmsg(int *name, u_int namelen, */ if (*sizep == sizeof(struct msginfo)) return (copyout(&msginfo, where, sizeof(msginfo))); - - info = malloc(infolen0, M_TEMP, M_WAIT|M_ZERO); - - /* if the malloc slept, this may have changed */ - infolen = sizeof(msginfo) + - msginfo.msgmni * sizeof(struct msqid_ds); - - if (*sizep < infolen) { - free(info, M_TEMP, infolen0); + if (*sizep < infolen) return (ENOMEM); - } + + info = malloc(infolen, M_TEMP, M_WAIT|M_ZERO); memcpy(&info->msginfo, &msginfo, sizeof(struct msginfo)); @@ -707,7 +740,7 @@ sysctl_sysvmsg(int *name, u_int namelen, error = copyout(info, where, infolen); - free(info, M_TEMP, infolen0); + free(info, M_TEMP, infolen); return (error); Index: sys/kern/sysv_sem.c =================================================================== RCS file: /cvs/src/sys/kern/sysv_sem.c,v diff -u -p -r1.65 sysv_sem.c --- sys/kern/sysv_sem.c 1 Aug 2025 08:40:25 -0000 1.65 +++ sys/kern/sysv_sem.c 13 Jul 2026 18:31:15 -0000 @@ -47,11 +47,29 @@ #define SEMOP_MAX (MALLOC_MAX / sizeof(struct sembuf)) +/* + * In-kernel semaphore implementation + */ +struct semid_ds_kern { + struct ipc_perm sem_perm; /* operation permission struct */ + struct sem *sem_base; /* pointer to first semaphore in set */ + unsigned short sem_nsems; /* number of sems in set */ + time_t sem_otime; /* last operation time */ + time_t sem_ctime; /* last change time */ + /* Times measured in secs since */ + /* 00:00:00 GMT, Jan. 1, 1970 */ + struct refcnt sem_refcnt; +}; + +/* rename sema for stable as it is declared as struct semid_ds in sem.h */ +extern struct semid_ds_kern **sema_kern; +#define sema sema_kern + int semtot = 0; int semutot = 0; -struct semid_ds **sema; /* semaphore id list */ +struct semid_ds_kern **sema; /* semaphore id list */ SLIST_HEAD(, sem_undo) semu_list; /* list of undo structures */ -struct pool sema_pool; /* pool for struct semid_ds */ +struct pool sema_pool; /* pool for struct semid_ds_kern */ struct pool semu_pool; /* pool for struct sem_undo (SEMUSZ) */ unsigned short *semseqs; /* array of sem sequence numbers */ @@ -63,16 +81,33 @@ void seminit(void) { - pool_init(&sema_pool, sizeof(struct semid_ds), 0, 0, PR_WAITOK, + pool_init(&sema_pool, sizeof(struct semid_ds_kern), 0, 0, PR_WAITOK, "semapl", NULL); pool_init(&semu_pool, SEMUSZ, 0, 0, PR_WAITOK, "semupl", NULL); - sema = mallocarray(seminfo.semmni, sizeof(struct semid_ds *), + sema = mallocarray(seminfo.semmni, sizeof(struct semid_ds_kern *), M_SEM, M_WAITOK|M_ZERO); semseqs = mallocarray(seminfo.semmni, sizeof(unsigned short), M_SEM, M_WAITOK|M_ZERO); SLIST_INIT(&semu_list); } +static inline void +sem_ref(struct semid_ds_kern *semaptr) +{ + refcnt_take(&semaptr->sem_refcnt); +} + +void +sem_rele(struct semid_ds_kern *semaptr) +{ + if (refcnt_rele(&semaptr->sem_refcnt)) { + semtot -= semaptr->sem_nsems; + free(semaptr->sem_base, M_SEM, + semaptr->sem_nsems * sizeof(struct sem)); + pool_put(&sema_pool, semaptr); + } +} + /* * Allocate a new sem_undo structure for a process * (returns ptr to structure or NULL if no more room) @@ -237,7 +272,7 @@ sys___semctl(struct proc *p, void *v, re int cmd = SCARG(uap, cmd); union semun arg, *uarg = SCARG(uap, arg); struct semid_ds sbuf; - struct semid_ds *semaptr; + struct semid_ds_kern *semaptr; unsigned short *semval = NULL, nsems; int i, ix, error; @@ -271,11 +306,8 @@ again: return (error); semaptr->sem_perm.cuid = cred->cr_uid; semaptr->sem_perm.uid = cred->cr_uid; - semtot -= semaptr->sem_nsems; - free(semaptr->sem_base, M_SEM, - semaptr->sem_nsems * sizeof(struct sem)); - pool_put(&sema_pool, semaptr); sema[ix] = NULL; + sem_rele(semaptr); semundo_clear(ix, -1); wakeup(&sema[ix]); break; @@ -293,9 +325,14 @@ again: case IPC_STAT: if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) return (error); - memcpy(&sbuf, semaptr, sizeof sbuf); - sbuf.sem_base = NULL; - error = copyout(&sbuf, arg.buf, sizeof(struct semid_ds)); + + memset(&sbuf, 0, sizeof(sbuf)); + sbuf.sem_perm = semaptr->sem_perm; + sbuf.sem_nsems = semaptr->sem_nsems; + sbuf.sem_otime = semaptr->sem_otime; + sbuf.sem_ctime = semaptr->sem_ctime; + + error = copyout(&sbuf, arg.buf, sizeof(sbuf)); break; case GETNCNT: @@ -324,16 +361,19 @@ again: case GETALL: nsems = semaptr->sem_nsems; + + sem_ref(semaptr); semval = mallocarray(nsems, sizeof(arg.array[0]), M_TEMP, M_WAITOK); - if (semaptr != sema[ix] || - semaptr->sem_perm.seq != IPCID_TO_SEQ(semid) || - semaptr->sem_nsems != nsems) { + sem_rele(semaptr); + + if (semaptr != sema[ix]) { free(semval, M_TEMP, nsems * sizeof(arg.array[0])); goto again; } if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) goto error; + for (i = 0; i < nsems; i++) semval[i] = semaptr->sem_base[i].semval; for (i = 0; i < nsems; i++) { @@ -366,21 +406,26 @@ again: case SETALL: nsems = semaptr->sem_nsems; + + sem_ref(semaptr); semval = mallocarray(nsems, sizeof(arg.array[0]), M_TEMP, M_WAITOK); for (i = 0; i < nsems; i++) { error = copyin(&arg.array[i], &semval[i], sizeof(arg.array[0])); if (error != 0) - goto error; + break; if (semval[i] > seminfo.semvmx) { error = ERANGE; - goto error; + break; } } - if (semaptr != sema[ix] || - semaptr->sem_perm.seq != IPCID_TO_SEQ(semid) || - semaptr->sem_nsems != nsems) { + sem_rele(semaptr); + + if (error) + goto error; + + if (semaptr != sema[ix]) { free(semval, M_TEMP, nsems * sizeof(arg.array[0])); goto again; } @@ -414,7 +459,7 @@ sys_semget(struct proc *p, void *v, regi int key = SCARG(uap, key); int nsems = SCARG(uap, nsems); int semflg = SCARG(uap, semflg); - struct semid_ds *semaptr, *semaptr_new = NULL; + struct semid_ds_kern *semaptr, *semaptr_new = NULL; struct ucred *cred = p->p_ucred; DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); @@ -484,6 +529,7 @@ sys_semget(struct proc *p, void *v, regi goto error; } DPRINTF(("semid %d is available\n", semid)); + refcnt_init(&semaptr_new->sem_refcnt); semaptr_new->sem_perm.key = key; semaptr_new->sem_perm.cuid = cred->cr_uid; semaptr_new->sem_perm.uid = cred->cr_uid; @@ -525,8 +571,8 @@ sys_semop(struct proc *p, void *v, regis struct sembuf sopbuf[NSOPS]; int semid = SCARG(uap, semid); size_t nsops = SCARG(uap, nsops); - struct sembuf *sops; - struct semid_ds *semaptr; + struct sembuf *sops = NULL; + struct semid_ds_kern *semaptr; struct sembuf *sopptr = NULL; struct sem *semptr = NULL; struct sem_undo *suptr = NULL; @@ -537,38 +583,52 @@ sys_semop(struct proc *p, void *v, regis DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops), (u_long)nsops)); + if (nsops == 0) + goto skipcopy; + + if (nsops > (size_t)seminfo.semopm) { + DPRINTF(("too many sops (max=%d, nsops=%lu)\n", + seminfo.semopm, (u_long)nsops)); + return (E2BIG); + } + + if (nsops <= NSOPS) + sops = sopbuf; + else { + sops = mallocarray(nsops, sizeof(struct sembuf), + M_SEM, M_WAITOK); + } + + error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf)); + if (error != 0) { + DPRINTF(("error = %d from copyin(%p, %p, %zu)\n", error, + SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf))); + goto done2; + } + +skipcopy: semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ - if (semid < 0 || semid >= seminfo.semmni) - return (EINVAL); + if (semid < 0 || semid >= seminfo.semmni) { + error = EINVAL; + goto done2; + } if ((semaptr = sema[semid]) == NULL || - semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) - return (EINVAL); + semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) { + error = EINVAL; + goto done2; + } if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { DPRINTF(("error = %d from ipaccess\n", error)); - return (error); + goto done2; } if (nsops == 0) { + /* `sops' has not been allocated, no need to release */ *retval = 0; return (0); - } else if (nsops > (size_t)seminfo.semopm) { - DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm, - (u_long)nsops)); - return (E2BIG); - } - - if (nsops <= NSOPS) - sops = sopbuf; - else - sops = mallocarray(nsops, sizeof(struct sembuf), M_SEM, M_WAITOK); - error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf)); - if (error != 0) { - DPRINTF(("error = %d from copyin(%p, %p, %zu)\n", error, - SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf))); - goto done2; } /* @@ -663,22 +723,28 @@ sys_semop(struct proc *p, void *v, regis else semptr->semncnt++; + sem_ref(semaptr); + DPRINTF(("semop: good night!\n")); error = tsleep_nsec(&sema[semid], PLOCK | PCATCH, "semwait", INFSLP); DPRINTF(("semop: good morning (error=%d)!\n", error)); - suptr = NULL; /* sem_undo may have been reallocated */ + sem_rele(semaptr); /* - * Make sure that the semaphore still exists + * Make sure that the semaphore still exists. Even if + * `semaptr' was released, it's address was not used to + * alloc the new one. The semaphore is alive if address + * was not changed. */ - if (sema[semid] == NULL || - semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) { + if (semaptr != sema[semid]) { error = EIDRM; goto done2; } + suptr = NULL; /* sem_undo may have been reallocated */ + /* * The semaphore is still alive. Readjust the count of * waiting processes. @@ -819,7 +885,7 @@ semexit(struct process *pr) int semid = suptr->un_ent[ix].un_id; int semnum = suptr->un_ent[ix].un_num; int adjval = suptr->un_ent[ix].un_adjval; - struct semid_ds *semaptr; + struct semid_ds_kern *semaptr; if ((semaptr = sema[semid]) == NULL) panic("semexit - semid not allocated"); @@ -856,17 +922,17 @@ semexit(struct process *pr) void sema_reallocate(int val) { - struct semid_ds **sema_new; + struct semid_ds_kern **sema_new; unsigned short *newseqs; - sema_new = mallocarray(val, sizeof(struct semid_ds *), + sema_new = mallocarray(val, sizeof(struct semid_ds_kern *), M_SEM, M_WAITOK|M_ZERO); memcpy(sema_new, sema, - seminfo.semmni * sizeof(struct semid_ds *)); + seminfo.semmni * sizeof(struct semid_ds_kern *)); newseqs = mallocarray(val, sizeof(unsigned short), M_SEM, M_WAITOK|M_ZERO); memcpy(newseqs, semseqs, seminfo.semmni * sizeof(unsigned short)); - free(sema, M_SEM, seminfo.semmni * sizeof(struct semid_ds *)); + free(sema, M_SEM, seminfo.semmni * sizeof(struct semid_ds_kern *)); free(semseqs, M_SEM, seminfo.semmni * sizeof(unsigned short)); sema = sema_new; semseqs = newseqs; Index: sys/kern/sysv_shm.c =================================================================== RCS file: /cvs/src/sys/kern/sysv_shm.c,v diff -u -p -r1.81 sysv_shm.c --- sys/kern/sysv_shm.c 5 Nov 2024 15:34:30 -0000 1.81 +++ sys/kern/sysv_shm.c 13 Jul 2026 18:31:15 -0000 @@ -86,6 +86,10 @@ struct shmid_ds *shm_find_segment_by_shm * per proc 'struct shmmap_head' with an array of 'struct shmmap_state' */ +/* Limit to prevent chunk size overflow in sys_shmat() */ +#define SHMSEG_MAX \ + ((0xffffffff - sizeof(int)) / sizeof(struct shmmap_state) / 8) + #define SHMSEG_REMOVED 0x0200 /* can't overlap ACCESSPERMS */ int shm_last_free, shm_nused, shm_committed; @@ -224,17 +228,30 @@ sys_shmat(struct proc *p, void *v, regis shmmap_h = (struct shmmap_head *)p->p_vmspace->vm_shm; if (shmmap_h == NULL) { + struct shmmap_head *shmmap_h_probe; + int shmseg_local = atomic_load_int(&shminfo.shmseg); + size = sizeof(int) + - shminfo.shmseg * sizeof(struct shmmap_state); + shmseg_local * sizeof(struct shmmap_state); shmmap_h = malloc(size, M_SHM, M_WAITOK | M_CANFAIL); if (shmmap_h == NULL) return (ENOMEM); - shmmap_h->shmseg = shminfo.shmseg; + + shmmap_h_probe = + (struct shmmap_head *)READ_ONCE(p->p_vmspace->vm_shm); + if (shmmap_h_probe != NULL) { + free(shmmap_h, M_SHM, size); + shmmap_h = shmmap_h_probe; + goto allocated; + } + + shmmap_h->shmseg = shmseg_local; for (i = 0, shmmap_s = shmmap_h->state; i < shmmap_h->shmseg; i++, shmmap_s++) shmmap_s->shmid = -1; p->p_vmspace->vm_shm = (caddr_t)shmmap_h; } +allocated: shmseg = shm_find_segment_by_shmid(SCARG(uap, shmid)); if (shmseg == NULL) return (EINVAL); @@ -414,10 +431,10 @@ shmget_allocate_segment(struct proc *p, * the key we want in the meantime. Yes, this is ugly. */ key = SCARG(uap, key); - shmseg = pool_get(&shm_pool, key == IPC_PRIVATE ? PR_WAITOK : - PR_NOWAIT); + shmseg = pool_get(&shm_pool, + (key == IPC_PRIVATE ? PR_WAITOK : PR_NOWAIT) | PR_ZERO); if (shmseg == NULL) { - shmseg = pool_get(&shm_pool, PR_WAITOK); + shmseg = pool_get(&shm_pool, PR_WAITOK | PR_ZERO); if (shm_find_segment_by_key(key) != -1) { pool_put(&shm_pool, shmseg); shm_nused--; @@ -609,7 +626,7 @@ sysctl_sysvshm(int *name, u_int namelen, return (0); case KERN_SHMINFO_SHMSEG: return (sysctl_int_bounded(oldp, oldlenp, newp, newlen, - &shminfo.shmseg, 1, INT_MAX)); + &shminfo.shmseg, 1, SHMSEG_MAX)); case KERN_SHMINFO_SHMALL: /* can't decrease shmall */ return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,