12729Sdfr/*	$NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $	*/
2139804Simp/*-
32729Sdfr * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
42729Sdfr *
52729Sdfr * Redistribution and use in source and binary forms, with or without
62729Sdfr * modification, are permitted provided that the following conditions
72729Sdfr * are met:
82729Sdfr * 1. Redistributions of source code must retain the above copyright
92729Sdfr *    notice, this list of conditions and the following disclaimer.
102729Sdfr * 2. Redistributions in binary form must reproduce the above copyright
112729Sdfr *    notice, this list of conditions and the following disclaimer in the
122729Sdfr *    documentation and/or other materials provided with the distribution.
132729Sdfr * 3. All advertising materials mentioning features or use of this software
142729Sdfr *    must display the following acknowledgement:
152729Sdfr *	This product includes software developed by Adam Glass and Charles
162729Sdfr *	Hannum.
172729Sdfr * 4. The names of the authors may not be used to endorse or promote products
182729Sdfr *    derived from this software without specific prior written permission.
192729Sdfr *
202729Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
212729Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
222729Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
232729Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
242729Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
252729Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
262729Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
272729Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
282729Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
292729Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
302729Sdfr */
31140617Srwatson/*-
32140617Srwatson * Copyright (c) 2003-2005 McAfee, Inc.
33140617Srwatson * All rights reserved.
34140617Srwatson *
35140617Srwatson * This software was developed for the FreeBSD Project in part by McAfee
36140617Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
37140617Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
38140617Srwatson * program.
39140617Srwatson *
40140617Srwatson * Redistribution and use in source and binary forms, with or without
41140617Srwatson * modification, are permitted provided that the following conditions
42140617Srwatson * are met:
43140617Srwatson * 1. Redistributions of source code must retain the above copyright
44140617Srwatson *    notice, this list of conditions and the following disclaimer.
45140617Srwatson * 2. Redistributions in binary form must reproduce the above copyright
46140617Srwatson *    notice, this list of conditions and the following disclaimer in the
47140617Srwatson *    documentation and/or other materials provided with the distribution.
48140617Srwatson *
49140617Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50140617Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51140617Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52140617Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53140617Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54140617Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55140617Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56140617Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57140617Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58140617Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59140617Srwatson * SUCH DAMAGE.
60140617Srwatson */
612729Sdfr
62116182Sobrien#include <sys/cdefs.h>
63116182Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/kern/sysv_shm.c 298661 2016-04-26 19:57:35Z cem $");
64116182Sobrien
6531778Seivind#include "opt_compat.h"
6658820Speter#include "opt_sysvipc.h"
6713255Swollman
682729Sdfr#include <sys/param.h>
6911626Sbde#include <sys/systm.h>
702729Sdfr#include <sys/kernel.h>
71194910Sjhb#include <sys/limits.h>
7276166Smarkm#include <sys/lock.h>
7358820Speter#include <sys/sysctl.h>
742729Sdfr#include <sys/shm.h>
752729Sdfr#include <sys/proc.h>
762729Sdfr#include <sys/malloc.h>
7776941Sjhb#include <sys/mman.h>
78129882Sphk#include <sys/module.h>
7976827Salfred#include <sys/mutex.h>
80220398Strasz#include <sys/racct.h>
81130730Stjr#include <sys/resourcevar.h>
82248084Sattilio#include <sys/rwlock.h>
832729Sdfr#include <sys/stat.h>
8469449Salfred#include <sys/syscall.h>
85114724Smbr#include <sys/syscallsubr.h>
8611626Sbde#include <sys/sysent.h>
8776166Smarkm#include <sys/sysproto.h>
8868024Srwatson#include <sys/jail.h>
892729Sdfr
90163606Srwatson#include <security/mac/mac_framework.h>
91163606Srwatson
922729Sdfr#include <vm/vm.h>
9312662Sdg#include <vm/vm_param.h>
9412662Sdg#include <vm/pmap.h>
9518098Sdyson#include <vm/vm_object.h>
962729Sdfr#include <vm/vm_map.h>
9742957Sdillon#include <vm/vm_page.h>
9818199Sdyson#include <vm/vm_pager.h>
992729Sdfr
100219028SnetchildFEATURE(sysv_shm, "System V shared memory segments support");
101219028Snetchild
10230354Sphkstatic MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
10330309Sphk
10492723Salfredstatic int shmget_allocate_segment(struct thread *td,
10592723Salfred    struct shmget_args *uap, int mode);
10692723Salfredstatic int shmget_existing(struct thread *td, struct shmget_args *uap,
10792723Salfred    int mode, int segnum);
1088876Srgrimes
1092729Sdfr#define	SHMSEG_FREE     	0x0200
1102729Sdfr#define	SHMSEG_REMOVED  	0x0400
1112729Sdfr#define	SHMSEG_ALLOCATED	0x0800
1122729Sdfr
113189283Skibstatic int shm_last_free, shm_nused, shmalloced;
114189398Skibvm_size_t shm_committed;
115298585Sjamiestatic struct shmid_kernel *shmsegs;
116298585Sjamiestatic unsigned shm_prison_slot;
1172729Sdfr
1182729Sdfrstruct shmmap_state {
1192729Sdfr	vm_offset_t va;
1202729Sdfr	int shmid;
1212729Sdfr};
1222729Sdfr
123137613Srwatsonstatic void shm_deallocate_segment(struct shmid_kernel *);
124298585Sjamiestatic int shm_find_segment_by_key(struct prison *, key_t);
125298585Sjamiestatic struct shmid_kernel *shm_find_segment(struct prison *, int, bool);
126109205Sdillonstatic int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
12792723Salfredstatic void shmrealloc(void);
128205323Skibstatic int shminit(void);
12992723Salfredstatic int sysvshm_modload(struct module *, int, void *);
13092723Salfredstatic int shmunload(void);
131109205Sdillonstatic void shmexit_myhook(struct vmspace *vm);
13292723Salfredstatic void shmfork_myhook(struct proc *p1, struct proc *p2);
13392723Salfredstatic int sysctl_shmsegs(SYSCTL_HANDLER_ARGS);
134298585Sjamiestatic void shm_remove(struct shmid_kernel *, int);
135298585Sjamiestatic struct prison *shm_find_prison(struct ucred *);
136298585Sjamiestatic int shm_prison_cansee(struct prison *, struct shmid_kernel *);
137298585Sjamiestatic int shm_prison_check(void *, void *);
138298585Sjamiestatic int shm_prison_set(void *, void *);
139298585Sjamiestatic int shm_prison_get(void *, void *);
140298585Sjamiestatic int shm_prison_remove(void *, void *);
141298585Sjamiestatic void shm_prison_cleanup(struct prison *);
1422729Sdfr
14358820Speter/*
14477104Sdd * Tuneable values.
14558820Speter */
14658820Speter#ifndef SHMMAXPGS
147209037Sivoras#define	SHMMAXPGS	131072	/* Note: sysv shared memory is swap backed. */
14858820Speter#endif
14958820Speter#ifndef SHMMAX
15058820Speter#define	SHMMAX	(SHMMAXPGS*PAGE_SIZE)
15158820Speter#endif
15258820Speter#ifndef SHMMIN
15358820Speter#define	SHMMIN	1
15458820Speter#endif
15558820Speter#ifndef SHMMNI
15676275Sdillon#define	SHMMNI	192
15758820Speter#endif
15858820Speter#ifndef SHMSEG
15976275Sdillon#define	SHMSEG	128
16058820Speter#endif
16158820Speter#ifndef SHMALL
16258820Speter#define	SHMALL	(SHMMAXPGS)
16358820Speter#endif
16458820Speter
16558820Speterstruct	shminfo shminfo = {
166267992Shselasky	.shmmax = SHMMAX,
167267992Shselasky	.shmmin = SHMMIN,
168267992Shselasky	.shmmni = SHMMNI,
169267992Shselasky	.shmseg = SHMSEG,
170267992Shselasky	.shmall = SHMALL
17158820Speter};
17258820Speter
17361081Sdillonstatic int shm_use_phys;
174289112Straszstatic int shm_allow_removed = 1;
17561081Sdillon
176267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RWTUN, &shminfo.shmmax, 0,
177141710Scsjp    "Maximum shared memory segment size");
178267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RWTUN, &shminfo.shmmin, 0,
179141710Scsjp    "Minimum shared memory segment size");
180148782ScsjpSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
181141710Scsjp    "Number of shared memory identifiers");
182148782ScsjpSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
183141710Scsjp    "Number of segments per process");
184267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RWTUN, &shminfo.shmall, 0,
185141710Scsjp    "Maximum number of pages available for shared memory");
186267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RWTUN,
187141710Scsjp    &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
188267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RWTUN,
189141710Scsjp    &shm_allow_removed, 0,
190141710Scsjp    "Enable/Disable attachment to attached segments marked for removal");
191280323SkibSYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD |
192280323Skib    CTLFLAG_MPSAFE, NULL, 0, sysctl_shmsegs, "",
193141710Scsjp    "Current number of shared memory segments allocated");
19458820Speter
195280323Skibstatic struct sx sysvshmsx;
196280323Skib#define	SYSVSHM_LOCK()		sx_xlock(&sysvshmsx)
197280323Skib#define	SYSVSHM_UNLOCK()	sx_xunlock(&sysvshmsx)
198280323Skib#define	SYSVSHM_ASSERT_LOCKED()	sx_assert(&sysvshmsx, SA_XLOCKED)
199280323Skib
2002729Sdfrstatic int
201298585Sjamieshm_find_segment_by_key(struct prison *pr, key_t key)
2022729Sdfr{
2032729Sdfr	int i;
2042729Sdfr
20558820Speter	for (i = 0; i < shmalloced; i++)
206137613Srwatson		if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
207298585Sjamie		    shmsegs[i].cred != NULL &&
208298585Sjamie		    shmsegs[i].cred->cr_prison == pr &&
209137613Srwatson		    shmsegs[i].u.shm_perm.key == key)
210101891Salfred			return (i);
211101891Salfred	return (-1);
2122729Sdfr}
2132729Sdfr
214280323Skib/*
215280323Skib * Finds segment either by shmid if is_shmid is true, or by segnum if
216280323Skib * is_shmid is false.
217280323Skib */
218137613Srwatsonstatic struct shmid_kernel *
219298585Sjamieshm_find_segment(struct prison *rpr, int arg, bool is_shmid)
2202729Sdfr{
221280323Skib	struct shmid_kernel *shmseg;
2222729Sdfr	int segnum;
2232729Sdfr
224280323Skib	segnum = is_shmid ? IPCID_TO_IX(arg) : arg;
22558820Speter	if (segnum < 0 || segnum >= shmalloced)
226101891Salfred		return (NULL);
2272729Sdfr	shmseg = &shmsegs[segnum];
228137613Srwatson	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
229122088Sfjoe	    (!shm_allow_removed &&
230285057Smjg	    (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
231298585Sjamie	    (is_shmid && shmseg->u.shm_perm.seq != IPCID_TO_SEQ(arg)) ||
232298597Sjamie	    shm_prison_cansee(rpr, shmseg) != 0)
233101891Salfred		return (NULL);
234101891Salfred	return (shmseg);
2352729Sdfr}
2362729Sdfr
2372729Sdfrstatic void
238280323Skibshm_deallocate_segment(struct shmid_kernel *shmseg)
2392729Sdfr{
240189398Skib	vm_size_t size;
2412729Sdfr
242280323Skib	SYSVSHM_ASSERT_LOCKED();
24379224Sdillon
244194910Sjhb	vm_object_deallocate(shmseg->object);
245194910Sjhb	shmseg->object = NULL;
246194910Sjhb	size = round_page(shmseg->u.shm_segsz);
2472729Sdfr	shm_committed -= btoc(size);
2482729Sdfr	shm_nused--;
249137613Srwatson	shmseg->u.shm_perm.mode = SHMSEG_FREE;
250140617Srwatson#ifdef MAC
251172930Srwatson	mac_sysvshm_cleanup(shmseg);
252140617Srwatson#endif
253220398Strasz	racct_sub_cred(shmseg->cred, RACCT_NSHM, 1);
254220398Strasz	racct_sub_cred(shmseg->cred, RACCT_SHMSIZE, size);
255220388Strasz	crfree(shmseg->cred);
256220388Strasz	shmseg->cred = NULL;
2572729Sdfr}
2582729Sdfr
2592729Sdfrstatic int
260109205Sdillonshm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
2612729Sdfr{
262137613Srwatson	struct shmid_kernel *shmseg;
2632729Sdfr	int segnum, result;
264189398Skib	vm_size_t size;
2658876Srgrimes
266280323Skib	SYSVSHM_ASSERT_LOCKED();
267280323Skib	segnum = IPCID_TO_IX(shmmap_s->shmid);
268280323Skib	KASSERT(segnum >= 0 && segnum < shmalloced,
269280323Skib	    ("segnum %d shmalloced %d", segnum, shmalloced));
27077104Sdd
2712729Sdfr	shmseg = &shmsegs[segnum];
272194910Sjhb	size = round_page(shmseg->u.shm_segsz);
273109205Sdillon	result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
2742729Sdfr	if (result != KERN_SUCCESS)
275101891Salfred		return (EINVAL);
2762729Sdfr	shmmap_s->shmid = -1;
277137613Srwatson	shmseg->u.shm_dtime = time_second;
278137613Srwatson	if ((--shmseg->u.shm_nattch <= 0) &&
279137613Srwatson	    (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
2802729Sdfr		shm_deallocate_segment(shmseg);
2812729Sdfr		shm_last_free = segnum;
2822729Sdfr	}
283101891Salfred	return (0);
2842729Sdfr}
2852729Sdfr
286298585Sjamiestatic void
287298585Sjamieshm_remove(struct shmid_kernel *shmseg, int segnum)
288298585Sjamie{
289298585Sjamie
290298585Sjamie	shmseg->u.shm_perm.key = IPC_PRIVATE;
291298585Sjamie	shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
292298585Sjamie	if (shmseg->u.shm_nattch <= 0) {
293298585Sjamie		shm_deallocate_segment(shmseg);
294298585Sjamie		shm_last_free = segnum;
295298585Sjamie	}
296298585Sjamie}
297298585Sjamie
298298585Sjamiestatic struct prison *
299298585Sjamieshm_find_prison(struct ucred *cred)
300298585Sjamie{
301298585Sjamie	struct prison *pr, *rpr;
302298585Sjamie
303298585Sjamie	pr = cred->cr_prison;
304298585Sjamie	prison_lock(pr);
305298585Sjamie	rpr = osd_jail_get(pr, shm_prison_slot);
306298585Sjamie	prison_unlock(pr);
307298585Sjamie	return rpr;
308298585Sjamie}
309298585Sjamie
310280323Skibstatic int
311298585Sjamieshm_prison_cansee(struct prison *rpr, struct shmid_kernel *shmseg)
312298585Sjamie{
313298585Sjamie
314298585Sjamie	if (shmseg->cred == NULL ||
315298585Sjamie	    !(rpr == shmseg->cred->cr_prison ||
316298585Sjamie	      prison_ischild(rpr, shmseg->cred->cr_prison)))
317298585Sjamie		return (EINVAL);
318298585Sjamie	return (0);
319298585Sjamie}
320298585Sjamie
321298585Sjamiestatic int
322280323Skibkern_shmdt_locked(struct thread *td, const void *shmaddr)
3232729Sdfr{
32483366Sjulian	struct proc *p = td->td_proc;
3252729Sdfr	struct shmmap_state *shmmap_s;
326140617Srwatson#ifdef MAC
327140617Srwatson	struct shmid_kernel *shmsegptr;
328285057Smjg	int error;
329140617Srwatson#endif
330285057Smjg	int i;
3312729Sdfr
332280323Skib	SYSVSHM_ASSERT_LOCKED();
333298585Sjamie	if (shm_find_prison(td->td_ucred) == NULL)
33491703Sjhb		return (ENOSYS);
335100512Salfred	shmmap_s = p->p_vmspace->vm_shm;
336280323Skib 	if (shmmap_s == NULL)
337280323Skib		return (EINVAL);
33882607Sdillon	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
3392729Sdfr		if (shmmap_s->shmid != -1 &&
340280323Skib		    shmmap_s->va == (vm_offset_t)shmaddr) {
3412729Sdfr			break;
34282607Sdillon		}
34382607Sdillon	}
344280323Skib	if (i == shminfo.shmseg)
345280323Skib		return (EINVAL);
346140617Srwatson#ifdef MAC
347140617Srwatson	shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
348172930Srwatson	error = mac_sysvshm_check_shmdt(td->td_ucred, shmsegptr);
349162468Srwatson	if (error != 0)
350280323Skib		return (error);
351140617Srwatson#endif
352285057Smjg	return (shm_delete_mapping(p->p_vmspace, shmmap_s));
3532729Sdfr}
3542729Sdfr
35512866Speter#ifndef _SYS_SYSPROTO_H_
356280323Skibstruct shmdt_args {
357109831Salfred	const void *shmaddr;
3582729Sdfr};
35912866Speter#endif
3602729Sdfrint
361280323Skibsys_shmdt(struct thread *td, struct shmdt_args *uap)
3622729Sdfr{
363280323Skib	int error;
364280323Skib
365280323Skib	SYSVSHM_LOCK();
366280323Skib	error = kern_shmdt_locked(td, uap->shmaddr);
367280323Skib	SYSVSHM_UNLOCK();
368280323Skib	return (error);
369280323Skib}
370280323Skib
371280323Skibstatic int
372280323Skibkern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
373280323Skib    int shmflg)
374280323Skib{
375298585Sjamie	struct prison *rpr;
37683366Sjulian	struct proc *p = td->td_proc;
377137613Srwatson	struct shmid_kernel *shmseg;
378281071Skib	struct shmmap_state *shmmap_s;
3792729Sdfr	vm_offset_t attach_va;
3802729Sdfr	vm_prot_t prot;
3812729Sdfr	vm_size_t size;
382280323Skib	int error, i, rv;
3832729Sdfr
384280323Skib	SYSVSHM_ASSERT_LOCKED();
385298585Sjamie	rpr = shm_find_prison(td->td_ucred);
386298585Sjamie	if (rpr == NULL)
38791703Sjhb		return (ENOSYS);
388100512Salfred	shmmap_s = p->p_vmspace->vm_shm;
3892729Sdfr	if (shmmap_s == NULL) {
390189398Skib		shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state),
391189398Skib		    M_SHM, M_WAITOK);
392280323Skib		for (i = 0; i < shminfo.shmseg; i++)
393280323Skib			shmmap_s[i].shmid = -1;
394280323Skib		KASSERT(p->p_vmspace->vm_shm == NULL, ("raced"));
395280323Skib		p->p_vmspace->vm_shm = shmmap_s;
3962729Sdfr	}
397298585Sjamie	shmseg = shm_find_segment(rpr, shmid, true);
398280323Skib	if (shmseg == NULL)
399280323Skib		return (EINVAL);
400137613Srwatson	error = ipcperm(td, &shmseg->u.shm_perm,
401114724Smbr	    (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
402280323Skib	if (error != 0)
403280323Skib		return (error);
404140617Srwatson#ifdef MAC
405172930Srwatson	error = mac_sysvshm_check_shmat(td->td_ucred, shmseg, shmflg);
406162468Srwatson	if (error != 0)
407280323Skib		return (error);
408140617Srwatson#endif
4092729Sdfr	for (i = 0; i < shminfo.shmseg; i++) {
4102729Sdfr		if (shmmap_s->shmid == -1)
4112729Sdfr			break;
4122729Sdfr		shmmap_s++;
4132729Sdfr	}
414280323Skib	if (i >= shminfo.shmseg)
415280323Skib		return (EMFILE);
416194910Sjhb	size = round_page(shmseg->u.shm_segsz);
4172729Sdfr	prot = VM_PROT_READ;
418114724Smbr	if ((shmflg & SHM_RDONLY) == 0)
4192729Sdfr		prot |= VM_PROT_WRITE;
420280323Skib	if (shmaddr != NULL) {
421280323Skib		if ((shmflg & SHM_RND) != 0)
422298433Spfg			attach_va = rounddown2((vm_offset_t)shmaddr, SHMLBA);
423280323Skib		else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0)
424114724Smbr			attach_va = (vm_offset_t)shmaddr;
425280323Skib		else
426280323Skib			return (EINVAL);
4272729Sdfr	} else {
42877104Sdd		/*
42977104Sdd		 * This is just a hint to vm_map_find() about where to
43077104Sdd		 * put it.
43177104Sdd		 */
432130730Stjr		attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
433285056Smjg		    lim_max(td, RLIMIT_DATA));
4342729Sdfr	}
43518098Sdyson
436194910Sjhb	vm_object_reference(shmseg->object);
437270883Salc	rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va,
438270883Salc	    size, 0, shmaddr != NULL ? VMFS_NO_SPACE : VMFS_OPTIMAL_SPACE,
439270883Salc	    prot, prot, MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL);
44018098Sdyson	if (rv != KERN_SUCCESS) {
441194910Sjhb		vm_object_deallocate(shmseg->object);
442280323Skib		return (ENOMEM);
44318098Sdyson	}
44418231Sdyson
4452729Sdfr	shmmap_s->va = attach_va;
446114724Smbr	shmmap_s->shmid = shmid;
447137613Srwatson	shmseg->u.shm_lpid = p->p_pid;
448137613Srwatson	shmseg->u.shm_atime = time_second;
449137613Srwatson	shmseg->u.shm_nattch++;
45083366Sjulian	td->td_retval[0] = attach_va;
45182607Sdillon	return (error);
4522729Sdfr}
4532729Sdfr
454122201Srwatsonint
455280323Skibkern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg)
456114724Smbr{
457280323Skib	int error;
458280323Skib
459280323Skib	SYSVSHM_LOCK();
460280323Skib	error = kern_shmat_locked(td, shmid, shmaddr, shmflg);
461280323Skib	SYSVSHM_UNLOCK();
462280323Skib	return (error);
463114724Smbr}
464114724Smbr
465280323Skib#ifndef _SYS_SYSPROTO_H_
466280323Skibstruct shmat_args {
467280323Skib	int shmid;
468280323Skib	const void *shmaddr;
469280323Skib	int shmflg;
470280323Skib};
471280323Skib#endif
4722729Sdfrint
473280323Skibsys_shmat(struct thread *td, struct shmat_args *uap)
4742729Sdfr{
475280323Skib
476280323Skib	return (kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg));
477280323Skib}
478280323Skib
479280323Skibstatic int
480280323Skibkern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf,
481280323Skib    size_t *bufsz)
482280323Skib{
483298585Sjamie	struct prison *rpr;
484137613Srwatson	struct shmid_kernel *shmseg;
485280323Skib	struct shmid_ds *shmidp;
486280323Skib	struct shm_info shm_info;
487280323Skib	int error;
4882729Sdfr
489280323Skib	SYSVSHM_ASSERT_LOCKED();
490280323Skib
491298585Sjamie	rpr = shm_find_prison(td->td_ucred);
492298585Sjamie	if (rpr == NULL)
49391703Sjhb		return (ENOSYS);
494114724Smbr
495114724Smbr	switch (cmd) {
496176221Scsjp	/*
497176221Scsjp	 * It is possible that kern_shmctl is being called from the Linux ABI
498176221Scsjp	 * layer, in which case, we will need to implement IPC_INFO.  It should
499176221Scsjp	 * be noted that other shmctl calls will be funneled through here for
500176221Scsjp	 * Linix binaries as well.
501176221Scsjp	 *
502176221Scsjp	 * NB: The Linux ABI layer will convert this data to structure(s) more
503176221Scsjp	 * consistent with the Linux ABI.
504176221Scsjp	 */
50585623Smr	case IPC_INFO:
506114724Smbr		memcpy(buf, &shminfo, sizeof(shminfo));
507114724Smbr		if (bufsz)
508114724Smbr			*bufsz = sizeof(shminfo);
50985623Smr		td->td_retval[0] = shmalloced;
510280323Skib		return (0);
51185623Smr	case SHM_INFO: {
51285623Smr		shm_info.used_ids = shm_nused;
51385623Smr		shm_info.shm_rss = 0;	/*XXX where to get from ? */
51485623Smr		shm_info.shm_tot = 0;	/*XXX where to get from ? */
51585623Smr		shm_info.shm_swp = 0;	/*XXX where to get from ? */
51685623Smr		shm_info.swap_attempts = 0;	/*XXX where to get from ? */
51785623Smr		shm_info.swap_successes = 0;	/*XXX where to get from ? */
518114724Smbr		memcpy(buf, &shm_info, sizeof(shm_info));
519280323Skib		if (bufsz != NULL)
520114724Smbr			*bufsz = sizeof(shm_info);
52185623Smr		td->td_retval[0] = shmalloced;
522280323Skib		return (0);
52385623Smr	}
52485623Smr	}
525298585Sjamie	shmseg = shm_find_segment(rpr, shmid, cmd != SHM_STAT);
526280323Skib	if (shmseg == NULL)
527280323Skib		return (EINVAL);
528140617Srwatson#ifdef MAC
529172930Srwatson	error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd);
530162468Srwatson	if (error != 0)
531280323Skib		return (error);
532140617Srwatson#endif
533114724Smbr	switch (cmd) {
53485623Smr	case SHM_STAT:
5352729Sdfr	case IPC_STAT:
536298585Sjamie		shmidp = (struct shmid_ds *)buf;
537137613Srwatson		error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
538280323Skib		if (error != 0)
539280323Skib			return (error);
540298585Sjamie		memcpy(shmidp, &shmseg->u, sizeof(struct shmid_ds));
541298585Sjamie		if (td->td_ucred->cr_prison != shmseg->cred->cr_prison)
542298585Sjamie			shmidp->shm_perm.key = IPC_PRIVATE;
543280323Skib		if (bufsz != NULL)
544114724Smbr			*bufsz = sizeof(struct shmid_ds);
545280323Skib		if (cmd == SHM_STAT) {
546280323Skib			td->td_retval[0] = IXSEQ_TO_IPCID(shmid,
547280323Skib			    shmseg->u.shm_perm);
548280323Skib		}
5492729Sdfr		break;
550280323Skib	case IPC_SET:
551280323Skib		shmidp = (struct shmid_ds *)buf;
552137613Srwatson		error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
553280323Skib		if (error != 0)
554280323Skib			return (error);
555280323Skib		shmseg->u.shm_perm.uid = shmidp->shm_perm.uid;
556280323Skib		shmseg->u.shm_perm.gid = shmidp->shm_perm.gid;
557137613Srwatson		shmseg->u.shm_perm.mode =
558137613Srwatson		    (shmseg->u.shm_perm.mode & ~ACCESSPERMS) |
559280323Skib		    (shmidp->shm_perm.mode & ACCESSPERMS);
560137613Srwatson		shmseg->u.shm_ctime = time_second;
5612729Sdfr		break;
5622729Sdfr	case IPC_RMID:
563137613Srwatson		error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
564280323Skib		if (error != 0)
565280323Skib			return (error);
566298585Sjamie		shm_remove(shmseg, IPCID_TO_IX(shmid));
5672729Sdfr		break;
5682729Sdfr#if 0
5692729Sdfr	case SHM_LOCK:
5702729Sdfr	case SHM_UNLOCK:
5712729Sdfr#endif
5722729Sdfr	default:
57382607Sdillon		error = EINVAL;
57482607Sdillon		break;
5752729Sdfr	}
57682607Sdillon	return (error);
5772729Sdfr}
5782729Sdfr
579280323Skibint
580280323Skibkern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz)
581280323Skib{
582280323Skib	int error;
583280323Skib
584280323Skib	SYSVSHM_LOCK();
585280323Skib	error = kern_shmctl_locked(td, shmid, cmd, buf, bufsz);
586280323Skib	SYSVSHM_UNLOCK();
587280323Skib	return (error);
588280323Skib}
589280323Skib
590280323Skib
591194832Sjhb#ifndef _SYS_SYSPROTO_H_
592194832Sjhbstruct shmctl_args {
593194832Sjhb	int shmid;
594194832Sjhb	int cmd;
595194832Sjhb	struct shmid_ds *buf;
596194832Sjhb};
597194832Sjhb#endif
598114724Smbrint
599280323Skibsys_shmctl(struct thread *td, struct shmctl_args *uap)
600114724Smbr{
601285057Smjg	int error;
602114724Smbr	struct shmid_ds buf;
603114724Smbr	size_t bufsz;
604285057Smjg
605176221Scsjp	/*
606176221Scsjp	 * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
607176221Scsjp	 * Linux binaries.  If we see the call come through the FreeBSD ABI,
608176221Scsjp	 * return an error back to the user since we do not to support this.
609176221Scsjp	 */
610176221Scsjp	if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
611176221Scsjp	    uap->cmd == SHM_STAT)
612176221Scsjp		return (EINVAL);
613176221Scsjp
614114724Smbr	/* IPC_SET needs to copyin the buffer before calling kern_shmctl */
615114724Smbr	if (uap->cmd == IPC_SET) {
616114724Smbr		if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
617114724Smbr			goto done;
618114724Smbr	}
619285057Smjg
620122088Sfjoe	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
621114724Smbr	if (error)
622114724Smbr		goto done;
623285057Smjg
624114724Smbr	/* Cases in which we need to copyout */
625114724Smbr	switch (uap->cmd) {
626114724Smbr	case IPC_STAT:
627114724Smbr		error = copyout(&buf, uap->buf, bufsz);
628114724Smbr		break;
629114724Smbr	}
630114724Smbr
631114724Smbrdone:
632114724Smbr	if (error) {
633114724Smbr		/* Invalidate the return value */
634114724Smbr		td->td_retval[0] = -1;
635114724Smbr	}
636114724Smbr	return (error);
637114724Smbr}
638114724Smbr
639114724Smbr
6402729Sdfrstatic int
641280323Skibshmget_existing(struct thread *td, struct shmget_args *uap, int mode,
642280323Skib    int segnum)
6432729Sdfr{
644137613Srwatson	struct shmid_kernel *shmseg;
645280325Scognet#ifdef MAC
6462729Sdfr	int error;
647280325Scognet#endif
6482729Sdfr
649280323Skib	SYSVSHM_ASSERT_LOCKED();
650280323Skib	KASSERT(segnum >= 0 && segnum < shmalloced,
651280323Skib	    ("segnum %d shmalloced %d", segnum, shmalloced));
6522729Sdfr	shmseg = &shmsegs[segnum];
65348039Salc	if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
654101891Salfred		return (EEXIST);
655140617Srwatson#ifdef MAC
656172930Srwatson	error = mac_sysvshm_check_shmget(td->td_ucred, shmseg, uap->shmflg);
657162468Srwatson	if (error != 0)
658150937Srwatson		return (error);
659140617Srwatson#endif
660194910Sjhb	if (uap->size != 0 && uap->size > shmseg->u.shm_segsz)
661101891Salfred		return (EINVAL);
662137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
663101891Salfred	return (0);
6642729Sdfr}
6652729Sdfr
6662729Sdfrstatic int
667280323Skibshmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode)
6682729Sdfr{
66991406Sjhb	struct ucred *cred = td->td_ucred;
670137613Srwatson	struct shmid_kernel *shmseg;
671131857Salc	vm_object_t shm_object;
672280323Skib	int i, segnum;
673280323Skib	size_t size;
6748876Srgrimes
675280323Skib	SYSVSHM_ASSERT_LOCKED();
67679224Sdillon
6772729Sdfr	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
678101891Salfred		return (EINVAL);
67977104Sdd	if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
680101891Salfred		return (ENOSPC);
68115636Sjoerg	size = round_page(uap->size);
6822729Sdfr	if (shm_committed + btoc(size) > shminfo.shmall)
683101891Salfred		return (ENOMEM);
6842729Sdfr	if (shm_last_free < 0) {
68577104Sdd		shmrealloc();	/* Maybe expand the shmsegs[] array. */
68658820Speter		for (i = 0; i < shmalloced; i++)
687137613Srwatson			if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
6882729Sdfr				break;
68958820Speter		if (i == shmalloced)
690101891Salfred			return (ENOSPC);
6912729Sdfr		segnum = i;
6922729Sdfr	} else  {
6932729Sdfr		segnum = shm_last_free;
6942729Sdfr		shm_last_free = -1;
6952729Sdfr	}
696280323Skib	KASSERT(segnum >= 0 && segnum < shmalloced,
697280323Skib	    ("segnum %d shmalloced %d", segnum, shmalloced));
6982729Sdfr	shmseg = &shmsegs[segnum];
699223825Strasz#ifdef RACCT
700282213Strasz	if (racct_enable) {
701282213Strasz		PROC_LOCK(td->td_proc);
702282213Strasz		if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
703282213Strasz			PROC_UNLOCK(td->td_proc);
704282213Strasz			return (ENOSPC);
705282213Strasz		}
706282213Strasz		if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) {
707282213Strasz			racct_sub(td->td_proc, RACCT_NSHM, 1);
708282213Strasz			PROC_UNLOCK(td->td_proc);
709282213Strasz			return (ENOMEM);
710282213Strasz		}
711220398Strasz		PROC_UNLOCK(td->td_proc);
712220398Strasz	}
713223825Strasz#endif
714280323Skib
7152729Sdfr	/*
71618199Sdyson	 * We make sure that we have allocated a pager before we need
71718199Sdyson	 * to.
71818199Sdyson	 */
719194766Skib	shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP,
720194766Skib	    0, size, VM_PROT_DEFAULT, 0, cred);
721220398Strasz	if (shm_object == NULL) {
722223825Strasz#ifdef RACCT
723282213Strasz		if (racct_enable) {
724282213Strasz			PROC_LOCK(td->td_proc);
725282213Strasz			racct_sub(td->td_proc, RACCT_NSHM, 1);
726282213Strasz			racct_sub(td->td_proc, RACCT_SHMSIZE, size);
727282213Strasz			PROC_UNLOCK(td->td_proc);
728282213Strasz		}
729223825Strasz#endif
730194766Skib		return (ENOMEM);
731220398Strasz	}
732278697Salc	shm_object->pg_color = 0;
733248084Sattilio	VM_OBJECT_WLOCK(shm_object);
734131857Salc	vm_object_clear_flag(shm_object, OBJ_ONEMAPPING);
735278697Salc	vm_object_set_flag(shm_object, OBJ_COLORED | OBJ_NOSPLIT);
736248084Sattilio	VM_OBJECT_WUNLOCK(shm_object);
73735669Sdyson
738194910Sjhb	shmseg->object = shm_object;
739137613Srwatson	shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid;
740137613Srwatson	shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid;
741280323Skib	shmseg->u.shm_perm.mode = (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
742280323Skib	shmseg->u.shm_perm.key = uap->key;
743280323Skib	shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff;
744220399Strasz	shmseg->cred = crhold(cred);
745137613Srwatson	shmseg->u.shm_segsz = uap->size;
746137613Srwatson	shmseg->u.shm_cpid = td->td_proc->p_pid;
747137613Srwatson	shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0;
748137613Srwatson	shmseg->u.shm_atime = shmseg->u.shm_dtime = 0;
749140617Srwatson#ifdef MAC
750172930Srwatson	mac_sysvshm_create(cred, shmseg);
751140617Srwatson#endif
752137613Srwatson	shmseg->u.shm_ctime = time_second;
7532729Sdfr	shm_committed += btoc(size);
7542729Sdfr	shm_nused++;
755280323Skib	td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
756280323Skib
757101891Salfred	return (0);
7582729Sdfr}
7592729Sdfr
760194832Sjhb#ifndef _SYS_SYSPROTO_H_
761194832Sjhbstruct shmget_args {
762194832Sjhb	key_t key;
763194832Sjhb	size_t size;
764194832Sjhb	int shmflg;
765194832Sjhb};
766194832Sjhb#endif
7672729Sdfrint
768280323Skibsys_shmget(struct thread *td, struct shmget_args *uap)
7692729Sdfr{
77082607Sdillon	int segnum, mode;
77182607Sdillon	int error;
7722729Sdfr
773298585Sjamie	if (shm_find_prison(td->td_ucred) == NULL)
77491703Sjhb		return (ENOSYS);
7752729Sdfr	mode = uap->shmflg & ACCESSPERMS;
776280323Skib	SYSVSHM_LOCK();
777280323Skib	if (uap->key == IPC_PRIVATE) {
778280323Skib		error = shmget_allocate_segment(td, uap, mode);
779280323Skib	} else {
780298585Sjamie		segnum = shm_find_segment_by_key(td->td_ucred->cr_prison,
781298585Sjamie		    uap->key);
782280323Skib		if (segnum >= 0)
78383366Sjulian			error = shmget_existing(td, uap, mode, segnum);
784280323Skib		else if ((uap->shmflg & IPC_CREAT) == 0)
78582607Sdillon			error = ENOENT;
786280323Skib		else
787280323Skib			error = shmget_allocate_segment(td, uap, mode);
7882729Sdfr	}
789280323Skib	SYSVSHM_UNLOCK();
79082607Sdillon	return (error);
7912729Sdfr}
7922729Sdfr
79369449Salfredstatic void
794280323Skibshmfork_myhook(struct proc *p1, struct proc *p2)
7952729Sdfr{
7962729Sdfr	struct shmmap_state *shmmap_s;
7972729Sdfr	size_t size;
7982729Sdfr	int i;
7992729Sdfr
800280323Skib	SYSVSHM_LOCK();
8012729Sdfr	size = shminfo.shmseg * sizeof(struct shmmap_state);
802111119Simp	shmmap_s = malloc(size, M_SHM, M_WAITOK);
803100511Salfred	bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
804100511Salfred	p2->p_vmspace->vm_shm = shmmap_s;
805280323Skib	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
806280323Skib		if (shmmap_s->shmid != -1) {
807280323Skib			KASSERT(IPCID_TO_IX(shmmap_s->shmid) >= 0 &&
808280323Skib			    IPCID_TO_IX(shmmap_s->shmid) < shmalloced,
809280323Skib			    ("segnum %d shmalloced %d",
810280323Skib			    IPCID_TO_IX(shmmap_s->shmid), shmalloced));
811137613Srwatson			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
812280323Skib		}
813280323Skib	}
814280323Skib	SYSVSHM_UNLOCK();
8152729Sdfr}
8162729Sdfr
81769449Salfredstatic void
818109205Sdillonshmexit_myhook(struct vmspace *vm)
8192729Sdfr{
820109205Sdillon	struct shmmap_state *base, *shm;
8212729Sdfr	int i;
8222729Sdfr
823280323Skib	base = vm->vm_shm;
824280323Skib	if (base != NULL) {
825109205Sdillon		vm->vm_shm = NULL;
826280323Skib		SYSVSHM_LOCK();
827109205Sdillon		for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
828109205Sdillon			if (shm->shmid != -1)
829109205Sdillon				shm_delete_mapping(vm, shm);
830109205Sdillon		}
831280323Skib		SYSVSHM_UNLOCK();
832109205Sdillon		free(base, M_SHM);
833109205Sdillon	}
8342729Sdfr}
8352729Sdfr
83658820Speterstatic void
83758820Spetershmrealloc(void)
83858820Speter{
839280323Skib	struct shmid_kernel *newsegs;
84058820Speter	int i;
84158820Speter
842280323Skib	SYSVSHM_ASSERT_LOCKED();
843280323Skib
84458820Speter	if (shmalloced >= shminfo.shmmni)
84558820Speter		return;
84658820Speter
847111119Simp	newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
84858820Speter	for (i = 0; i < shmalloced; i++)
84958820Speter		bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
85058820Speter	for (; i < shminfo.shmmni; i++) {
851285055Smjg		newsegs[i].u.shm_perm.mode = SHMSEG_FREE;
852285055Smjg		newsegs[i].u.shm_perm.seq = 0;
853140617Srwatson#ifdef MAC
854285055Smjg		mac_sysvshm_init(&newsegs[i]);
855140617Srwatson#endif
85658820Speter	}
85758820Speter	free(shmsegs, M_SHM);
85858820Speter	shmsegs = newsegs;
85958820Speter	shmalloced = shminfo.shmmni;
86058820Speter}
86158820Speter
862205323Skibstatic struct syscall_helper_data shm_syscalls[] = {
863205323Skib	SYSCALL_INIT_HELPER(shmat),
864205323Skib	SYSCALL_INIT_HELPER(shmctl),
865205323Skib	SYSCALL_INIT_HELPER(shmdt),
866205323Skib	SYSCALL_INIT_HELPER(shmget),
867205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
868205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
869225617Skmacy	SYSCALL_INIT_HELPER_COMPAT(freebsd7_shmctl),
870205323Skib#endif
871205323Skib#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
872205323Skib	SYSCALL_INIT_HELPER(shmsys),
873205323Skib#endif
874205323Skib	SYSCALL_INIT_LAST
875205323Skib};
876205323Skib
877205323Skib#ifdef COMPAT_FREEBSD32
878205323Skib#include <compat/freebsd32/freebsd32.h>
879205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
880205323Skib#include <compat/freebsd32/freebsd32_proto.h>
881205323Skib#include <compat/freebsd32/freebsd32_signal.h>
882205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
883205323Skib#include <compat/freebsd32/freebsd32_util.h>
884205323Skib
885205323Skibstatic struct syscall_helper_data shm32_syscalls[] = {
886225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(shmat),
887225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(shmdt),
888225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(shmget),
889205323Skib	SYSCALL32_INIT_HELPER(freebsd32_shmsys),
890205323Skib	SYSCALL32_INIT_HELPER(freebsd32_shmctl),
891205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
892205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
893205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_shmctl),
894205323Skib#endif
895205323Skib	SYSCALL_INIT_LAST
896205323Skib};
897205323Skib#endif
898205323Skib
899205323Skibstatic int
900280323Skibshminit(void)
9012729Sdfr{
902298585Sjamie	struct prison *pr;
903298661Scem	void **rsv;
904205323Skib	int i, error;
905298585Sjamie	osd_method_t methods[PR_MAXMETHOD] = {
906298585Sjamie	    [PR_METHOD_CHECK] =		shm_prison_check,
907298585Sjamie	    [PR_METHOD_SET] =		shm_prison_set,
908298585Sjamie	    [PR_METHOD_GET] =		shm_prison_get,
909298585Sjamie	    [PR_METHOD_REMOVE] =	shm_prison_remove,
910298585Sjamie	};
91158820Speter
912198449Sru#ifndef BURN_BRIDGES
913198449Sru	if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0)
914198449Sru		printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n");
915198449Sru#endif
916267992Shselasky	if (shminfo.shmmax == SHMMAX) {
917231195Spjd		/* Initialize shmmax dealing with possible overflow. */
918267992Shselasky		for (i = PAGE_SIZE; i != 0; i--) {
919231195Spjd			shminfo.shmmax = shminfo.shmall * i;
920267992Shselasky			if ((shminfo.shmmax / shminfo.shmall) == (u_long)i)
921231195Spjd				break;
922231195Spjd		}
923110982Salfred	}
92458820Speter	shmalloced = shminfo.shmmni;
925111119Simp	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
92658820Speter	for (i = 0; i < shmalloced; i++) {
927137613Srwatson		shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
928137613Srwatson		shmsegs[i].u.shm_perm.seq = 0;
929140617Srwatson#ifdef MAC
930172930Srwatson		mac_sysvshm_init(&shmsegs[i]);
931140617Srwatson#endif
9322729Sdfr	}
9332729Sdfr	shm_last_free = 0;
9342729Sdfr	shm_nused = 0;
9352729Sdfr	shm_committed = 0;
936280323Skib	sx_init(&sysvshmsx, "sysvshmsx");
93769449Salfred	shmexit_hook = &shmexit_myhook;
93869449Salfred	shmfork_hook = &shmfork_myhook;
939205323Skib
940298585Sjamie	/* Set current prisons according to their allow.sysvipc. */
941298585Sjamie	shm_prison_slot = osd_jail_register(NULL, methods);
942298585Sjamie	rsv = osd_reserve(shm_prison_slot);
943298585Sjamie	prison_lock(&prison0);
944298585Sjamie	(void)osd_jail_set_reserved(&prison0, shm_prison_slot, rsv, &prison0);
945298585Sjamie	prison_unlock(&prison0);
946298585Sjamie	rsv = NULL;
947298585Sjamie	sx_slock(&allprison_lock);
948298585Sjamie	TAILQ_FOREACH(pr, &allprison, pr_list) {
949298585Sjamie		if (rsv == NULL)
950298585Sjamie			rsv = osd_reserve(shm_prison_slot);
951298585Sjamie		prison_lock(pr);
952298585Sjamie		if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) {
953298585Sjamie			(void)osd_jail_set_reserved(pr, shm_prison_slot, rsv,
954298585Sjamie			    &prison0);
955298585Sjamie			rsv = NULL;
956298585Sjamie		}
957298585Sjamie		prison_unlock(pr);
958298585Sjamie	}
959298585Sjamie	if (rsv != NULL)
960298585Sjamie		osd_free_reserved(rsv);
961298585Sjamie	sx_sunlock(&allprison_lock);
962298585Sjamie
963273707Smjg	error = syscall_helper_register(shm_syscalls, SY_THR_STATIC_KLD);
964205323Skib	if (error != 0)
965205323Skib		return (error);
966205323Skib#ifdef COMPAT_FREEBSD32
967273707Smjg	error = syscall32_helper_register(shm32_syscalls, SY_THR_STATIC_KLD);
968205323Skib	if (error != 0)
969205323Skib		return (error);
970205323Skib#endif
971205323Skib	return (0);
9722729Sdfr}
97369449Salfred
97469449Salfredstatic int
975280323Skibshmunload(void)
97669449Salfred{
977285057Smjg	int i;
97869449Salfred
97969449Salfred	if (shm_nused > 0)
98069449Salfred		return (EBUSY);
98169449Salfred
982205323Skib#ifdef COMPAT_FREEBSD32
983205323Skib	syscall32_helper_unregister(shm32_syscalls);
984205323Skib#endif
985205323Skib	syscall_helper_unregister(shm_syscalls);
986298585Sjamie	if (shm_prison_slot != 0)
987298585Sjamie		osd_jail_deregister(shm_prison_slot);
988205323Skib
989209580Skib	for (i = 0; i < shmalloced; i++) {
990140617Srwatson#ifdef MAC
991172930Srwatson		mac_sysvshm_destroy(&shmsegs[i]);
992140617Srwatson#endif
993209580Skib		/*
994209580Skib		 * Objects might be still mapped into the processes
995209580Skib		 * address spaces.  Actual free would happen on the
996209580Skib		 * last mapping destruction.
997209580Skib		 */
998209580Skib		if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE)
999209580Skib			vm_object_deallocate(shmsegs[i].object);
1000209580Skib	}
100169449Salfred	free(shmsegs, M_SHM);
100269449Salfred	shmexit_hook = NULL;
100369449Salfred	shmfork_hook = NULL;
1004280323Skib	sx_destroy(&sysvshmsx);
100569449Salfred	return (0);
100669449Salfred}
100769449Salfred
100869449Salfredstatic int
100977461Sddsysctl_shmsegs(SYSCTL_HANDLER_ARGS)
101077461Sdd{
1011298656Sjamie	struct shmid_kernel tshmseg;
1012298656Sjamie	struct prison *pr, *rpr;
1013298585Sjamie	int error, i;
101477461Sdd
1015280323Skib	SYSVSHM_LOCK();
1016298656Sjamie	pr = req->td->td_ucred->cr_prison;
1017298585Sjamie	rpr = shm_find_prison(req->td->td_ucred);
1018298656Sjamie	error = 0;
1019298585Sjamie	for (i = 0; i < shmalloced; i++) {
1020298656Sjamie		if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
1021298585Sjamie		    rpr == NULL || shm_prison_cansee(rpr, &shmsegs[i]) != 0) {
1022298656Sjamie			bzero(&tshmseg, sizeof(tshmseg));
1023298656Sjamie			tshmseg.u.shm_perm.mode = SHMSEG_FREE;
1024298656Sjamie		} else {
1025298656Sjamie			tshmseg = shmsegs[i];
1026298656Sjamie			if (tshmseg.cred->cr_prison != pr)
1027298656Sjamie				tshmseg.u.shm_perm.key = IPC_PRIVATE;
1028298585Sjamie		}
1029298656Sjamie		error = SYSCTL_OUT(req, &tshmseg, sizeof(tshmseg));
1030298656Sjamie		if (error != 0)
1031298656Sjamie			break;
1032298585Sjamie	}
1033280323Skib	SYSVSHM_UNLOCK();
1034280323Skib	return (error);
103577461Sdd}
103677461Sdd
1037298585Sjamiestatic int
1038298585Sjamieshm_prison_check(void *obj, void *data)
1039298585Sjamie{
1040298585Sjamie	struct prison *pr = obj;
1041298585Sjamie	struct prison *prpr;
1042298585Sjamie	struct vfsoptlist *opts = data;
1043298585Sjamie	int error, jsys;
1044298585Sjamie
1045298585Sjamie	/*
1046298585Sjamie	 * sysvshm is a jailsys integer.
1047298585Sjamie	 * It must be "disable" if the parent jail is disabled.
1048298585Sjamie	 */
1049298585Sjamie	error = vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys));
1050298585Sjamie	if (error != ENOENT) {
1051298585Sjamie		if (error != 0)
1052298585Sjamie			return (error);
1053298585Sjamie		switch (jsys) {
1054298585Sjamie		case JAIL_SYS_DISABLE:
1055298585Sjamie			break;
1056298585Sjamie		case JAIL_SYS_NEW:
1057298585Sjamie		case JAIL_SYS_INHERIT:
1058298585Sjamie			prison_lock(pr->pr_parent);
1059298585Sjamie			prpr = osd_jail_get(pr->pr_parent, shm_prison_slot);
1060298585Sjamie			prison_unlock(pr->pr_parent);
1061298585Sjamie			if (prpr == NULL)
1062298585Sjamie				return (EPERM);
1063298585Sjamie			break;
1064298585Sjamie		default:
1065298585Sjamie			return (EINVAL);
1066298585Sjamie		}
1067298585Sjamie	}
1068298585Sjamie
1069298585Sjamie	return (0);
1070298585Sjamie}
1071298585Sjamie
1072298585Sjamiestatic int
1073298585Sjamieshm_prison_set(void *obj, void *data)
1074298585Sjamie{
1075298585Sjamie	struct prison *pr = obj;
1076298585Sjamie	struct prison *tpr, *orpr, *nrpr, *trpr;
1077298585Sjamie	struct vfsoptlist *opts = data;
1078298585Sjamie	void *rsv;
1079298585Sjamie	int jsys, descend;
1080298585Sjamie
1081298585Sjamie	/*
1082298585Sjamie	 * sysvshm controls which jail is the root of the associated segments
1083298585Sjamie	 * (this jail or same as the parent), or if the feature is available
1084298585Sjamie	 * at all.
1085298585Sjamie	 */
1086298585Sjamie	if (vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys)) == ENOENT)
1087298585Sjamie		jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0)
1088298585Sjamie		    ? JAIL_SYS_INHERIT
1089298585Sjamie		    : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0)
1090298585Sjamie		    ? JAIL_SYS_DISABLE
1091298585Sjamie		    : -1;
1092298585Sjamie	if (jsys == JAIL_SYS_DISABLE) {
1093298585Sjamie		prison_lock(pr);
1094298585Sjamie		orpr = osd_jail_get(pr, shm_prison_slot);
1095298585Sjamie		if (orpr != NULL)
1096298585Sjamie			osd_jail_del(pr, shm_prison_slot);
1097298585Sjamie		prison_unlock(pr);
1098298585Sjamie		if (orpr != NULL) {
1099298585Sjamie			if (orpr == pr)
1100298585Sjamie				shm_prison_cleanup(pr);
1101298585Sjamie			/* Disable all child jails as well. */
1102298585Sjamie			FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1103298585Sjamie				prison_lock(tpr);
1104298585Sjamie				trpr = osd_jail_get(tpr, shm_prison_slot);
1105298585Sjamie				if (trpr != NULL) {
1106298585Sjamie					osd_jail_del(tpr, shm_prison_slot);
1107298585Sjamie					prison_unlock(tpr);
1108298585Sjamie					if (trpr == tpr)
1109298585Sjamie						shm_prison_cleanup(tpr);
1110298585Sjamie				} else {
1111298585Sjamie					prison_unlock(tpr);
1112298585Sjamie					descend = 0;
1113298585Sjamie				}
1114298585Sjamie			}
1115298585Sjamie		}
1116298585Sjamie	} else if (jsys != -1) {
1117298585Sjamie		if (jsys == JAIL_SYS_NEW)
1118298585Sjamie			nrpr = pr;
1119298585Sjamie		else {
1120298585Sjamie			prison_lock(pr->pr_parent);
1121298585Sjamie			nrpr = osd_jail_get(pr->pr_parent, shm_prison_slot);
1122298585Sjamie			prison_unlock(pr->pr_parent);
1123298585Sjamie		}
1124298585Sjamie		rsv = osd_reserve(shm_prison_slot);
1125298585Sjamie		prison_lock(pr);
1126298585Sjamie		orpr = osd_jail_get(pr, shm_prison_slot);
1127298585Sjamie		if (orpr != nrpr)
1128298585Sjamie			(void)osd_jail_set_reserved(pr, shm_prison_slot, rsv,
1129298585Sjamie			    nrpr);
1130298585Sjamie		else
1131298585Sjamie			osd_free_reserved(rsv);
1132298585Sjamie		prison_unlock(pr);
1133298585Sjamie		if (orpr != nrpr) {
1134298585Sjamie			if (orpr == pr)
1135298585Sjamie				shm_prison_cleanup(pr);
1136298585Sjamie			if (orpr != NULL) {
1137298585Sjamie				/* Change child jails matching the old root, */
1138298585Sjamie				FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
1139298585Sjamie					prison_lock(tpr);
1140298585Sjamie					trpr = osd_jail_get(tpr,
1141298585Sjamie					    shm_prison_slot);
1142298585Sjamie					if (trpr == orpr) {
1143298585Sjamie						(void)osd_jail_set(tpr,
1144298585Sjamie						    shm_prison_slot, nrpr);
1145298585Sjamie						prison_unlock(tpr);
1146298585Sjamie						if (trpr == tpr)
1147298585Sjamie							shm_prison_cleanup(tpr);
1148298585Sjamie					} else {
1149298585Sjamie						prison_unlock(tpr);
1150298585Sjamie						descend = 0;
1151298585Sjamie					}
1152298585Sjamie				}
1153298585Sjamie			}
1154298585Sjamie		}
1155298585Sjamie	}
1156298585Sjamie
1157298585Sjamie	return (0);
1158298585Sjamie}
1159298585Sjamie
1160298585Sjamiestatic int
1161298585Sjamieshm_prison_get(void *obj, void *data)
1162298585Sjamie{
1163298585Sjamie	struct prison *pr = obj;
1164298585Sjamie	struct prison *rpr;
1165298585Sjamie	struct vfsoptlist *opts = data;
1166298585Sjamie	int error, jsys;
1167298585Sjamie
1168298585Sjamie	/* Set sysvshm based on the jail's root prison. */
1169298585Sjamie	prison_lock(pr);
1170298585Sjamie	rpr = osd_jail_get(pr, shm_prison_slot);
1171298585Sjamie	prison_unlock(pr);
1172298585Sjamie	jsys = rpr == NULL ? JAIL_SYS_DISABLE
1173298585Sjamie	    : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
1174298585Sjamie	error = vfs_setopt(opts, "sysvshm", &jsys, sizeof(jsys));
1175298585Sjamie	if (error == ENOENT)
1176298585Sjamie		error = 0;
1177298585Sjamie	return (error);
1178298585Sjamie}
1179298585Sjamie
1180298585Sjamiestatic int
1181298585Sjamieshm_prison_remove(void *obj, void *data __unused)
1182298585Sjamie{
1183298585Sjamie	struct prison *pr = obj;
1184298585Sjamie	struct prison *rpr;
1185298585Sjamie
1186298585Sjamie	SYSVSHM_LOCK();
1187298585Sjamie	prison_lock(pr);
1188298585Sjamie	rpr = osd_jail_get(pr, shm_prison_slot);
1189298585Sjamie	prison_unlock(pr);
1190298585Sjamie	if (rpr == pr)
1191298585Sjamie		shm_prison_cleanup(pr);
1192298585Sjamie	SYSVSHM_UNLOCK();
1193298585Sjamie	return (0);
1194298585Sjamie}
1195298585Sjamie
1196298585Sjamiestatic void
1197298585Sjamieshm_prison_cleanup(struct prison *pr)
1198298585Sjamie{
1199298585Sjamie	struct shmid_kernel *shmseg;
1200298585Sjamie	int i;
1201298585Sjamie
1202298585Sjamie	/* Remove any segments that belong to this jail. */
1203298585Sjamie	for (i = 0; i < shmalloced; i++) {
1204298585Sjamie		shmseg = &shmsegs[i];
1205298585Sjamie		if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) &&
1206298585Sjamie		    shmseg->cred != NULL && shmseg->cred->cr_prison == pr) {
1207298585Sjamie			shm_remove(shmseg, i);
1208298585Sjamie		}
1209298585Sjamie	}
1210298585Sjamie}
1211298585Sjamie
1212298585SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvshm, CTLFLAG_RW, "SYSV shared memory");
1213298585Sjamie
1214194894Sjhb#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
1215194894Sjhbstruct oshmid_ds {
1216194894Sjhb	struct	ipc_perm_old shm_perm;	/* operation perms */
1217194894Sjhb	int	shm_segsz;		/* size of segment (bytes) */
1218194894Sjhb	u_short	shm_cpid;		/* pid, creator */
1219194894Sjhb	u_short	shm_lpid;		/* pid, last operation */
1220194894Sjhb	short	shm_nattch;		/* no. of current attaches */
1221194894Sjhb	time_t	shm_atime;		/* last attach time */
1222194894Sjhb	time_t	shm_dtime;		/* last detach time */
1223194894Sjhb	time_t	shm_ctime;		/* last change time */
1224194894Sjhb	void	*shm_handle;		/* internal handle for shm segment */
1225194894Sjhb};
1226194894Sjhb
1227194894Sjhbstruct oshmctl_args {
1228194894Sjhb	int shmid;
1229194894Sjhb	int cmd;
1230194894Sjhb	struct oshmid_ds *ubuf;
1231194894Sjhb};
1232194894Sjhb
123377461Sddstatic int
1234194959Sjhboshmctl(struct thread *td, struct oshmctl_args *uap)
1235194894Sjhb{
1236194894Sjhb#ifdef COMPAT_43
1237194894Sjhb	int error = 0;
1238298585Sjamie	struct prison *rpr;
1239194894Sjhb	struct shmid_kernel *shmseg;
1240194894Sjhb	struct oshmid_ds outbuf;
1241194894Sjhb
1242298585Sjamie	rpr = shm_find_prison(td->td_ucred);
1243298585Sjamie	if (rpr == NULL)
1244194894Sjhb		return (ENOSYS);
1245282084Skib	if (uap->cmd != IPC_STAT) {
1246282084Skib		return (freebsd7_shmctl(td,
1247282084Skib		    (struct freebsd7_shmctl_args *)uap));
1248282084Skib	}
1249280323Skib	SYSVSHM_LOCK();
1250298585Sjamie	shmseg = shm_find_segment(rpr, uap->shmid, true);
1251194894Sjhb	if (shmseg == NULL) {
1252280323Skib		SYSVSHM_UNLOCK();
1253281094Skib		return (EINVAL);
1254194894Sjhb	}
1255282084Skib	error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
1256282084Skib	if (error != 0) {
1257282084Skib		SYSVSHM_UNLOCK();
1258282084Skib		return (error);
1259282084Skib	}
1260194894Sjhb#ifdef MAC
1261282084Skib	error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd);
1262282084Skib	if (error != 0) {
1263282084Skib		SYSVSHM_UNLOCK();
1264282084Skib		return (error);
1265282084Skib	}
1266194894Sjhb#endif
1267282084Skib	ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm);
1268282084Skib	outbuf.shm_segsz = shmseg->u.shm_segsz;
1269282084Skib	outbuf.shm_cpid = shmseg->u.shm_cpid;
1270282084Skib	outbuf.shm_lpid = shmseg->u.shm_lpid;
1271282084Skib	outbuf.shm_nattch = shmseg->u.shm_nattch;
1272282084Skib	outbuf.shm_atime = shmseg->u.shm_atime;
1273282084Skib	outbuf.shm_dtime = shmseg->u.shm_dtime;
1274282084Skib	outbuf.shm_ctime = shmseg->u.shm_ctime;
1275282084Skib	outbuf.shm_handle = shmseg->object;
1276280323Skib	SYSVSHM_UNLOCK();
1277285057Smjg	return (copyout(&outbuf, uap->ubuf, sizeof(outbuf)));
1278194894Sjhb#else
1279194894Sjhb	return (EINVAL);
1280194894Sjhb#endif
1281194894Sjhb}
1282194894Sjhb
1283194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1284194894Sjhbstatic sy_call_t *shmcalls[] = {
1285225617Skmacy	(sy_call_t *)sys_shmat, (sy_call_t *)oshmctl,
1286225617Skmacy	(sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget,
1287194910Sjhb	(sy_call_t *)freebsd7_shmctl
1288194894Sjhb};
1289194894Sjhb
1290280323Skib#ifndef _SYS_SYSPROTO_H_
1291280323Skib/* XXX actually varargs. */
1292280323Skibstruct shmsys_args {
1293280323Skib	int	which;
1294280323Skib	int	a2;
1295280323Skib	int	a3;
1296280323Skib	int	a4;
1297280323Skib};
1298280323Skib#endif
1299194894Sjhbint
1300280323Skibsys_shmsys(struct thread *td, struct shmsys_args *uap)
1301194894Sjhb{
1302194894Sjhb
1303280323Skib	if (uap->which < 0 || uap->which >= nitems(shmcalls))
1304194894Sjhb		return (EINVAL);
1305285057Smjg	return ((*shmcalls[uap->which])(td, &uap->a2));
1306194894Sjhb}
1307194894Sjhb
1308194894Sjhb#endif	/* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */
1309194894Sjhb
1310205323Skib#ifdef COMPAT_FREEBSD32
1311205323Skib
1312205323Skibint
1313205323Skibfreebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
1314205323Skib{
1315205323Skib
1316194910Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1317194910Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1318205323Skib	switch (uap->which) {
1319205323Skib	case 0:	{	/* shmat */
1320205323Skib		struct shmat_args ap;
1321194910Sjhb
1322205323Skib		ap.shmid = uap->a2;
1323205323Skib		ap.shmaddr = PTRIN(uap->a3);
1324205323Skib		ap.shmflg = uap->a4;
1325205323Skib		return (sysent[SYS_shmat].sy_call(td, &ap));
1326205323Skib	}
1327205323Skib	case 2: {	/* shmdt */
1328205323Skib		struct shmdt_args ap;
1329205323Skib
1330205323Skib		ap.shmaddr = PTRIN(uap->a2);
1331205323Skib		return (sysent[SYS_shmdt].sy_call(td, &ap));
1332205323Skib	}
1333205323Skib	case 3: {	/* shmget */
1334205323Skib		struct shmget_args ap;
1335205323Skib
1336205323Skib		ap.key = uap->a2;
1337205323Skib		ap.size = uap->a3;
1338205323Skib		ap.shmflg = uap->a4;
1339205323Skib		return (sysent[SYS_shmget].sy_call(td, &ap));
1340205323Skib	}
1341205323Skib	case 4: {	/* shmctl */
1342205323Skib		struct freebsd7_freebsd32_shmctl_args ap;
1343205323Skib
1344205323Skib		ap.shmid = uap->a2;
1345205323Skib		ap.cmd = uap->a3;
1346205323Skib		ap.buf = PTRIN(uap->a4);
1347205323Skib		return (freebsd7_freebsd32_shmctl(td, &ap));
1348205323Skib	}
1349205323Skib	case 1:		/* oshmctl */
1350205323Skib	default:
1351205323Skib		return (EINVAL);
1352205323Skib	}
1353205323Skib#else
1354205323Skib	return (nosys(td, NULL));
1355205323Skib#endif
1356205323Skib}
1357205323Skib
1358205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1359205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1360205323Skibint
1361205323Skibfreebsd7_freebsd32_shmctl(struct thread *td,
1362205323Skib    struct freebsd7_freebsd32_shmctl_args *uap)
1363205323Skib{
1364285057Smjg	int error;
1365205323Skib	union {
1366205323Skib		struct shmid_ds shmid_ds;
1367205323Skib		struct shm_info shm_info;
1368205323Skib		struct shminfo shminfo;
1369205323Skib	} u;
1370205323Skib	union {
1371205323Skib		struct shmid_ds32_old shmid_ds32;
1372205323Skib		struct shm_info32 shm_info32;
1373205323Skib		struct shminfo32 shminfo32;
1374205323Skib	} u32;
1375205323Skib	size_t sz;
1376205323Skib
1377205323Skib	if (uap->cmd == IPC_SET) {
1378205323Skib		if ((error = copyin(uap->buf, &u32.shmid_ds32,
1379205323Skib		    sizeof(u32.shmid_ds32))))
1380205323Skib			goto done;
1381205323Skib		freebsd32_ipcperm_old_in(&u32.shmid_ds32.shm_perm,
1382205323Skib		    &u.shmid_ds.shm_perm);
1383205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
1384205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
1385205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
1386205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
1387205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
1388205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
1389205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
1390205323Skib	}
1391285057Smjg
1392205323Skib	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
1393205323Skib	if (error)
1394205323Skib		goto done;
1395285057Smjg
1396205323Skib	/* Cases in which we need to copyout */
1397205323Skib	switch (uap->cmd) {
1398205323Skib	case IPC_INFO:
1399205323Skib		CP(u.shminfo, u32.shminfo32, shmmax);
1400205323Skib		CP(u.shminfo, u32.shminfo32, shmmin);
1401205323Skib		CP(u.shminfo, u32.shminfo32, shmmni);
1402205323Skib		CP(u.shminfo, u32.shminfo32, shmseg);
1403205323Skib		CP(u.shminfo, u32.shminfo32, shmall);
1404205323Skib		error = copyout(&u32.shminfo32, uap->buf,
1405205323Skib		    sizeof(u32.shminfo32));
1406205323Skib		break;
1407205323Skib	case SHM_INFO:
1408205323Skib		CP(u.shm_info, u32.shm_info32, used_ids);
1409205323Skib		CP(u.shm_info, u32.shm_info32, shm_rss);
1410205323Skib		CP(u.shm_info, u32.shm_info32, shm_tot);
1411205323Skib		CP(u.shm_info, u32.shm_info32, shm_swp);
1412205323Skib		CP(u.shm_info, u32.shm_info32, swap_attempts);
1413205323Skib		CP(u.shm_info, u32.shm_info32, swap_successes);
1414205323Skib		error = copyout(&u32.shm_info32, uap->buf,
1415205323Skib		    sizeof(u32.shm_info32));
1416205323Skib		break;
1417205323Skib	case SHM_STAT:
1418205323Skib	case IPC_STAT:
1419205323Skib		freebsd32_ipcperm_old_out(&u.shmid_ds.shm_perm,
1420205323Skib		    &u32.shmid_ds32.shm_perm);
1421205323Skib		if (u.shmid_ds.shm_segsz > INT32_MAX)
1422205323Skib			u32.shmid_ds32.shm_segsz = INT32_MAX;
1423205323Skib		else
1424205323Skib			CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
1425205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
1426205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
1427205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
1428205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
1429205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
1430205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
1431205323Skib		u32.shmid_ds32.shm_internal = 0;
1432205323Skib		error = copyout(&u32.shmid_ds32, uap->buf,
1433205323Skib		    sizeof(u32.shmid_ds32));
1434205323Skib		break;
1435205323Skib	}
1436205323Skib
1437205323Skibdone:
1438205323Skib	if (error) {
1439205323Skib		/* Invalidate the return value */
1440205323Skib		td->td_retval[0] = -1;
1441205323Skib	}
1442205323Skib	return (error);
1443205323Skib}
1444205323Skib#endif
1445205323Skib
1446205323Skibint
1447205323Skibfreebsd32_shmctl(struct thread *td, struct freebsd32_shmctl_args *uap)
1448205323Skib{
1449285057Smjg	int error;
1450205323Skib	union {
1451205323Skib		struct shmid_ds shmid_ds;
1452205323Skib		struct shm_info shm_info;
1453205323Skib		struct shminfo shminfo;
1454205323Skib	} u;
1455205323Skib	union {
1456205323Skib		struct shmid_ds32 shmid_ds32;
1457205323Skib		struct shm_info32 shm_info32;
1458205323Skib		struct shminfo32 shminfo32;
1459205323Skib	} u32;
1460205323Skib	size_t sz;
1461285057Smjg
1462205323Skib	if (uap->cmd == IPC_SET) {
1463205323Skib		if ((error = copyin(uap->buf, &u32.shmid_ds32,
1464205323Skib		    sizeof(u32.shmid_ds32))))
1465205323Skib			goto done;
1466205323Skib		freebsd32_ipcperm_in(&u32.shmid_ds32.shm_perm,
1467205323Skib		    &u.shmid_ds.shm_perm);
1468205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
1469205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
1470205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
1471205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
1472205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
1473205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
1474205323Skib		CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
1475205323Skib	}
1476285057Smjg
1477205323Skib	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
1478205323Skib	if (error)
1479205323Skib		goto done;
1480285057Smjg
1481205323Skib	/* Cases in which we need to copyout */
1482205323Skib	switch (uap->cmd) {
1483205323Skib	case IPC_INFO:
1484205323Skib		CP(u.shminfo, u32.shminfo32, shmmax);
1485205323Skib		CP(u.shminfo, u32.shminfo32, shmmin);
1486205323Skib		CP(u.shminfo, u32.shminfo32, shmmni);
1487205323Skib		CP(u.shminfo, u32.shminfo32, shmseg);
1488205323Skib		CP(u.shminfo, u32.shminfo32, shmall);
1489205323Skib		error = copyout(&u32.shminfo32, uap->buf,
1490205323Skib		    sizeof(u32.shminfo32));
1491205323Skib		break;
1492205323Skib	case SHM_INFO:
1493205323Skib		CP(u.shm_info, u32.shm_info32, used_ids);
1494205323Skib		CP(u.shm_info, u32.shm_info32, shm_rss);
1495205323Skib		CP(u.shm_info, u32.shm_info32, shm_tot);
1496205323Skib		CP(u.shm_info, u32.shm_info32, shm_swp);
1497205323Skib		CP(u.shm_info, u32.shm_info32, swap_attempts);
1498205323Skib		CP(u.shm_info, u32.shm_info32, swap_successes);
1499205323Skib		error = copyout(&u32.shm_info32, uap->buf,
1500205323Skib		    sizeof(u32.shm_info32));
1501205323Skib		break;
1502205323Skib	case SHM_STAT:
1503205323Skib	case IPC_STAT:
1504205323Skib		freebsd32_ipcperm_out(&u.shmid_ds.shm_perm,
1505205323Skib		    &u32.shmid_ds32.shm_perm);
1506205323Skib		if (u.shmid_ds.shm_segsz > INT32_MAX)
1507205323Skib			u32.shmid_ds32.shm_segsz = INT32_MAX;
1508205323Skib		else
1509205323Skib			CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
1510205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
1511205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
1512205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
1513205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
1514205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
1515205323Skib		CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
1516205323Skib		error = copyout(&u32.shmid_ds32, uap->buf,
1517205323Skib		    sizeof(u32.shmid_ds32));
1518205323Skib		break;
1519205323Skib	}
1520205323Skib
1521205323Skibdone:
1522205323Skib	if (error) {
1523205323Skib		/* Invalidate the return value */
1524205323Skib		td->td_retval[0] = -1;
1525205323Skib	}
1526205323Skib	return (error);
1527205323Skib}
1528205323Skib#endif
1529205323Skib
1530205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1531205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1532205323Skib
1533205323Skib#ifndef CP
1534194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1535205323Skib#endif
1536194910Sjhb
1537194910Sjhb#ifndef _SYS_SYSPROTO_H_
1538194910Sjhbstruct freebsd7_shmctl_args {
1539194910Sjhb	int shmid;
1540194910Sjhb	int cmd;
1541194910Sjhb	struct shmid_ds_old *buf;
1542194910Sjhb};
1543194910Sjhb#endif
1544194910Sjhbint
1545280323Skibfreebsd7_shmctl(struct thread *td, struct freebsd7_shmctl_args *uap)
1546194910Sjhb{
1547285057Smjg	int error;
1548194910Sjhb	struct shmid_ds_old old;
1549194910Sjhb	struct shmid_ds buf;
1550194910Sjhb	size_t bufsz;
1551285057Smjg
1552194910Sjhb	/*
1553194910Sjhb	 * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
1554194910Sjhb	 * Linux binaries.  If we see the call come through the FreeBSD ABI,
1555194910Sjhb	 * return an error back to the user since we do not to support this.
1556194910Sjhb	 */
1557194910Sjhb	if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
1558194910Sjhb	    uap->cmd == SHM_STAT)
1559194910Sjhb		return (EINVAL);
1560194910Sjhb
1561194910Sjhb	/* IPC_SET needs to copyin the buffer before calling kern_shmctl */
1562194910Sjhb	if (uap->cmd == IPC_SET) {
1563194910Sjhb		if ((error = copyin(uap->buf, &old, sizeof(old))))
1564194910Sjhb			goto done;
1565194910Sjhb		ipcperm_old2new(&old.shm_perm, &buf.shm_perm);
1566194910Sjhb		CP(old, buf, shm_segsz);
1567194910Sjhb		CP(old, buf, shm_lpid);
1568194910Sjhb		CP(old, buf, shm_cpid);
1569194910Sjhb		CP(old, buf, shm_nattch);
1570194910Sjhb		CP(old, buf, shm_atime);
1571194910Sjhb		CP(old, buf, shm_dtime);
1572194910Sjhb		CP(old, buf, shm_ctime);
1573194910Sjhb	}
1574285057Smjg
1575194910Sjhb	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
1576194910Sjhb	if (error)
1577194910Sjhb		goto done;
1578194910Sjhb
1579194910Sjhb	/* Cases in which we need to copyout */
1580194910Sjhb	switch (uap->cmd) {
1581194910Sjhb	case IPC_STAT:
1582194910Sjhb		ipcperm_new2old(&buf.shm_perm, &old.shm_perm);
1583194910Sjhb		if (buf.shm_segsz > INT_MAX)
1584194910Sjhb			old.shm_segsz = INT_MAX;
1585194910Sjhb		else
1586194910Sjhb			CP(buf, old, shm_segsz);
1587194910Sjhb		CP(buf, old, shm_lpid);
1588194910Sjhb		CP(buf, old, shm_cpid);
1589194910Sjhb		if (buf.shm_nattch > SHRT_MAX)
1590194910Sjhb			old.shm_nattch = SHRT_MAX;
1591194910Sjhb		else
1592194910Sjhb			CP(buf, old, shm_nattch);
1593194910Sjhb		CP(buf, old, shm_atime);
1594194910Sjhb		CP(buf, old, shm_dtime);
1595194910Sjhb		CP(buf, old, shm_ctime);
1596194910Sjhb		old.shm_internal = NULL;
1597194910Sjhb		error = copyout(&old, uap->buf, sizeof(old));
1598194910Sjhb		break;
1599194910Sjhb	}
1600194910Sjhb
1601194910Sjhbdone:
1602194910Sjhb	if (error) {
1603194910Sjhb		/* Invalidate the return value */
1604194910Sjhb		td->td_retval[0] = -1;
1605194910Sjhb	}
1606194910Sjhb	return (error);
1607194910Sjhb}
1608194910Sjhb
1609194910Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1610194910Sjhb	   COMPAT_FREEBSD7 */
1611194910Sjhb
1612194894Sjhbstatic int
161369449Salfredsysvshm_modload(struct module *module, int cmd, void *arg)
161469449Salfred{
161569449Salfred	int error = 0;
161669449Salfred
161769449Salfred	switch (cmd) {
161869449Salfred	case MOD_LOAD:
1619205323Skib		error = shminit();
1620205323Skib		if (error != 0)
1621205323Skib			shmunload();
162269449Salfred		break;
162369449Salfred	case MOD_UNLOAD:
162469449Salfred		error = shmunload();
162569449Salfred		break;
162669449Salfred	case MOD_SHUTDOWN:
162769449Salfred		break;
162869449Salfred	default:
162969449Salfred		error = EINVAL;
163069449Salfred		break;
163169449Salfred	}
163269449Salfred	return (error);
163369449Salfred}
163469449Salfred
163571038Sdesstatic moduledata_t sysvshm_mod = {
163671038Sdes	"sysvshm",
163769449Salfred	&sysvshm_modload,
163869449Salfred	NULL
163969449Salfred};
164069449Salfred
1641194832SjhbDECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
164271038SdesMODULE_VERSION(sysvshm, 1);
1643