19454b2d8SWarner Losh /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause
38a36da99SPedro F. Giffuni *
43d903220SDoug Rabson * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved.
53d903220SDoug Rabson *
63d903220SDoug Rabson * Redistribution and use in source and binary forms, with or without
73d903220SDoug Rabson * modification, are permitted provided that the following conditions
83d903220SDoug Rabson * are met:
93d903220SDoug Rabson * 1. Redistributions of source code must retain the above copyright
103d903220SDoug Rabson * notice, this list of conditions and the following disclaimer.
113d903220SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
123d903220SDoug Rabson * notice, this list of conditions and the following disclaimer in the
133d903220SDoug Rabson * documentation and/or other materials provided with the distribution.
143d903220SDoug Rabson * 3. All advertising materials mentioning features or use of this software
153d903220SDoug Rabson * must display the following acknowledgement:
163d903220SDoug Rabson * This product includes software developed by Adam Glass and Charles
173d903220SDoug Rabson * Hannum.
183d903220SDoug Rabson * 4. The names of the authors may not be used to endorse or promote products
193d903220SDoug Rabson * derived from this software without specific prior written permission.
203d903220SDoug Rabson *
213d903220SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
223d903220SDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
233d903220SDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
243d903220SDoug Rabson * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253d903220SDoug Rabson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
263d903220SDoug Rabson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
273d903220SDoug Rabson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
283d903220SDoug Rabson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
293d903220SDoug Rabson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
303d903220SDoug Rabson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
310879ca72SPedro F. Giffuni *
320879ca72SPedro F. Giffuni * $NetBSD: sysv_shm.c,v 1.39 1997/10/07 10:02:03 drochner Exp $
333d903220SDoug Rabson */
3414cedfc8SRobert Watson /*-
3514cedfc8SRobert Watson * Copyright (c) 2003-2005 McAfee, Inc.
361c2da029SRobert Watson * Copyright (c) 2016-2017 Robert N. M. Watson
3714cedfc8SRobert Watson * All rights reserved.
3814cedfc8SRobert Watson *
3914cedfc8SRobert Watson * This software was developed for the FreeBSD Project in part by McAfee
4014cedfc8SRobert Watson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
4114cedfc8SRobert Watson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
4214cedfc8SRobert Watson * program.
4314cedfc8SRobert Watson *
441c2da029SRobert Watson * Portions of this software were developed by BAE Systems, the University of
451c2da029SRobert Watson * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
461c2da029SRobert Watson * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
471c2da029SRobert Watson * Computing (TC) research program.
481c2da029SRobert Watson *
4914cedfc8SRobert Watson * Redistribution and use in source and binary forms, with or without
5014cedfc8SRobert Watson * modification, are permitted provided that the following conditions
5114cedfc8SRobert Watson * are met:
5214cedfc8SRobert Watson * 1. Redistributions of source code must retain the above copyright
5314cedfc8SRobert Watson * notice, this list of conditions and the following disclaimer.
5414cedfc8SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
5514cedfc8SRobert Watson * notice, this list of conditions and the following disclaimer in the
5614cedfc8SRobert Watson * documentation and/or other materials provided with the distribution.
5714cedfc8SRobert Watson *
5814cedfc8SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5914cedfc8SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6014cedfc8SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6114cedfc8SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
6214cedfc8SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6314cedfc8SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6414cedfc8SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6514cedfc8SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6614cedfc8SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6714cedfc8SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6814cedfc8SRobert Watson * SUCH DAMAGE.
6914cedfc8SRobert Watson */
703d903220SDoug Rabson
71255108f3SPeter Wemm #include "opt_sysvipc.h"
72511b67b7SGarrett Wollman
733d903220SDoug Rabson #include <sys/param.h>
74725db531SBruce Evans #include <sys/systm.h>
75562894f0SBrooks Davis #include <sys/abi_compat.h>
763d903220SDoug Rabson #include <sys/kernel.h>
77b648d480SJohn Baldwin #include <sys/limits.h>
78fb919e4dSMark Murray #include <sys/lock.h>
79255108f3SPeter Wemm #include <sys/sysctl.h>
803d903220SDoug Rabson #include <sys/shm.h>
813d903220SDoug Rabson #include <sys/proc.h>
823d903220SDoug Rabson #include <sys/malloc.h>
833d903220SDoug Rabson #include <sys/mman.h>
8477409fe1SPoul-Henning Kamp #include <sys/module.h>
859dceb26bSJohn Baldwin #include <sys/mutex.h>
863bcf7445SEdward Tomasz Napierala #include <sys/racct.h>
8768ba7a1dSTim J. Robbins #include <sys/resourcevar.h>
8889f6b863SAttilio Rao #include <sys/rwlock.h>
893d903220SDoug Rabson #include <sys/stat.h>
9078525ce3SAlfred Perlstein #include <sys/syscall.h>
91f130dcf2SMartin Blapp #include <sys/syscallsubr.h>
92725db531SBruce Evans #include <sys/sysent.h>
93fb919e4dSMark Murray #include <sys/sysproto.h>
94cb1f0db9SRobert Watson #include <sys/jail.h>
95aed55708SRobert Watson
96b7830259SRobert Watson #include <security/audit/audit.h>
97aed55708SRobert Watson #include <security/mac/mac_framework.h>
983d903220SDoug Rabson
993d903220SDoug Rabson #include <vm/vm.h>
100efeaf95aSDavid Greenman #include <vm/vm_param.h>
101efeaf95aSDavid Greenman #include <vm/pmap.h>
102a51f7119SJohn Dyson #include <vm/vm_object.h>
1033d903220SDoug Rabson #include <vm/vm_map.h>
1041c7c3c6aSMatthew Dillon #include <vm/vm_page.h>
105ae9b8c3aSJohn Dyson #include <vm/vm_pager.h>
1063d903220SDoug Rabson
107de5b1952SAlexander Leidinger FEATURE(sysv_shm, "System V shared memory segments support");
108de5b1952SAlexander Leidinger
109a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
11055166637SPoul-Henning Kamp
11165067cc8SKonstantin Belousov static int shm_last_free, shm_nused, shmalloced;
11245329b60SKonstantin Belousov vm_size_t shm_committed;
113921d05b9SRobert Watson static struct shmid_kernel *shmsegs;
11452a510acSJamie Gritton static unsigned shm_prison_slot;
1153d903220SDoug Rabson
1163d903220SDoug Rabson struct shmmap_state {
1173d903220SDoug Rabson vm_offset_t va;
1183d903220SDoug Rabson int shmid;
1193d903220SDoug Rabson };
1203d903220SDoug Rabson
121921d05b9SRobert Watson static void shm_deallocate_segment(struct shmid_kernel *);
12252a510acSJamie Gritton static int shm_find_segment_by_key(struct prison *, key_t);
12352a510acSJamie Gritton static struct shmid_kernel *shm_find_segment(struct prison *, int, bool);
1243db161e0SMatthew Dillon static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
12519647e76SBrooks Davis static int shmget_allocate_segment(struct thread *td, key_t key, size_t size,
12619647e76SBrooks Davis int mode);
12719647e76SBrooks Davis static int shmget_existing(struct thread *td, size_t size, int shmflg,
12819647e76SBrooks Davis int mode, int segnum);
1294d77a549SAlfred Perlstein static void shmrealloc(void);
13075d633cbSKonstantin Belousov static int shminit(void);
1314d77a549SAlfred Perlstein static int sysvshm_modload(struct module *, int, void *);
1324d77a549SAlfred Perlstein static int shmunload(void);
1335408c6dbSMateusz Guzik #ifndef SYSVSHM
1343db161e0SMatthew Dillon static void shmexit_myhook(struct vmspace *vm);
1354d77a549SAlfred Perlstein static void shmfork_myhook(struct proc *p1, struct proc *p2);
136*b7202958SKonstantin Belousov static void shmobjinfo_myhook(vm_object_t obj, key_t *key,
137*b7202958SKonstantin Belousov unsigned short *seq);
1385408c6dbSMateusz Guzik #endif
1394d77a549SAlfred Perlstein static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS);
14052a510acSJamie Gritton static void shm_remove(struct shmid_kernel *, int);
14152a510acSJamie Gritton static struct prison *shm_find_prison(struct ucred *);
14252a510acSJamie Gritton static int shm_prison_cansee(struct prison *, struct shmid_kernel *);
14352a510acSJamie Gritton static int shm_prison_check(void *, void *);
14452a510acSJamie Gritton static int shm_prison_set(void *, void *);
14552a510acSJamie Gritton static int shm_prison_get(void *, void *);
14652a510acSJamie Gritton static int shm_prison_remove(void *, void *);
14752a510acSJamie Gritton static void shm_prison_cleanup(struct prison *);
148255108f3SPeter Wemm
149255108f3SPeter Wemm /*
150028f979dSDima Dorfman * Tuneable values.
151255108f3SPeter Wemm */
152255108f3SPeter Wemm #ifndef SHMMAXPGS
153cab496e1SAndrew Turner #define SHMMAXPGS 131072ul /* Note: sysv shared memory is swap backed. */
154255108f3SPeter Wemm #endif
155255108f3SPeter Wemm #ifndef SHMMAX
156255108f3SPeter Wemm #define SHMMAX (SHMMAXPGS*PAGE_SIZE)
157255108f3SPeter Wemm #endif
158255108f3SPeter Wemm #ifndef SHMMIN
159255108f3SPeter Wemm #define SHMMIN 1
160255108f3SPeter Wemm #endif
161255108f3SPeter Wemm #ifndef SHMMNI
1621766b2e5SMatthew Dillon #define SHMMNI 192
163255108f3SPeter Wemm #endif
164255108f3SPeter Wemm #ifndef SHMSEG
1651766b2e5SMatthew Dillon #define SHMSEG 128
166255108f3SPeter Wemm #endif
167255108f3SPeter Wemm #ifndef SHMALL
168255108f3SPeter Wemm #define SHMALL (SHMMAXPGS)
169255108f3SPeter Wemm #endif
170255108f3SPeter Wemm
171255108f3SPeter Wemm struct shminfo shminfo = {
172af3b2549SHans Petter Selasky .shmmax = SHMMAX,
173af3b2549SHans Petter Selasky .shmmin = SHMMIN,
174af3b2549SHans Petter Selasky .shmmni = SHMMNI,
175af3b2549SHans Petter Selasky .shmseg = SHMSEG,
176af3b2549SHans Petter Selasky .shmall = SHMALL
177255108f3SPeter Wemm };
178255108f3SPeter Wemm
1798b03c8edSMatthew Dillon static int shm_use_phys;
18092001b94SEdward Tomasz Napierala static int shm_allow_removed = 1;
1818b03c8edSMatthew Dillon
182af3b2549SHans Petter Selasky SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RWTUN, &shminfo.shmmax, 0,
18384f85aedSChristian S.J. Peron "Maximum shared memory segment size");
184af3b2549SHans Petter Selasky SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RWTUN, &shminfo.shmmin, 0,
18584f85aedSChristian S.J. Peron "Minimum shared memory segment size");
1869baea4b4SChristian S.J. Peron SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
18784f85aedSChristian S.J. Peron "Number of shared memory identifiers");
1889baea4b4SChristian S.J. Peron SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
18984f85aedSChristian S.J. Peron "Number of segments per process");
190af3b2549SHans Petter Selasky SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RWTUN, &shminfo.shmall, 0,
19184f85aedSChristian S.J. Peron "Maximum number of pages available for shared memory");
192af3b2549SHans Petter Selasky SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RWTUN,
19384f85aedSChristian S.J. Peron &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
194af3b2549SHans Petter Selasky SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RWTUN,
19584f85aedSChristian S.J. Peron &shm_allow_removed, 0,
19684f85aedSChristian S.J. Peron "Enable/Disable attachment to attached segments marked for removal");
1970555fb35SKonstantin Belousov SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD |
1980555fb35SKonstantin Belousov CTLFLAG_MPSAFE, NULL, 0, sysctl_shmsegs, "",
1997a095112SBrooks Davis "Array of struct shmid_kernel for each potential shared memory segment");
2003d903220SDoug Rabson
2010555fb35SKonstantin Belousov static struct sx sysvshmsx;
2020555fb35SKonstantin Belousov #define SYSVSHM_LOCK() sx_xlock(&sysvshmsx)
2030555fb35SKonstantin Belousov #define SYSVSHM_UNLOCK() sx_xunlock(&sysvshmsx)
2040555fb35SKonstantin Belousov #define SYSVSHM_ASSERT_LOCKED() sx_assert(&sysvshmsx, SA_XLOCKED)
2050555fb35SKonstantin Belousov
2063d903220SDoug Rabson static int
shm_find_segment_by_key(struct prison * pr,key_t key)20752a510acSJamie Gritton shm_find_segment_by_key(struct prison *pr, key_t key)
2083d903220SDoug Rabson {
2093d903220SDoug Rabson int i;
2103d903220SDoug Rabson
211255108f3SPeter Wemm for (i = 0; i < shmalloced; i++)
212921d05b9SRobert Watson if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
21352a510acSJamie Gritton shmsegs[i].cred != NULL &&
21452a510acSJamie Gritton shmsegs[i].cred->cr_prison == pr &&
215921d05b9SRobert Watson shmsegs[i].u.shm_perm.key == key)
216b618bb96SAlfred Perlstein return (i);
217b618bb96SAlfred Perlstein return (-1);
2183d903220SDoug Rabson }
2193d903220SDoug Rabson
2200555fb35SKonstantin Belousov /*
2210555fb35SKonstantin Belousov * Finds segment either by shmid if is_shmid is true, or by segnum if
2220555fb35SKonstantin Belousov * is_shmid is false.
2230555fb35SKonstantin Belousov */
224921d05b9SRobert Watson static struct shmid_kernel *
shm_find_segment(struct prison * rpr,int arg,bool is_shmid)22552a510acSJamie Gritton shm_find_segment(struct prison *rpr, int arg, bool is_shmid)
2263d903220SDoug Rabson {
227921d05b9SRobert Watson struct shmid_kernel *shmseg;
2280555fb35SKonstantin Belousov int segnum;
2293d903220SDoug Rabson
2300555fb35SKonstantin Belousov segnum = is_shmid ? IPCID_TO_IX(arg) : arg;
231255108f3SPeter Wemm if (segnum < 0 || segnum >= shmalloced)
232b618bb96SAlfred Perlstein return (NULL);
2333d903220SDoug Rabson shmseg = &shmsegs[segnum];
234921d05b9SRobert Watson if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
2352332251cSMax Khon (!shm_allow_removed &&
236921d05b9SRobert Watson (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
23752a510acSJamie Gritton (is_shmid && shmseg->u.shm_perm.seq != IPCID_TO_SEQ(arg)) ||
2380bfd7a26SJamie Gritton shm_prison_cansee(rpr, shmseg) != 0)
239b618bb96SAlfred Perlstein return (NULL);
240b618bb96SAlfred Perlstein return (shmseg);
241491dec93SMichael Reifenberger }
242491dec93SMichael Reifenberger
2433d903220SDoug Rabson static void
shm_deallocate_segment(struct shmid_kernel * shmseg)2440555fb35SKonstantin Belousov shm_deallocate_segment(struct shmid_kernel *shmseg)
2453d903220SDoug Rabson {
24645329b60SKonstantin Belousov vm_size_t size;
2473d903220SDoug Rabson
2480555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
2490cddd8f0SMatthew Dillon
250b648d480SJohn Baldwin vm_object_deallocate(shmseg->object);
251b648d480SJohn Baldwin shmseg->object = NULL;
252b648d480SJohn Baldwin size = round_page(shmseg->u.shm_segsz);
2533d903220SDoug Rabson shm_committed -= btoc(size);
2543d903220SDoug Rabson shm_nused--;
255921d05b9SRobert Watson shmseg->u.shm_perm.mode = SHMSEG_FREE;
25614cedfc8SRobert Watson #ifdef MAC
25730d239bcSRobert Watson mac_sysvshm_cleanup(shmseg);
25814cedfc8SRobert Watson #endif
2593bcf7445SEdward Tomasz Napierala racct_sub_cred(shmseg->cred, RACCT_NSHM, 1);
2603bcf7445SEdward Tomasz Napierala racct_sub_cred(shmseg->cred, RACCT_SHMSIZE, size);
2618caddd81SEdward Tomasz Napierala crfree(shmseg->cred);
2628caddd81SEdward Tomasz Napierala shmseg->cred = NULL;
2633d903220SDoug Rabson }
2643d903220SDoug Rabson
2653d903220SDoug Rabson static int
shm_delete_mapping(struct vmspace * vm,struct shmmap_state * shmmap_s)2663db161e0SMatthew Dillon shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
2673d903220SDoug Rabson {
268921d05b9SRobert Watson struct shmid_kernel *shmseg;
2693d903220SDoug Rabson int segnum, result;
27045329b60SKonstantin Belousov vm_size_t size;
2713d903220SDoug Rabson
2720555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
2733d903220SDoug Rabson segnum = IPCID_TO_IX(shmmap_s->shmid);
2740555fb35SKonstantin Belousov KASSERT(segnum >= 0 && segnum < shmalloced,
2750555fb35SKonstantin Belousov ("segnum %d shmalloced %d", segnum, shmalloced));
2760555fb35SKonstantin Belousov
2773d903220SDoug Rabson shmseg = &shmsegs[segnum];
278b648d480SJohn Baldwin size = round_page(shmseg->u.shm_segsz);
2793db161e0SMatthew Dillon result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
2803d903220SDoug Rabson if (result != KERN_SUCCESS)
281b618bb96SAlfred Perlstein return (EINVAL);
2823d903220SDoug Rabson shmmap_s->shmid = -1;
283921d05b9SRobert Watson shmseg->u.shm_dtime = time_second;
284f63cd251SEd Schouten if (--shmseg->u.shm_nattch == 0 &&
285921d05b9SRobert Watson (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
2863d903220SDoug Rabson shm_deallocate_segment(shmseg);
2873d903220SDoug Rabson shm_last_free = segnum;
2883d903220SDoug Rabson }
289b618bb96SAlfred Perlstein return (0);
2903d903220SDoug Rabson }
2913d903220SDoug Rabson
29252a510acSJamie Gritton static void
shm_remove(struct shmid_kernel * shmseg,int segnum)29352a510acSJamie Gritton shm_remove(struct shmid_kernel *shmseg, int segnum)
29452a510acSJamie Gritton {
29552a510acSJamie Gritton
29652a510acSJamie Gritton shmseg->u.shm_perm.key = IPC_PRIVATE;
29752a510acSJamie Gritton shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
298f63cd251SEd Schouten if (shmseg->u.shm_nattch == 0) {
29952a510acSJamie Gritton shm_deallocate_segment(shmseg);
30052a510acSJamie Gritton shm_last_free = segnum;
30152a510acSJamie Gritton }
30252a510acSJamie Gritton }
30352a510acSJamie Gritton
30452a510acSJamie Gritton static struct prison *
shm_find_prison(struct ucred * cred)30552a510acSJamie Gritton shm_find_prison(struct ucred *cred)
30652a510acSJamie Gritton {
30752a510acSJamie Gritton struct prison *pr, *rpr;
30852a510acSJamie Gritton
30952a510acSJamie Gritton pr = cred->cr_prison;
31052a510acSJamie Gritton prison_lock(pr);
31152a510acSJamie Gritton rpr = osd_jail_get(pr, shm_prison_slot);
31252a510acSJamie Gritton prison_unlock(pr);
31352a510acSJamie Gritton return rpr;
31452a510acSJamie Gritton }
31552a510acSJamie Gritton
31652a510acSJamie Gritton static int
shm_prison_cansee(struct prison * rpr,struct shmid_kernel * shmseg)31752a510acSJamie Gritton shm_prison_cansee(struct prison *rpr, struct shmid_kernel *shmseg)
31852a510acSJamie Gritton {
31952a510acSJamie Gritton
32052a510acSJamie Gritton if (shmseg->cred == NULL ||
32152a510acSJamie Gritton !(rpr == shmseg->cred->cr_prison ||
32252a510acSJamie Gritton prison_ischild(rpr, shmseg->cred->cr_prison)))
32352a510acSJamie Gritton return (EINVAL);
32452a510acSJamie Gritton return (0);
32552a510acSJamie Gritton }
32652a510acSJamie Gritton
3270555fb35SKonstantin Belousov static int
kern_shmdt_locked(struct thread * td,const void * shmaddr)3280555fb35SKonstantin Belousov kern_shmdt_locked(struct thread *td, const void *shmaddr)
3293d903220SDoug Rabson {
330b40ce416SJulian Elischer struct proc *p = td->td_proc;
3313d903220SDoug Rabson struct shmmap_state *shmmap_s;
3321c2da029SRobert Watson #ifdef MAC
333e2f5418eSMateusz Guzik int error;
33414cedfc8SRobert Watson #endif
335e2f5418eSMateusz Guzik int i;
3363d903220SDoug Rabson
3370555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
33852a510acSJamie Gritton if (shm_find_prison(td->td_ucred) == NULL)
339c6f55f33SJohn Baldwin return (ENOSYS);
3408209f090SAlfred Perlstein shmmap_s = p->p_vmspace->vm_shm;
3410555fb35SKonstantin Belousov if (shmmap_s == NULL)
3420555fb35SKonstantin Belousov return (EINVAL);
3431c2da029SRobert Watson AUDIT_ARG_SVIPC_ID(shmmap_s->shmid);
344b6a4b4f9SMatthew Dillon for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
3453d903220SDoug Rabson if (shmmap_s->shmid != -1 &&
3460555fb35SKonstantin Belousov shmmap_s->va == (vm_offset_t)shmaddr) {
3473d903220SDoug Rabson break;
348b6a4b4f9SMatthew Dillon }
349b6a4b4f9SMatthew Dillon }
3500555fb35SKonstantin Belousov if (i == shminfo.shmseg)
3510555fb35SKonstantin Belousov return (EINVAL);
3521c2da029SRobert Watson #ifdef MAC
3538782eef4SKonstantin Belousov error = mac_sysvshm_check_shmdt(td->td_ucred,
3548782eef4SKonstantin Belousov &shmsegs[IPCID_TO_IX(shmmap_s->shmid)]);
355f50c4fd8SRobert Watson if (error != 0)
3560555fb35SKonstantin Belousov return (error);
35714cedfc8SRobert Watson #endif
358e2f5418eSMateusz Guzik return (shm_delete_mapping(p->p_vmspace, shmmap_s));
3593d903220SDoug Rabson }
3603d903220SDoug Rabson
361b5d5c0c9SPeter Wemm #ifndef _SYS_SYSPROTO_H_
3620555fb35SKonstantin Belousov struct shmdt_args {
363e1d7d0bbSAlfred Perlstein const void *shmaddr;
3643d903220SDoug Rabson };
365b5d5c0c9SPeter Wemm #endif
3663d903220SDoug Rabson int
sys_shmdt(struct thread * td,struct shmdt_args * uap)3670555fb35SKonstantin Belousov sys_shmdt(struct thread *td, struct shmdt_args *uap)
3680555fb35SKonstantin Belousov {
3690555fb35SKonstantin Belousov int error;
3700555fb35SKonstantin Belousov
3710555fb35SKonstantin Belousov SYSVSHM_LOCK();
3720555fb35SKonstantin Belousov error = kern_shmdt_locked(td, uap->shmaddr);
3730555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
3740555fb35SKonstantin Belousov return (error);
3750555fb35SKonstantin Belousov }
3760555fb35SKonstantin Belousov
3770555fb35SKonstantin Belousov static int
kern_shmat_locked(struct thread * td,int shmid,const void * shmaddr,int shmflg)3780555fb35SKonstantin Belousov kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
3790555fb35SKonstantin Belousov int shmflg)
3803d903220SDoug Rabson {
38152a510acSJamie Gritton struct prison *rpr;
382b40ce416SJulian Elischer struct proc *p = td->td_proc;
383921d05b9SRobert Watson struct shmid_kernel *shmseg;
3840122d251SKonstantin Belousov struct shmmap_state *shmmap_s;
3853d903220SDoug Rabson vm_offset_t attach_va;
3863d903220SDoug Rabson vm_prot_t prot;
3873d903220SDoug Rabson vm_size_t size;
388ea7e7006SKonstantin Belousov int cow, error, find_space, i, rv;
3893d903220SDoug Rabson
3901c2da029SRobert Watson AUDIT_ARG_SVIPC_ID(shmid);
3911c2da029SRobert Watson AUDIT_ARG_VALUE(shmflg);
3921c2da029SRobert Watson
3930555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
39452a510acSJamie Gritton rpr = shm_find_prison(td->td_ucred);
39552a510acSJamie Gritton if (rpr == NULL)
396c6f55f33SJohn Baldwin return (ENOSYS);
3978209f090SAlfred Perlstein shmmap_s = p->p_vmspace->vm_shm;
3983d903220SDoug Rabson if (shmmap_s == NULL) {
39945329b60SKonstantin Belousov shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state),
40045329b60SKonstantin Belousov M_SHM, M_WAITOK);
4013d903220SDoug Rabson for (i = 0; i < shminfo.shmseg; i++)
4023d903220SDoug Rabson shmmap_s[i].shmid = -1;
4030555fb35SKonstantin Belousov KASSERT(p->p_vmspace->vm_shm == NULL, ("raced"));
4042cc593fdSAlfred Perlstein p->p_vmspace->vm_shm = shmmap_s;
4053d903220SDoug Rabson }
40652a510acSJamie Gritton shmseg = shm_find_segment(rpr, shmid, true);
4070555fb35SKonstantin Belousov if (shmseg == NULL)
4080555fb35SKonstantin Belousov return (EINVAL);
409921d05b9SRobert Watson error = ipcperm(td, &shmseg->u.shm_perm,
410f130dcf2SMartin Blapp (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
4110555fb35SKonstantin Belousov if (error != 0)
4120555fb35SKonstantin Belousov return (error);
41314cedfc8SRobert Watson #ifdef MAC
41430d239bcSRobert Watson error = mac_sysvshm_check_shmat(td->td_ucred, shmseg, shmflg);
415f50c4fd8SRobert Watson if (error != 0)
4160555fb35SKonstantin Belousov return (error);
41714cedfc8SRobert Watson #endif
4183d903220SDoug Rabson for (i = 0; i < shminfo.shmseg; i++) {
4193d903220SDoug Rabson if (shmmap_s->shmid == -1)
4203d903220SDoug Rabson break;
4213d903220SDoug Rabson shmmap_s++;
4223d903220SDoug Rabson }
4230555fb35SKonstantin Belousov if (i >= shminfo.shmseg)
4240555fb35SKonstantin Belousov return (EMFILE);
425b648d480SJohn Baldwin size = round_page(shmseg->u.shm_segsz);
4263d903220SDoug Rabson prot = VM_PROT_READ;
427ea7e7006SKonstantin Belousov cow = MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL;
428f130dcf2SMartin Blapp if ((shmflg & SHM_RDONLY) == 0)
4293d903220SDoug Rabson prot |= VM_PROT_WRITE;
4300555fb35SKonstantin Belousov if (shmaddr != NULL) {
4310555fb35SKonstantin Belousov if ((shmflg & SHM_RND) != 0)
432d9c9c81cSPedro F. Giffuni attach_va = rounddown2((vm_offset_t)shmaddr, SHMLBA);
4330555fb35SKonstantin Belousov else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0)
434f130dcf2SMartin Blapp attach_va = (vm_offset_t)shmaddr;
4350555fb35SKonstantin Belousov else
4360555fb35SKonstantin Belousov return (EINVAL);
437ea7e7006SKonstantin Belousov if ((shmflg & SHM_REMAP) != 0)
438ea7e7006SKonstantin Belousov cow |= MAP_REMAP;
439ea7e7006SKonstantin Belousov find_space = VMFS_NO_SPACE;
4403d903220SDoug Rabson } else {
441028f979dSDima Dorfman /*
442028f979dSDima Dorfman * This is just a hint to vm_map_find() about where to
443028f979dSDima Dorfman * put it.
444028f979dSDima Dorfman */
44568ba7a1dSTim J. Robbins attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
44677a26248SMateusz Guzik lim_max(td, RLIMIT_DATA));
447ea7e7006SKonstantin Belousov find_space = VMFS_OPTIMAL_SPACE;
4483d903220SDoug Rabson }
449a51f7119SJohn Dyson
450b648d480SJohn Baldwin vm_object_reference(shmseg->object);
45101a8fb7dSAlan Cox rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va,
452ea7e7006SKonstantin Belousov size, 0, find_space, prot, prot, cow);
453a51f7119SJohn Dyson if (rv != KERN_SUCCESS) {
454b648d480SJohn Baldwin vm_object_deallocate(shmseg->object);
4550555fb35SKonstantin Belousov return (ENOMEM);
456a51f7119SJohn Dyson }
4570463028cSJohn Dyson
4583d903220SDoug Rabson shmmap_s->va = attach_va;
459f130dcf2SMartin Blapp shmmap_s->shmid = shmid;
460921d05b9SRobert Watson shmseg->u.shm_lpid = p->p_pid;
461921d05b9SRobert Watson shmseg->u.shm_atime = time_second;
462921d05b9SRobert Watson shmseg->u.shm_nattch++;
463b40ce416SJulian Elischer td->td_retval[0] = attach_va;
464b6a4b4f9SMatthew Dillon return (error);
4653d903220SDoug Rabson }
4663d903220SDoug Rabson
467f130dcf2SMartin Blapp int
kern_shmat(struct thread * td,int shmid,const void * shmaddr,int shmflg)4680555fb35SKonstantin Belousov kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg)
469f130dcf2SMartin Blapp {
4700555fb35SKonstantin Belousov int error;
4710555fb35SKonstantin Belousov
4720555fb35SKonstantin Belousov SYSVSHM_LOCK();
4730555fb35SKonstantin Belousov error = kern_shmat_locked(td, shmid, shmaddr, shmflg);
4740555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
4750555fb35SKonstantin Belousov return (error);
476f130dcf2SMartin Blapp }
477f130dcf2SMartin Blapp
4780555fb35SKonstantin Belousov #ifndef _SYS_SYSPROTO_H_
4790555fb35SKonstantin Belousov struct shmat_args {
480f130dcf2SMartin Blapp int shmid;
4810555fb35SKonstantin Belousov const void *shmaddr;
4820555fb35SKonstantin Belousov int shmflg;
4830555fb35SKonstantin Belousov };
4840555fb35SKonstantin Belousov #endif
4850555fb35SKonstantin Belousov int
sys_shmat(struct thread * td,struct shmat_args * uap)4860555fb35SKonstantin Belousov sys_shmat(struct thread *td, struct shmat_args *uap)
4873d903220SDoug Rabson {
4880555fb35SKonstantin Belousov
4890555fb35SKonstantin Belousov return (kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg));
4900555fb35SKonstantin Belousov }
4910555fb35SKonstantin Belousov
4920555fb35SKonstantin Belousov static int
kern_shmctl_locked(struct thread * td,int shmid,int cmd,void * buf,size_t * bufsz)4930555fb35SKonstantin Belousov kern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf,
4940555fb35SKonstantin Belousov size_t *bufsz)
4950555fb35SKonstantin Belousov {
49652a510acSJamie Gritton struct prison *rpr;
497921d05b9SRobert Watson struct shmid_kernel *shmseg;
4980555fb35SKonstantin Belousov struct shmid_ds *shmidp;
4990555fb35SKonstantin Belousov struct shm_info shm_info;
5000555fb35SKonstantin Belousov int error;
5010555fb35SKonstantin Belousov
5020555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
5033d903220SDoug Rabson
50452a510acSJamie Gritton rpr = shm_find_prison(td->td_ucred);
50552a510acSJamie Gritton if (rpr == NULL)
506c6f55f33SJohn Baldwin return (ENOSYS);
507f130dcf2SMartin Blapp
5081c2da029SRobert Watson AUDIT_ARG_SVIPC_ID(shmid);
5091c2da029SRobert Watson AUDIT_ARG_SVIPC_CMD(cmd);
5101c2da029SRobert Watson
511f130dcf2SMartin Blapp switch (cmd) {
5124f18813fSChristian S.J. Peron /*
5134f18813fSChristian S.J. Peron * It is possible that kern_shmctl is being called from the Linux ABI
5144f18813fSChristian S.J. Peron * layer, in which case, we will need to implement IPC_INFO. It should
5154f18813fSChristian S.J. Peron * be noted that other shmctl calls will be funneled through here for
5164f18813fSChristian S.J. Peron * Linix binaries as well.
5174f18813fSChristian S.J. Peron *
5184f18813fSChristian S.J. Peron * NB: The Linux ABI layer will convert this data to structure(s) more
5194f18813fSChristian S.J. Peron * consistent with the Linux ABI.
5204f18813fSChristian S.J. Peron */
521491dec93SMichael Reifenberger case IPC_INFO:
522f130dcf2SMartin Blapp memcpy(buf, &shminfo, sizeof(shminfo));
523f130dcf2SMartin Blapp if (bufsz)
524f130dcf2SMartin Blapp *bufsz = sizeof(shminfo);
525491dec93SMichael Reifenberger td->td_retval[0] = shmalloced;
5260555fb35SKonstantin Belousov return (0);
527491dec93SMichael Reifenberger case SHM_INFO: {
528491dec93SMichael Reifenberger shm_info.used_ids = shm_nused;
529491dec93SMichael Reifenberger shm_info.shm_rss = 0; /*XXX where to get from ? */
530491dec93SMichael Reifenberger shm_info.shm_tot = 0; /*XXX where to get from ? */
531491dec93SMichael Reifenberger shm_info.shm_swp = 0; /*XXX where to get from ? */
532491dec93SMichael Reifenberger shm_info.swap_attempts = 0; /*XXX where to get from ? */
533491dec93SMichael Reifenberger shm_info.swap_successes = 0; /*XXX where to get from ? */
534f130dcf2SMartin Blapp memcpy(buf, &shm_info, sizeof(shm_info));
5350555fb35SKonstantin Belousov if (bufsz != NULL)
536f130dcf2SMartin Blapp *bufsz = sizeof(shm_info);
537491dec93SMichael Reifenberger td->td_retval[0] = shmalloced;
5380555fb35SKonstantin Belousov return (0);
539491dec93SMichael Reifenberger }
540491dec93SMichael Reifenberger }
54152a510acSJamie Gritton shmseg = shm_find_segment(rpr, shmid, cmd != SHM_STAT);
5420555fb35SKonstantin Belousov if (shmseg == NULL)
5430555fb35SKonstantin Belousov return (EINVAL);
54414cedfc8SRobert Watson #ifdef MAC
54530d239bcSRobert Watson error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd);
546f50c4fd8SRobert Watson if (error != 0)
5470555fb35SKonstantin Belousov return (error);
54814cedfc8SRobert Watson #endif
549f130dcf2SMartin Blapp switch (cmd) {
550491dec93SMichael Reifenberger case SHM_STAT:
5513d903220SDoug Rabson case IPC_STAT:
55252a510acSJamie Gritton shmidp = (struct shmid_ds *)buf;
553921d05b9SRobert Watson error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
5540555fb35SKonstantin Belousov if (error != 0)
5550555fb35SKonstantin Belousov return (error);
55652a510acSJamie Gritton memcpy(shmidp, &shmseg->u, sizeof(struct shmid_ds));
55752a510acSJamie Gritton if (td->td_ucred->cr_prison != shmseg->cred->cr_prison)
55852a510acSJamie Gritton shmidp->shm_perm.key = IPC_PRIVATE;
5590555fb35SKonstantin Belousov if (bufsz != NULL)
560f130dcf2SMartin Blapp *bufsz = sizeof(struct shmid_ds);
5610555fb35SKonstantin Belousov if (cmd == SHM_STAT) {
5620555fb35SKonstantin Belousov td->td_retval[0] = IXSEQ_TO_IPCID(shmid,
5630555fb35SKonstantin Belousov shmseg->u.shm_perm);
5640555fb35SKonstantin Belousov }
5653d903220SDoug Rabson break;
5660555fb35SKonstantin Belousov case IPC_SET:
5670555fb35SKonstantin Belousov shmidp = (struct shmid_ds *)buf;
5681c2da029SRobert Watson AUDIT_ARG_SVIPC_PERM(&shmidp->shm_perm);
569921d05b9SRobert Watson error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
5700555fb35SKonstantin Belousov if (error != 0)
5710555fb35SKonstantin Belousov return (error);
5720555fb35SKonstantin Belousov shmseg->u.shm_perm.uid = shmidp->shm_perm.uid;
5730555fb35SKonstantin Belousov shmseg->u.shm_perm.gid = shmidp->shm_perm.gid;
574921d05b9SRobert Watson shmseg->u.shm_perm.mode =
575921d05b9SRobert Watson (shmseg->u.shm_perm.mode & ~ACCESSPERMS) |
5760555fb35SKonstantin Belousov (shmidp->shm_perm.mode & ACCESSPERMS);
577921d05b9SRobert Watson shmseg->u.shm_ctime = time_second;
5783d903220SDoug Rabson break;
5793d903220SDoug Rabson case IPC_RMID:
580921d05b9SRobert Watson error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
5810555fb35SKonstantin Belousov if (error != 0)
5820555fb35SKonstantin Belousov return (error);
58352a510acSJamie Gritton shm_remove(shmseg, IPCID_TO_IX(shmid));
5843d903220SDoug Rabson break;
5853d903220SDoug Rabson #if 0
5863d903220SDoug Rabson case SHM_LOCK:
5873d903220SDoug Rabson case SHM_UNLOCK:
5883d903220SDoug Rabson #endif
5893d903220SDoug Rabson default:
590b6a4b4f9SMatthew Dillon error = EINVAL;
591b6a4b4f9SMatthew Dillon break;
5923d903220SDoug Rabson }
593b6a4b4f9SMatthew Dillon return (error);
5943d903220SDoug Rabson }
5953d903220SDoug Rabson
5960555fb35SKonstantin Belousov int
kern_shmctl(struct thread * td,int shmid,int cmd,void * buf,size_t * bufsz)5970555fb35SKonstantin Belousov kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz)
5980555fb35SKonstantin Belousov {
5990555fb35SKonstantin Belousov int error;
6000555fb35SKonstantin Belousov
6010555fb35SKonstantin Belousov SYSVSHM_LOCK();
6020555fb35SKonstantin Belousov error = kern_shmctl_locked(td, shmid, cmd, buf, bufsz);
6030555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
6040555fb35SKonstantin Belousov return (error);
6050555fb35SKonstantin Belousov }
6060555fb35SKonstantin Belousov
60771361470SJohn Baldwin #ifndef _SYS_SYSPROTO_H_
60871361470SJohn Baldwin struct shmctl_args {
60971361470SJohn Baldwin int shmid;
61071361470SJohn Baldwin int cmd;
61171361470SJohn Baldwin struct shmid_ds *buf;
61271361470SJohn Baldwin };
61371361470SJohn Baldwin #endif
614f130dcf2SMartin Blapp int
sys_shmctl(struct thread * td,struct shmctl_args * uap)6150555fb35SKonstantin Belousov sys_shmctl(struct thread *td, struct shmctl_args *uap)
616f130dcf2SMartin Blapp {
617e2f5418eSMateusz Guzik int error;
618f130dcf2SMartin Blapp struct shmid_ds buf;
619f130dcf2SMartin Blapp size_t bufsz;
620f130dcf2SMartin Blapp
6214f18813fSChristian S.J. Peron /*
6224f18813fSChristian S.J. Peron * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
6234f18813fSChristian S.J. Peron * Linux binaries. If we see the call come through the FreeBSD ABI,
6244f18813fSChristian S.J. Peron * return an error back to the user since we do not to support this.
6254f18813fSChristian S.J. Peron */
6264f18813fSChristian S.J. Peron if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
6274f18813fSChristian S.J. Peron uap->cmd == SHM_STAT)
6284f18813fSChristian S.J. Peron return (EINVAL);
6294f18813fSChristian S.J. Peron
630f130dcf2SMartin Blapp /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
631f130dcf2SMartin Blapp if (uap->cmd == IPC_SET) {
632f130dcf2SMartin Blapp if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
633f130dcf2SMartin Blapp goto done;
634f130dcf2SMartin Blapp }
635f130dcf2SMartin Blapp
6362332251cSMax Khon error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
637f130dcf2SMartin Blapp if (error)
638f130dcf2SMartin Blapp goto done;
639f130dcf2SMartin Blapp
640f130dcf2SMartin Blapp /* Cases in which we need to copyout */
641f130dcf2SMartin Blapp switch (uap->cmd) {
642f130dcf2SMartin Blapp case IPC_STAT:
643f130dcf2SMartin Blapp error = copyout(&buf, uap->buf, bufsz);
644f130dcf2SMartin Blapp break;
645f130dcf2SMartin Blapp }
646f130dcf2SMartin Blapp
647f130dcf2SMartin Blapp done:
648f130dcf2SMartin Blapp if (error) {
649f130dcf2SMartin Blapp /* Invalidate the return value */
650f130dcf2SMartin Blapp td->td_retval[0] = -1;
651f130dcf2SMartin Blapp }
652f130dcf2SMartin Blapp return (error);
653f130dcf2SMartin Blapp }
654f130dcf2SMartin Blapp
6553d903220SDoug Rabson static int
shmget_existing(struct thread * td,size_t size,int shmflg,int mode,int segnum)65619647e76SBrooks Davis shmget_existing(struct thread *td, size_t size, int shmflg, int mode,
6570555fb35SKonstantin Belousov int segnum)
6583d903220SDoug Rabson {
659921d05b9SRobert Watson struct shmid_kernel *shmseg;
660d8d2f476SOlivier Houchard #ifdef MAC
6613d903220SDoug Rabson int error;
662d8d2f476SOlivier Houchard #endif
6633d903220SDoug Rabson
6640555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
6650555fb35SKonstantin Belousov KASSERT(segnum >= 0 && segnum < shmalloced,
6660555fb35SKonstantin Belousov ("segnum %d shmalloced %d", segnum, shmalloced));
6673d903220SDoug Rabson shmseg = &shmsegs[segnum];
66819647e76SBrooks Davis if ((shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
669b618bb96SAlfred Perlstein return (EEXIST);
67014cedfc8SRobert Watson #ifdef MAC
67119647e76SBrooks Davis error = mac_sysvshm_check_shmget(td->td_ucred, shmseg, shmflg);
672f50c4fd8SRobert Watson if (error != 0)
6737723d5edSRobert Watson return (error);
67414cedfc8SRobert Watson #endif
67519647e76SBrooks Davis if (size != 0 && size > shmseg->u.shm_segsz)
676b618bb96SAlfred Perlstein return (EINVAL);
677921d05b9SRobert Watson td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
678b618bb96SAlfred Perlstein return (0);
6793d903220SDoug Rabson }
6803d903220SDoug Rabson
6813d903220SDoug Rabson static int
shmget_allocate_segment(struct thread * td,key_t key,size_t size,int mode)68219647e76SBrooks Davis shmget_allocate_segment(struct thread *td, key_t key, size_t size, int mode)
6833d903220SDoug Rabson {
684a854ed98SJohn Baldwin struct ucred *cred = td->td_ucred;
685921d05b9SRobert Watson struct shmid_kernel *shmseg;
6860049f8b2SAlan Cox vm_object_t shm_object;
6870555fb35SKonstantin Belousov int i, segnum;
6883d903220SDoug Rabson
6890555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
6900cddd8f0SMatthew Dillon
69119647e76SBrooks Davis if (size < shminfo.shmmin || size > shminfo.shmmax)
692b618bb96SAlfred Perlstein return (EINVAL);
693028f979dSDima Dorfman if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
694b618bb96SAlfred Perlstein return (ENOSPC);
69519647e76SBrooks Davis size = round_page(size);
6963d903220SDoug Rabson if (shm_committed + btoc(size) > shminfo.shmall)
697b618bb96SAlfred Perlstein return (ENOMEM);
6983d903220SDoug Rabson if (shm_last_free < 0) {
699028f979dSDima Dorfman shmrealloc(); /* Maybe expand the shmsegs[] array. */
700255108f3SPeter Wemm for (i = 0; i < shmalloced; i++)
701921d05b9SRobert Watson if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
7023d903220SDoug Rabson break;
703255108f3SPeter Wemm if (i == shmalloced)
704b618bb96SAlfred Perlstein return (ENOSPC);
7053d903220SDoug Rabson segnum = i;
7063d903220SDoug Rabson } else {
7073d903220SDoug Rabson segnum = shm_last_free;
7083d903220SDoug Rabson shm_last_free = -1;
7093d903220SDoug Rabson }
7100555fb35SKonstantin Belousov KASSERT(segnum >= 0 && segnum < shmalloced,
7110555fb35SKonstantin Belousov ("segnum %d shmalloced %d", segnum, shmalloced));
7123d903220SDoug Rabson shmseg = &shmsegs[segnum];
713afcc55f3SEdward Tomasz Napierala #ifdef RACCT
7144b5c9cf6SEdward Tomasz Napierala if (racct_enable) {
7153bcf7445SEdward Tomasz Napierala PROC_LOCK(td->td_proc);
7163bcf7445SEdward Tomasz Napierala if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
7173bcf7445SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc);
7183bcf7445SEdward Tomasz Napierala return (ENOSPC);
7193bcf7445SEdward Tomasz Napierala }
7203bcf7445SEdward Tomasz Napierala if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) {
7213bcf7445SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_NSHM, 1);
7223bcf7445SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc);
7233bcf7445SEdward Tomasz Napierala return (ENOMEM);
7243bcf7445SEdward Tomasz Napierala }
7253bcf7445SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc);
7264b5c9cf6SEdward Tomasz Napierala }
727afcc55f3SEdward Tomasz Napierala #endif
728a51f7119SJohn Dyson
729ae9b8c3aSJohn Dyson /*
730ae9b8c3aSJohn Dyson * We make sure that we have allocated a pager before we need
731ae9b8c3aSJohn Dyson * to.
732ae9b8c3aSJohn Dyson */
7333364c323SKonstantin Belousov shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP,
7343364c323SKonstantin Belousov 0, size, VM_PROT_DEFAULT, 0, cred);
7353bcf7445SEdward Tomasz Napierala if (shm_object == NULL) {
736afcc55f3SEdward Tomasz Napierala #ifdef RACCT
7374b5c9cf6SEdward Tomasz Napierala if (racct_enable) {
7383bcf7445SEdward Tomasz Napierala PROC_LOCK(td->td_proc);
7393bcf7445SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_NSHM, 1);
7403bcf7445SEdward Tomasz Napierala racct_sub(td->td_proc, RACCT_SHMSIZE, size);
7413bcf7445SEdward Tomasz Napierala PROC_UNLOCK(td->td_proc);
7424b5c9cf6SEdward Tomasz Napierala }
743afcc55f3SEdward Tomasz Napierala #endif
7443364c323SKonstantin Belousov return (ENOMEM);
7453bcf7445SEdward Tomasz Napierala }
746cbd8ec09SJohn Dyson
747f186252eSKonstantin Belousov VM_OBJECT_WLOCK(shm_object);
748f186252eSKonstantin Belousov vm_object_set_flag(shm_object, OBJ_SYSVSHM);
749f186252eSKonstantin Belousov VM_OBJECT_WUNLOCK(shm_object);
750f186252eSKonstantin Belousov
751b648d480SJohn Baldwin shmseg->object = shm_object;
752921d05b9SRobert Watson shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid;
753921d05b9SRobert Watson shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid;
7540555fb35SKonstantin Belousov shmseg->u.shm_perm.mode = (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
75519647e76SBrooks Davis shmseg->u.shm_perm.key = key;
7560555fb35SKonstantin Belousov shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff;
757b1fb5f9cSEdward Tomasz Napierala shmseg->cred = crhold(cred);
75819647e76SBrooks Davis shmseg->u.shm_segsz = size;
759921d05b9SRobert Watson shmseg->u.shm_cpid = td->td_proc->p_pid;
760921d05b9SRobert Watson shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0;
761921d05b9SRobert Watson shmseg->u.shm_atime = shmseg->u.shm_dtime = 0;
76214cedfc8SRobert Watson #ifdef MAC
76330d239bcSRobert Watson mac_sysvshm_create(cred, shmseg);
76414cedfc8SRobert Watson #endif
765921d05b9SRobert Watson shmseg->u.shm_ctime = time_second;
7663d903220SDoug Rabson shm_committed += btoc(size);
7673d903220SDoug Rabson shm_nused++;
7680555fb35SKonstantin Belousov td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
7690555fb35SKonstantin Belousov
770b618bb96SAlfred Perlstein return (0);
7713d903220SDoug Rabson }
7723d903220SDoug Rabson
77371361470SJohn Baldwin #ifndef _SYS_SYSPROTO_H_
77471361470SJohn Baldwin struct shmget_args {
77571361470SJohn Baldwin key_t key;
77671361470SJohn Baldwin size_t size;
77771361470SJohn Baldwin int shmflg;
77871361470SJohn Baldwin };
77971361470SJohn Baldwin #endif
7803d903220SDoug Rabson int
sys_shmget(struct thread * td,struct shmget_args * uap)7810555fb35SKonstantin Belousov sys_shmget(struct thread *td, struct shmget_args *uap)
7823d903220SDoug Rabson {
783b6a4b4f9SMatthew Dillon int segnum, mode;
784b6a4b4f9SMatthew Dillon int error;
7853d903220SDoug Rabson
78652a510acSJamie Gritton if (shm_find_prison(td->td_ucred) == NULL)
787c6f55f33SJohn Baldwin return (ENOSYS);
7883d903220SDoug Rabson mode = uap->shmflg & ACCESSPERMS;
7890555fb35SKonstantin Belousov SYSVSHM_LOCK();
7900555fb35SKonstantin Belousov if (uap->key == IPC_PRIVATE) {
79119647e76SBrooks Davis error = shmget_allocate_segment(td, uap->key, uap->size, mode);
7920555fb35SKonstantin Belousov } else {
79352a510acSJamie Gritton segnum = shm_find_segment_by_key(td->td_ucred->cr_prison,
79452a510acSJamie Gritton uap->key);
7950555fb35SKonstantin Belousov if (segnum >= 0)
79619647e76SBrooks Davis error = shmget_existing(td, uap->size, uap->shmflg,
79719647e76SBrooks Davis mode, segnum);
7980555fb35SKonstantin Belousov else if ((uap->shmflg & IPC_CREAT) == 0)
7990555fb35SKonstantin Belousov error = ENOENT;
8000555fb35SKonstantin Belousov else
80119647e76SBrooks Davis error = shmget_allocate_segment(td, uap->key,
80219647e76SBrooks Davis uap->size, mode);
8030555fb35SKonstantin Belousov }
8040555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
805b6a4b4f9SMatthew Dillon return (error);
8063d903220SDoug Rabson }
8073d903220SDoug Rabson
8085408c6dbSMateusz Guzik #ifdef SYSVSHM
8095408c6dbSMateusz Guzik void
shmfork(struct proc * p1,struct proc * p2)8105408c6dbSMateusz Guzik shmfork(struct proc *p1, struct proc *p2)
8115408c6dbSMateusz Guzik #else
81278525ce3SAlfred Perlstein static void
8130555fb35SKonstantin Belousov shmfork_myhook(struct proc *p1, struct proc *p2)
8145408c6dbSMateusz Guzik #endif
8153d903220SDoug Rabson {
8163d903220SDoug Rabson struct shmmap_state *shmmap_s;
8173d903220SDoug Rabson size_t size;
8183d903220SDoug Rabson int i;
8193d903220SDoug Rabson
8200555fb35SKonstantin Belousov SYSVSHM_LOCK();
8213d903220SDoug Rabson size = shminfo.shmseg * sizeof(struct shmmap_state);
822a163d034SWarner Losh shmmap_s = malloc(size, M_SHM, M_WAITOK);
8232cc593fdSAlfred Perlstein bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
8242cc593fdSAlfred Perlstein p2->p_vmspace->vm_shm = shmmap_s;
8250555fb35SKonstantin Belousov for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
8260555fb35SKonstantin Belousov if (shmmap_s->shmid != -1) {
8270555fb35SKonstantin Belousov KASSERT(IPCID_TO_IX(shmmap_s->shmid) >= 0 &&
8280555fb35SKonstantin Belousov IPCID_TO_IX(shmmap_s->shmid) < shmalloced,
8290555fb35SKonstantin Belousov ("segnum %d shmalloced %d",
8300555fb35SKonstantin Belousov IPCID_TO_IX(shmmap_s->shmid), shmalloced));
831921d05b9SRobert Watson shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
8320555fb35SKonstantin Belousov }
8330555fb35SKonstantin Belousov }
8340555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
8353d903220SDoug Rabson }
8363d903220SDoug Rabson
8375408c6dbSMateusz Guzik #ifdef SYSVSHM
8385408c6dbSMateusz Guzik void
shmexit(struct vmspace * vm)8395408c6dbSMateusz Guzik shmexit(struct vmspace *vm)
8405408c6dbSMateusz Guzik #else
84178525ce3SAlfred Perlstein static void
8423db161e0SMatthew Dillon shmexit_myhook(struct vmspace *vm)
8435408c6dbSMateusz Guzik #endif
8443d903220SDoug Rabson {
8453db161e0SMatthew Dillon struct shmmap_state *base, *shm;
8463d903220SDoug Rabson int i;
8473d903220SDoug Rabson
8480555fb35SKonstantin Belousov base = vm->vm_shm;
8490555fb35SKonstantin Belousov if (base != NULL) {
8503db161e0SMatthew Dillon vm->vm_shm = NULL;
8510555fb35SKonstantin Belousov SYSVSHM_LOCK();
8523db161e0SMatthew Dillon for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
8533db161e0SMatthew Dillon if (shm->shmid != -1)
8543db161e0SMatthew Dillon shm_delete_mapping(vm, shm);
8553db161e0SMatthew Dillon }
8560555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
8573db161e0SMatthew Dillon free(base, M_SHM);
8583db161e0SMatthew Dillon }
8593d903220SDoug Rabson }
8603d903220SDoug Rabson
861*b7202958SKonstantin Belousov #ifdef SYSVSHM
862*b7202958SKonstantin Belousov void
shmobjinfo(vm_object_t obj,key_t * key,unsigned short * seq)863*b7202958SKonstantin Belousov shmobjinfo(vm_object_t obj, key_t *key, unsigned short *seq)
864*b7202958SKonstantin Belousov #else
865*b7202958SKonstantin Belousov static void
866*b7202958SKonstantin Belousov shmobjinfo_myhook(vm_object_t obj, key_t *key, unsigned short *seq)
867*b7202958SKonstantin Belousov #endif
868*b7202958SKonstantin Belousov {
869*b7202958SKonstantin Belousov int i;
870*b7202958SKonstantin Belousov
871*b7202958SKonstantin Belousov *key = 0; /* For statically compiled-in sysv_shm.c */
872*b7202958SKonstantin Belousov *seq = 0;
873*b7202958SKonstantin Belousov SYSVSHM_LOCK();
874*b7202958SKonstantin Belousov for (i = 0; i < shmalloced; i++) {
875*b7202958SKonstantin Belousov if (shmsegs[i].object == obj) {
876*b7202958SKonstantin Belousov *key = shmsegs[i].u.shm_perm.key;
877*b7202958SKonstantin Belousov *seq = shmsegs[i].u.shm_perm.seq;
878*b7202958SKonstantin Belousov break;
879*b7202958SKonstantin Belousov }
880*b7202958SKonstantin Belousov }
881*b7202958SKonstantin Belousov SYSVSHM_UNLOCK();
882*b7202958SKonstantin Belousov }
883*b7202958SKonstantin Belousov
884255108f3SPeter Wemm static void
shmrealloc(void)885255108f3SPeter Wemm shmrealloc(void)
886255108f3SPeter Wemm {
887921d05b9SRobert Watson struct shmid_kernel *newsegs;
8880555fb35SKonstantin Belousov int i;
8890555fb35SKonstantin Belousov
8900555fb35SKonstantin Belousov SYSVSHM_ASSERT_LOCKED();
891255108f3SPeter Wemm
892255108f3SPeter Wemm if (shmalloced >= shminfo.shmmni)
893255108f3SPeter Wemm return;
894255108f3SPeter Wemm
8950fd25723SBrooks Davis newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM,
8960fd25723SBrooks Davis M_WAITOK | M_ZERO);
897255108f3SPeter Wemm for (i = 0; i < shmalloced; i++)
898255108f3SPeter Wemm bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
899255108f3SPeter Wemm for (; i < shminfo.shmmni; i++) {
9000be3a191SMateusz Guzik newsegs[i].u.shm_perm.mode = SHMSEG_FREE;
9010be3a191SMateusz Guzik newsegs[i].u.shm_perm.seq = 0;
90214cedfc8SRobert Watson #ifdef MAC
9030be3a191SMateusz Guzik mac_sysvshm_init(&newsegs[i]);
90414cedfc8SRobert Watson #endif
905255108f3SPeter Wemm }
906255108f3SPeter Wemm free(shmsegs, M_SHM);
907255108f3SPeter Wemm shmsegs = newsegs;
908255108f3SPeter Wemm shmalloced = shminfo.shmmni;
909255108f3SPeter Wemm }
910255108f3SPeter Wemm
91175d633cbSKonstantin Belousov static struct syscall_helper_data shm_syscalls[] = {
91275d633cbSKonstantin Belousov SYSCALL_INIT_HELPER(shmat),
91375d633cbSKonstantin Belousov SYSCALL_INIT_HELPER(shmctl),
91475d633cbSKonstantin Belousov SYSCALL_INIT_HELPER(shmdt),
91575d633cbSKonstantin Belousov SYSCALL_INIT_HELPER(shmget),
91675d633cbSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
91775d633cbSKonstantin Belousov defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
9188451d0ddSKip Macy SYSCALL_INIT_HELPER_COMPAT(freebsd7_shmctl),
91975d633cbSKonstantin Belousov #endif
92075d633cbSKonstantin Belousov #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
92175d633cbSKonstantin Belousov SYSCALL_INIT_HELPER(shmsys),
92275d633cbSKonstantin Belousov #endif
92375d633cbSKonstantin Belousov SYSCALL_INIT_LAST
92475d633cbSKonstantin Belousov };
92575d633cbSKonstantin Belousov
92675d633cbSKonstantin Belousov #ifdef COMPAT_FREEBSD32
92775d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32.h>
92875d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32_ipc.h>
92975d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32_proto.h>
93075d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32_signal.h>
93175d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32_syscall.h>
93275d633cbSKonstantin Belousov #include <compat/freebsd32/freebsd32_util.h>
93375d633cbSKonstantin Belousov
93475d633cbSKonstantin Belousov static struct syscall_helper_data shm32_syscalls[] = {
9358451d0ddSKip Macy SYSCALL32_INIT_HELPER_COMPAT(shmat),
9368451d0ddSKip Macy SYSCALL32_INIT_HELPER_COMPAT(shmdt),
9378451d0ddSKip Macy SYSCALL32_INIT_HELPER_COMPAT(shmget),
93875d633cbSKonstantin Belousov SYSCALL32_INIT_HELPER(freebsd32_shmsys),
93975d633cbSKonstantin Belousov SYSCALL32_INIT_HELPER(freebsd32_shmctl),
94075d633cbSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
94175d633cbSKonstantin Belousov defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
94275d633cbSKonstantin Belousov SYSCALL32_INIT_HELPER(freebsd7_freebsd32_shmctl),
94375d633cbSKonstantin Belousov #endif
94475d633cbSKonstantin Belousov SYSCALL_INIT_LAST
94575d633cbSKonstantin Belousov };
94675d633cbSKonstantin Belousov #endif
94775d633cbSKonstantin Belousov
94875d633cbSKonstantin Belousov static int
shminit(void)9490555fb35SKonstantin Belousov shminit(void)
9503d903220SDoug Rabson {
95152a510acSJamie Gritton struct prison *pr;
952aa90aec2SConrad Meyer void **rsv;
95375d633cbSKonstantin Belousov int i, error;
95452a510acSJamie Gritton osd_method_t methods[PR_MAXMETHOD] = {
95552a510acSJamie Gritton [PR_METHOD_CHECK] = shm_prison_check,
95652a510acSJamie Gritton [PR_METHOD_SET] = shm_prison_set,
95752a510acSJamie Gritton [PR_METHOD_GET] = shm_prison_get,
95852a510acSJamie Gritton [PR_METHOD_REMOVE] = shm_prison_remove,
95952a510acSJamie Gritton };
960255108f3SPeter Wemm
9614d9d1e82SRuslan Ermilov #ifndef BURN_BRIDGES
9624d9d1e82SRuslan Ermilov if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0)
9634d9d1e82SRuslan Ermilov printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n");
9644d9d1e82SRuslan Ermilov #endif
965af3b2549SHans Petter Selasky if (shminfo.shmmax == SHMMAX) {
9664d9d1e82SRuslan Ermilov /* Initialize shmmax dealing with possible overflow. */
967af3b2549SHans Petter Selasky for (i = PAGE_SIZE; i != 0; i--) {
968a4c24c66SJohn Baldwin shminfo.shmmax = shminfo.shmall * i;
969af3b2549SHans Petter Selasky if ((shminfo.shmmax / shminfo.shmall) == (u_long)i)
9705015c68aSAlfred Perlstein break;
9715015c68aSAlfred Perlstein }
97212075c09SPawel Jakub Dawidek }
973255108f3SPeter Wemm shmalloced = shminfo.shmmni;
9740fd25723SBrooks Davis shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM,
9750fd25723SBrooks Davis M_WAITOK|M_ZERO);
976255108f3SPeter Wemm for (i = 0; i < shmalloced; i++) {
977921d05b9SRobert Watson shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
978921d05b9SRobert Watson shmsegs[i].u.shm_perm.seq = 0;
97914cedfc8SRobert Watson #ifdef MAC
98030d239bcSRobert Watson mac_sysvshm_init(&shmsegs[i]);
98114cedfc8SRobert Watson #endif
9823d903220SDoug Rabson }
9833d903220SDoug Rabson shm_last_free = 0;
9843d903220SDoug Rabson shm_nused = 0;
9853d903220SDoug Rabson shm_committed = 0;
9860555fb35SKonstantin Belousov sx_init(&sysvshmsx, "sysvshmsx");
9875408c6dbSMateusz Guzik #ifndef SYSVSHM
98878525ce3SAlfred Perlstein shmexit_hook = &shmexit_myhook;
98978525ce3SAlfred Perlstein shmfork_hook = &shmfork_myhook;
990*b7202958SKonstantin Belousov shmobjinfo_hook = &shmobjinfo_myhook;
9915408c6dbSMateusz Guzik #endif
99275d633cbSKonstantin Belousov
99352a510acSJamie Gritton /* Set current prisons according to their allow.sysvipc. */
99452a510acSJamie Gritton shm_prison_slot = osd_jail_register(NULL, methods);
99552a510acSJamie Gritton rsv = osd_reserve(shm_prison_slot);
99652a510acSJamie Gritton prison_lock(&prison0);
99752a510acSJamie Gritton (void)osd_jail_set_reserved(&prison0, shm_prison_slot, rsv, &prison0);
99852a510acSJamie Gritton prison_unlock(&prison0);
99952a510acSJamie Gritton rsv = NULL;
100052a510acSJamie Gritton sx_slock(&allprison_lock);
100152a510acSJamie Gritton TAILQ_FOREACH(pr, &allprison, pr_list) {
100252a510acSJamie Gritton if (rsv == NULL)
100352a510acSJamie Gritton rsv = osd_reserve(shm_prison_slot);
100452a510acSJamie Gritton prison_lock(pr);
1005f7496dcaSJamie Gritton if (pr->pr_allow & PR_ALLOW_SYSVIPC) {
100652a510acSJamie Gritton (void)osd_jail_set_reserved(pr, shm_prison_slot, rsv,
100752a510acSJamie Gritton &prison0);
100852a510acSJamie Gritton rsv = NULL;
100952a510acSJamie Gritton }
101052a510acSJamie Gritton prison_unlock(pr);
101152a510acSJamie Gritton }
101252a510acSJamie Gritton if (rsv != NULL)
101352a510acSJamie Gritton osd_free_reserved(rsv);
101452a510acSJamie Gritton sx_sunlock(&allprison_lock);
101552a510acSJamie Gritton
1016e015b1abSMateusz Guzik error = syscall_helper_register(shm_syscalls, SY_THR_STATIC_KLD);
101775d633cbSKonstantin Belousov if (error != 0)
101875d633cbSKonstantin Belousov return (error);
101975d633cbSKonstantin Belousov #ifdef COMPAT_FREEBSD32
1020e015b1abSMateusz Guzik error = syscall32_helper_register(shm32_syscalls, SY_THR_STATIC_KLD);
102175d633cbSKonstantin Belousov if (error != 0)
102275d633cbSKonstantin Belousov return (error);
102375d633cbSKonstantin Belousov #endif
102475d633cbSKonstantin Belousov return (0);
10253d903220SDoug Rabson }
102678525ce3SAlfred Perlstein
102778525ce3SAlfred Perlstein static int
shmunload(void)10280555fb35SKonstantin Belousov shmunload(void)
102978525ce3SAlfred Perlstein {
103014cedfc8SRobert Watson int i;
103178525ce3SAlfred Perlstein
103278525ce3SAlfred Perlstein if (shm_nused > 0)
103378525ce3SAlfred Perlstein return (EBUSY);
103478525ce3SAlfred Perlstein
103575d633cbSKonstantin Belousov #ifdef COMPAT_FREEBSD32
103675d633cbSKonstantin Belousov syscall32_helper_unregister(shm32_syscalls);
103775d633cbSKonstantin Belousov #endif
103875d633cbSKonstantin Belousov syscall_helper_unregister(shm_syscalls);
103952a510acSJamie Gritton if (shm_prison_slot != 0)
104052a510acSJamie Gritton osd_jail_deregister(shm_prison_slot);
104175d633cbSKonstantin Belousov
10420d9d996dSKonstantin Belousov for (i = 0; i < shmalloced; i++) {
104314cedfc8SRobert Watson #ifdef MAC
104430d239bcSRobert Watson mac_sysvshm_destroy(&shmsegs[i]);
104514cedfc8SRobert Watson #endif
10460d9d996dSKonstantin Belousov /*
10470d9d996dSKonstantin Belousov * Objects might be still mapped into the processes
10480d9d996dSKonstantin Belousov * address spaces. Actual free would happen on the
10490d9d996dSKonstantin Belousov * last mapping destruction.
10500d9d996dSKonstantin Belousov */
10510d9d996dSKonstantin Belousov if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE)
10520d9d996dSKonstantin Belousov vm_object_deallocate(shmsegs[i].object);
10530d9d996dSKonstantin Belousov }
105478525ce3SAlfred Perlstein free(shmsegs, M_SHM);
10555408c6dbSMateusz Guzik #ifndef SYSVSHM
105678525ce3SAlfred Perlstein shmexit_hook = NULL;
105778525ce3SAlfred Perlstein shmfork_hook = NULL;
1058*b7202958SKonstantin Belousov shmobjinfo_hook = NULL;
10595408c6dbSMateusz Guzik #endif
10600555fb35SKonstantin Belousov sx_destroy(&sysvshmsx);
106178525ce3SAlfred Perlstein return (0);
106278525ce3SAlfred Perlstein }
106378525ce3SAlfred Perlstein
106478525ce3SAlfred Perlstein static int
sysctl_shmsegs(SYSCTL_HANDLER_ARGS)1065a723c4e1SDima Dorfman sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
1066a723c4e1SDima Dorfman {
10675579267bSJamie Gritton struct shmid_kernel tshmseg;
10680fd25723SBrooks Davis #ifdef COMPAT_FREEBSD32
10690fd25723SBrooks Davis struct shmid_kernel32 tshmseg32;
10700fd25723SBrooks Davis #endif
10715579267bSJamie Gritton struct prison *pr, *rpr;
10720fd25723SBrooks Davis void *outaddr;
10730fd25723SBrooks Davis size_t outsize;
107452a510acSJamie Gritton int error, i;
1075a723c4e1SDima Dorfman
10760555fb35SKonstantin Belousov SYSVSHM_LOCK();
10775579267bSJamie Gritton pr = req->td->td_ucred->cr_prison;
107852a510acSJamie Gritton rpr = shm_find_prison(req->td->td_ucred);
10795579267bSJamie Gritton error = 0;
108052a510acSJamie Gritton for (i = 0; i < shmalloced; i++) {
10815579267bSJamie Gritton if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
108252a510acSJamie Gritton rpr == NULL || shm_prison_cansee(rpr, &shmsegs[i]) != 0) {
10835579267bSJamie Gritton bzero(&tshmseg, sizeof(tshmseg));
10845579267bSJamie Gritton tshmseg.u.shm_perm.mode = SHMSEG_FREE;
10855579267bSJamie Gritton } else {
10865579267bSJamie Gritton tshmseg = shmsegs[i];
10875579267bSJamie Gritton if (tshmseg.cred->cr_prison != pr)
10885579267bSJamie Gritton tshmseg.u.shm_perm.key = IPC_PRIVATE;
108952a510acSJamie Gritton }
10900fd25723SBrooks Davis #ifdef COMPAT_FREEBSD32
10910fd25723SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) {
10920fd25723SBrooks Davis bzero(&tshmseg32, sizeof(tshmseg32));
10930fd25723SBrooks Davis freebsd32_ipcperm_out(&tshmseg.u.shm_perm,
10940fd25723SBrooks Davis &tshmseg32.u.shm_perm);
10950fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_segsz);
10960fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_lpid);
10970fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_cpid);
10980fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_nattch);
10990fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_atime);
11000fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_dtime);
11010fd25723SBrooks Davis CP(tshmseg, tshmseg32, u.shm_ctime);
11020fd25723SBrooks Davis /* Don't copy object, label, or cred */
11030fd25723SBrooks Davis outaddr = &tshmseg32;
11040fd25723SBrooks Davis outsize = sizeof(tshmseg32);
11050fd25723SBrooks Davis } else
11060fd25723SBrooks Davis #endif
11070fd25723SBrooks Davis {
11080fd25723SBrooks Davis tshmseg.object = NULL;
11090fd25723SBrooks Davis tshmseg.label = NULL;
11100fd25723SBrooks Davis tshmseg.cred = NULL;
11110fd25723SBrooks Davis outaddr = &tshmseg;
11120fd25723SBrooks Davis outsize = sizeof(tshmseg);
11130fd25723SBrooks Davis }
11140fd25723SBrooks Davis error = SYSCTL_OUT(req, outaddr, outsize);
11155579267bSJamie Gritton if (error != 0)
11165579267bSJamie Gritton break;
111752a510acSJamie Gritton }
11180555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
11190555fb35SKonstantin Belousov return (error);
1120a723c4e1SDima Dorfman }
1121a723c4e1SDima Dorfman
112287a15652SKonstantin Belousov int
kern_get_shmsegs(struct thread * td,struct shmid_kernel ** res,size_t * sz)112387a15652SKonstantin Belousov kern_get_shmsegs(struct thread *td, struct shmid_kernel **res, size_t *sz)
112487a15652SKonstantin Belousov {
112587a15652SKonstantin Belousov struct shmid_kernel *pshmseg;
112687a15652SKonstantin Belousov struct prison *pr, *rpr;
112787a15652SKonstantin Belousov int i;
112887a15652SKonstantin Belousov
112987a15652SKonstantin Belousov SYSVSHM_LOCK();
113087a15652SKonstantin Belousov *sz = shmalloced;
113187a15652SKonstantin Belousov if (res == NULL)
113287a15652SKonstantin Belousov goto out;
113387a15652SKonstantin Belousov
113487a15652SKonstantin Belousov pr = td->td_ucred->cr_prison;
113587a15652SKonstantin Belousov rpr = shm_find_prison(td->td_ucred);
113687a15652SKonstantin Belousov *res = malloc(sizeof(struct shmid_kernel) * shmalloced, M_TEMP,
113787a15652SKonstantin Belousov M_WAITOK);
113887a15652SKonstantin Belousov for (i = 0; i < shmalloced; i++) {
113987a15652SKonstantin Belousov pshmseg = &(*res)[i];
114087a15652SKonstantin Belousov if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
114187a15652SKonstantin Belousov rpr == NULL || shm_prison_cansee(rpr, &shmsegs[i]) != 0) {
114287a15652SKonstantin Belousov bzero(pshmseg, sizeof(*pshmseg));
114387a15652SKonstantin Belousov pshmseg->u.shm_perm.mode = SHMSEG_FREE;
114487a15652SKonstantin Belousov } else {
114587a15652SKonstantin Belousov *pshmseg = shmsegs[i];
114687a15652SKonstantin Belousov if (pshmseg->cred->cr_prison != pr)
114787a15652SKonstantin Belousov pshmseg->u.shm_perm.key = IPC_PRIVATE;
114887a15652SKonstantin Belousov }
114987a15652SKonstantin Belousov pshmseg->object = NULL;
115087a15652SKonstantin Belousov pshmseg->label = NULL;
115187a15652SKonstantin Belousov pshmseg->cred = NULL;
115287a15652SKonstantin Belousov }
115387a15652SKonstantin Belousov out:
115487a15652SKonstantin Belousov SYSVSHM_UNLOCK();
115587a15652SKonstantin Belousov return (0);
115687a15652SKonstantin Belousov }
115787a15652SKonstantin Belousov
115852a510acSJamie Gritton static int
shm_prison_check(void * obj,void * data)115952a510acSJamie Gritton shm_prison_check(void *obj, void *data)
116052a510acSJamie Gritton {
116152a510acSJamie Gritton struct prison *pr = obj;
116252a510acSJamie Gritton struct prison *prpr;
116352a510acSJamie Gritton struct vfsoptlist *opts = data;
116452a510acSJamie Gritton int error, jsys;
116552a510acSJamie Gritton
116652a510acSJamie Gritton /*
116752a510acSJamie Gritton * sysvshm is a jailsys integer.
116852a510acSJamie Gritton * It must be "disable" if the parent jail is disabled.
116952a510acSJamie Gritton */
117052a510acSJamie Gritton error = vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys));
117152a510acSJamie Gritton if (error != ENOENT) {
117252a510acSJamie Gritton if (error != 0)
117352a510acSJamie Gritton return (error);
117452a510acSJamie Gritton switch (jsys) {
117552a510acSJamie Gritton case JAIL_SYS_DISABLE:
117652a510acSJamie Gritton break;
117752a510acSJamie Gritton case JAIL_SYS_NEW:
117852a510acSJamie Gritton case JAIL_SYS_INHERIT:
117952a510acSJamie Gritton prison_lock(pr->pr_parent);
118052a510acSJamie Gritton prpr = osd_jail_get(pr->pr_parent, shm_prison_slot);
118152a510acSJamie Gritton prison_unlock(pr->pr_parent);
118252a510acSJamie Gritton if (prpr == NULL)
118352a510acSJamie Gritton return (EPERM);
118452a510acSJamie Gritton break;
118552a510acSJamie Gritton default:
118652a510acSJamie Gritton return (EINVAL);
118752a510acSJamie Gritton }
118852a510acSJamie Gritton }
118952a510acSJamie Gritton
119052a510acSJamie Gritton return (0);
119152a510acSJamie Gritton }
119252a510acSJamie Gritton
119352a510acSJamie Gritton static int
shm_prison_set(void * obj,void * data)119452a510acSJamie Gritton shm_prison_set(void *obj, void *data)
119552a510acSJamie Gritton {
119652a510acSJamie Gritton struct prison *pr = obj;
119752a510acSJamie Gritton struct prison *tpr, *orpr, *nrpr, *trpr;
119852a510acSJamie Gritton struct vfsoptlist *opts = data;
119952a510acSJamie Gritton void *rsv;
120052a510acSJamie Gritton int jsys, descend;
120152a510acSJamie Gritton
120252a510acSJamie Gritton /*
120352a510acSJamie Gritton * sysvshm controls which jail is the root of the associated segments
120452a510acSJamie Gritton * (this jail or same as the parent), or if the feature is available
120552a510acSJamie Gritton * at all.
120652a510acSJamie Gritton */
120752a510acSJamie Gritton if (vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys)) == ENOENT)
120852a510acSJamie Gritton jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0)
120952a510acSJamie Gritton ? JAIL_SYS_INHERIT
121052a510acSJamie Gritton : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0)
121152a510acSJamie Gritton ? JAIL_SYS_DISABLE
121252a510acSJamie Gritton : -1;
121352a510acSJamie Gritton if (jsys == JAIL_SYS_DISABLE) {
121452a510acSJamie Gritton prison_lock(pr);
121552a510acSJamie Gritton orpr = osd_jail_get(pr, shm_prison_slot);
121652a510acSJamie Gritton if (orpr != NULL)
121752a510acSJamie Gritton osd_jail_del(pr, shm_prison_slot);
121852a510acSJamie Gritton prison_unlock(pr);
121952a510acSJamie Gritton if (orpr != NULL) {
122052a510acSJamie Gritton if (orpr == pr)
122152a510acSJamie Gritton shm_prison_cleanup(pr);
122252a510acSJamie Gritton /* Disable all child jails as well. */
122352a510acSJamie Gritton FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
122452a510acSJamie Gritton prison_lock(tpr);
122552a510acSJamie Gritton trpr = osd_jail_get(tpr, shm_prison_slot);
122652a510acSJamie Gritton if (trpr != NULL) {
122752a510acSJamie Gritton osd_jail_del(tpr, shm_prison_slot);
122852a510acSJamie Gritton prison_unlock(tpr);
122952a510acSJamie Gritton if (trpr == tpr)
123052a510acSJamie Gritton shm_prison_cleanup(tpr);
123152a510acSJamie Gritton } else {
123252a510acSJamie Gritton prison_unlock(tpr);
123352a510acSJamie Gritton descend = 0;
123452a510acSJamie Gritton }
123552a510acSJamie Gritton }
123652a510acSJamie Gritton }
123752a510acSJamie Gritton } else if (jsys != -1) {
123852a510acSJamie Gritton if (jsys == JAIL_SYS_NEW)
123952a510acSJamie Gritton nrpr = pr;
124052a510acSJamie Gritton else {
124152a510acSJamie Gritton prison_lock(pr->pr_parent);
124252a510acSJamie Gritton nrpr = osd_jail_get(pr->pr_parent, shm_prison_slot);
124352a510acSJamie Gritton prison_unlock(pr->pr_parent);
124452a510acSJamie Gritton }
124552a510acSJamie Gritton rsv = osd_reserve(shm_prison_slot);
124652a510acSJamie Gritton prison_lock(pr);
124752a510acSJamie Gritton orpr = osd_jail_get(pr, shm_prison_slot);
124852a510acSJamie Gritton if (orpr != nrpr)
124952a510acSJamie Gritton (void)osd_jail_set_reserved(pr, shm_prison_slot, rsv,
125052a510acSJamie Gritton nrpr);
125152a510acSJamie Gritton else
125252a510acSJamie Gritton osd_free_reserved(rsv);
125352a510acSJamie Gritton prison_unlock(pr);
125452a510acSJamie Gritton if (orpr != nrpr) {
125552a510acSJamie Gritton if (orpr == pr)
125652a510acSJamie Gritton shm_prison_cleanup(pr);
125752a510acSJamie Gritton if (orpr != NULL) {
125852a510acSJamie Gritton /* Change child jails matching the old root, */
125952a510acSJamie Gritton FOREACH_PRISON_DESCENDANT(pr, tpr, descend) {
126052a510acSJamie Gritton prison_lock(tpr);
126152a510acSJamie Gritton trpr = osd_jail_get(tpr,
126252a510acSJamie Gritton shm_prison_slot);
126352a510acSJamie Gritton if (trpr == orpr) {
126452a510acSJamie Gritton (void)osd_jail_set(tpr,
126552a510acSJamie Gritton shm_prison_slot, nrpr);
126652a510acSJamie Gritton prison_unlock(tpr);
126752a510acSJamie Gritton if (trpr == tpr)
126852a510acSJamie Gritton shm_prison_cleanup(tpr);
126952a510acSJamie Gritton } else {
127052a510acSJamie Gritton prison_unlock(tpr);
127152a510acSJamie Gritton descend = 0;
127252a510acSJamie Gritton }
127352a510acSJamie Gritton }
127452a510acSJamie Gritton }
127552a510acSJamie Gritton }
127652a510acSJamie Gritton }
127752a510acSJamie Gritton
127852a510acSJamie Gritton return (0);
127952a510acSJamie Gritton }
128052a510acSJamie Gritton
128152a510acSJamie Gritton static int
shm_prison_get(void * obj,void * data)128252a510acSJamie Gritton shm_prison_get(void *obj, void *data)
128352a510acSJamie Gritton {
128452a510acSJamie Gritton struct prison *pr = obj;
128552a510acSJamie Gritton struct prison *rpr;
128652a510acSJamie Gritton struct vfsoptlist *opts = data;
128752a510acSJamie Gritton int error, jsys;
128852a510acSJamie Gritton
128952a510acSJamie Gritton /* Set sysvshm based on the jail's root prison. */
129052a510acSJamie Gritton prison_lock(pr);
129152a510acSJamie Gritton rpr = osd_jail_get(pr, shm_prison_slot);
129252a510acSJamie Gritton prison_unlock(pr);
129352a510acSJamie Gritton jsys = rpr == NULL ? JAIL_SYS_DISABLE
129452a510acSJamie Gritton : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
129552a510acSJamie Gritton error = vfs_setopt(opts, "sysvshm", &jsys, sizeof(jsys));
129652a510acSJamie Gritton if (error == ENOENT)
129752a510acSJamie Gritton error = 0;
129852a510acSJamie Gritton return (error);
129952a510acSJamie Gritton }
130052a510acSJamie Gritton
130152a510acSJamie Gritton static int
shm_prison_remove(void * obj,void * data __unused)130252a510acSJamie Gritton shm_prison_remove(void *obj, void *data __unused)
130352a510acSJamie Gritton {
130452a510acSJamie Gritton struct prison *pr = obj;
130552a510acSJamie Gritton struct prison *rpr;
130652a510acSJamie Gritton
130752a510acSJamie Gritton SYSVSHM_LOCK();
130852a510acSJamie Gritton prison_lock(pr);
130952a510acSJamie Gritton rpr = osd_jail_get(pr, shm_prison_slot);
131052a510acSJamie Gritton prison_unlock(pr);
131152a510acSJamie Gritton if (rpr == pr)
131252a510acSJamie Gritton shm_prison_cleanup(pr);
131352a510acSJamie Gritton SYSVSHM_UNLOCK();
131452a510acSJamie Gritton return (0);
131552a510acSJamie Gritton }
131652a510acSJamie Gritton
131752a510acSJamie Gritton static void
shm_prison_cleanup(struct prison * pr)131852a510acSJamie Gritton shm_prison_cleanup(struct prison *pr)
131952a510acSJamie Gritton {
132052a510acSJamie Gritton struct shmid_kernel *shmseg;
132152a510acSJamie Gritton int i;
132252a510acSJamie Gritton
132352a510acSJamie Gritton /* Remove any segments that belong to this jail. */
132452a510acSJamie Gritton for (i = 0; i < shmalloced; i++) {
132552a510acSJamie Gritton shmseg = &shmsegs[i];
132652a510acSJamie Gritton if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) &&
132752a510acSJamie Gritton shmseg->cred != NULL && shmseg->cred->cr_prison == pr) {
132852a510acSJamie Gritton shm_remove(shmseg, i);
132952a510acSJamie Gritton }
133052a510acSJamie Gritton }
133152a510acSJamie Gritton }
133252a510acSJamie Gritton
133352a510acSJamie Gritton SYSCTL_JAIL_PARAM_SYS_NODE(sysvshm, CTLFLAG_RW, "SYSV shared memory");
133452a510acSJamie Gritton
133545f48220SJohn Baldwin #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
133645f48220SJohn Baldwin struct oshmid_ds {
133745f48220SJohn Baldwin struct ipc_perm_old shm_perm; /* operation perms */
133845f48220SJohn Baldwin int shm_segsz; /* size of segment (bytes) */
133945f48220SJohn Baldwin u_short shm_cpid; /* pid, creator */
134045f48220SJohn Baldwin u_short shm_lpid; /* pid, last operation */
134145f48220SJohn Baldwin short shm_nattch; /* no. of current attaches */
134245f48220SJohn Baldwin time_t shm_atime; /* last attach time */
134345f48220SJohn Baldwin time_t shm_dtime; /* last detach time */
134445f48220SJohn Baldwin time_t shm_ctime; /* last change time */
134545f48220SJohn Baldwin void *shm_handle; /* internal handle for shm segment */
134645f48220SJohn Baldwin };
134745f48220SJohn Baldwin
134845f48220SJohn Baldwin struct oshmctl_args {
134945f48220SJohn Baldwin int shmid;
135045f48220SJohn Baldwin int cmd;
135145f48220SJohn Baldwin struct oshmid_ds *ubuf;
135245f48220SJohn Baldwin };
135345f48220SJohn Baldwin
135445f48220SJohn Baldwin static int
oshmctl(struct thread * td,struct oshmctl_args * uap)1355ca998284SJohn Baldwin oshmctl(struct thread *td, struct oshmctl_args *uap)
135645f48220SJohn Baldwin {
135745f48220SJohn Baldwin #ifdef COMPAT_43
135845f48220SJohn Baldwin int error = 0;
135952a510acSJamie Gritton struct prison *rpr;
136045f48220SJohn Baldwin struct shmid_kernel *shmseg;
136145f48220SJohn Baldwin struct oshmid_ds outbuf;
136245f48220SJohn Baldwin
136352a510acSJamie Gritton rpr = shm_find_prison(td->td_ucred);
136452a510acSJamie Gritton if (rpr == NULL)
136545f48220SJohn Baldwin return (ENOSYS);
1366f16f8610SKonstantin Belousov if (uap->cmd != IPC_STAT) {
1367f16f8610SKonstantin Belousov return (freebsd7_shmctl(td,
1368f16f8610SKonstantin Belousov (struct freebsd7_shmctl_args *)uap));
1369f16f8610SKonstantin Belousov }
13700555fb35SKonstantin Belousov SYSVSHM_LOCK();
137152a510acSJamie Gritton shmseg = shm_find_segment(rpr, uap->shmid, true);
137245f48220SJohn Baldwin if (shmseg == NULL) {
13730555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
13744cfc037cSKonstantin Belousov return (EINVAL);
137545f48220SJohn Baldwin }
137645f48220SJohn Baldwin error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
1377f16f8610SKonstantin Belousov if (error != 0) {
1378f16f8610SKonstantin Belousov SYSVSHM_UNLOCK();
1379f16f8610SKonstantin Belousov return (error);
1380f16f8610SKonstantin Belousov }
13810555fb35SKonstantin Belousov #ifdef MAC
1382f16f8610SKonstantin Belousov error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd);
1383f16f8610SKonstantin Belousov if (error != 0) {
1384f16f8610SKonstantin Belousov SYSVSHM_UNLOCK();
1385f16f8610SKonstantin Belousov return (error);
1386f16f8610SKonstantin Belousov }
138745f48220SJohn Baldwin #endif
138845f48220SJohn Baldwin ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm);
138945f48220SJohn Baldwin outbuf.shm_segsz = shmseg->u.shm_segsz;
139045f48220SJohn Baldwin outbuf.shm_cpid = shmseg->u.shm_cpid;
139145f48220SJohn Baldwin outbuf.shm_lpid = shmseg->u.shm_lpid;
139245f48220SJohn Baldwin outbuf.shm_nattch = shmseg->u.shm_nattch;
139345f48220SJohn Baldwin outbuf.shm_atime = shmseg->u.shm_atime;
139445f48220SJohn Baldwin outbuf.shm_dtime = shmseg->u.shm_dtime;
139545f48220SJohn Baldwin outbuf.shm_ctime = shmseg->u.shm_ctime;
139645f48220SJohn Baldwin outbuf.shm_handle = shmseg->object;
13970555fb35SKonstantin Belousov SYSVSHM_UNLOCK();
1398e2f5418eSMateusz Guzik return (copyout(&outbuf, uap->ubuf, sizeof(outbuf)));
139945f48220SJohn Baldwin #else
140045f48220SJohn Baldwin return (EINVAL);
140145f48220SJohn Baldwin #endif
140245f48220SJohn Baldwin }
140345f48220SJohn Baldwin
140445f48220SJohn Baldwin /* XXX casting to (sy_call_t *) is bogus, as usual. */
140545f48220SJohn Baldwin static sy_call_t *shmcalls[] = {
14068451d0ddSKip Macy (sy_call_t *)sys_shmat, (sy_call_t *)oshmctl,
14078451d0ddSKip Macy (sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget,
1408b648d480SJohn Baldwin (sy_call_t *)freebsd7_shmctl
140945f48220SJohn Baldwin };
141045f48220SJohn Baldwin
14110555fb35SKonstantin Belousov #ifndef _SYS_SYSPROTO_H_
141245f48220SJohn Baldwin /* XXX actually varargs. */
14130555fb35SKonstantin Belousov struct shmsys_args {
141445f48220SJohn Baldwin int which;
141545f48220SJohn Baldwin int a2;
141645f48220SJohn Baldwin int a3;
141745f48220SJohn Baldwin int a4;
14180555fb35SKonstantin Belousov };
14190555fb35SKonstantin Belousov #endif
14200555fb35SKonstantin Belousov int
sys_shmsys(struct thread * td,struct shmsys_args * uap)14210555fb35SKonstantin Belousov sys_shmsys(struct thread *td, struct shmsys_args *uap)
142245f48220SJohn Baldwin {
142345f48220SJohn Baldwin
1424b7830259SRobert Watson AUDIT_ARG_SVIPC_WHICH(uap->which);
14250555fb35SKonstantin Belousov if (uap->which < 0 || uap->which >= nitems(shmcalls))
142645f48220SJohn Baldwin return (EINVAL);
1427e2f5418eSMateusz Guzik return ((*shmcalls[uap->which])(td, &uap->a2));
142845f48220SJohn Baldwin }
142945f48220SJohn Baldwin
143045f48220SJohn Baldwin #endif /* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */
143145f48220SJohn Baldwin
143275d633cbSKonstantin Belousov #ifdef COMPAT_FREEBSD32
143375d633cbSKonstantin Belousov
143475d633cbSKonstantin Belousov int
freebsd32_shmsys(struct thread * td,struct freebsd32_shmsys_args * uap)143575d633cbSKonstantin Belousov freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
143675d633cbSKonstantin Belousov {
143775d633cbSKonstantin Belousov
143875d633cbSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
143975d633cbSKonstantin Belousov defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1440b7830259SRobert Watson AUDIT_ARG_SVIPC_WHICH(uap->which);
144175d633cbSKonstantin Belousov switch (uap->which) {
144275d633cbSKonstantin Belousov case 0: { /* shmat */
144375d633cbSKonstantin Belousov struct shmat_args ap;
144475d633cbSKonstantin Belousov
144575d633cbSKonstantin Belousov ap.shmid = uap->a2;
144675d633cbSKonstantin Belousov ap.shmaddr = PTRIN(uap->a3);
144775d633cbSKonstantin Belousov ap.shmflg = uap->a4;
144875d633cbSKonstantin Belousov return (sysent[SYS_shmat].sy_call(td, &ap));
144975d633cbSKonstantin Belousov }
145075d633cbSKonstantin Belousov case 2: { /* shmdt */
145175d633cbSKonstantin Belousov struct shmdt_args ap;
145275d633cbSKonstantin Belousov
145375d633cbSKonstantin Belousov ap.shmaddr = PTRIN(uap->a2);
145475d633cbSKonstantin Belousov return (sysent[SYS_shmdt].sy_call(td, &ap));
145575d633cbSKonstantin Belousov }
145675d633cbSKonstantin Belousov case 3: { /* shmget */
145775d633cbSKonstantin Belousov struct shmget_args ap;
145875d633cbSKonstantin Belousov
145975d633cbSKonstantin Belousov ap.key = uap->a2;
146075d633cbSKonstantin Belousov ap.size = uap->a3;
146175d633cbSKonstantin Belousov ap.shmflg = uap->a4;
146275d633cbSKonstantin Belousov return (sysent[SYS_shmget].sy_call(td, &ap));
146375d633cbSKonstantin Belousov }
146475d633cbSKonstantin Belousov case 4: { /* shmctl */
146575d633cbSKonstantin Belousov struct freebsd7_freebsd32_shmctl_args ap;
146675d633cbSKonstantin Belousov
146775d633cbSKonstantin Belousov ap.shmid = uap->a2;
146875d633cbSKonstantin Belousov ap.cmd = uap->a3;
146975d633cbSKonstantin Belousov ap.buf = PTRIN(uap->a4);
147075d633cbSKonstantin Belousov return (freebsd7_freebsd32_shmctl(td, &ap));
147175d633cbSKonstantin Belousov }
147275d633cbSKonstantin Belousov case 1: /* oshmctl */
147375d633cbSKonstantin Belousov default:
147475d633cbSKonstantin Belousov return (EINVAL);
147575d633cbSKonstantin Belousov }
147675d633cbSKonstantin Belousov #else
147775d633cbSKonstantin Belousov return (nosys(td, NULL));
147875d633cbSKonstantin Belousov #endif
147975d633cbSKonstantin Belousov }
148075d633cbSKonstantin Belousov
148175d633cbSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
148275d633cbSKonstantin Belousov defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
148375d633cbSKonstantin Belousov int
freebsd7_freebsd32_shmctl(struct thread * td,struct freebsd7_freebsd32_shmctl_args * uap)148475d633cbSKonstantin Belousov freebsd7_freebsd32_shmctl(struct thread *td,
148575d633cbSKonstantin Belousov struct freebsd7_freebsd32_shmctl_args *uap)
148675d633cbSKonstantin Belousov {
1487e2f5418eSMateusz Guzik int error;
148875d633cbSKonstantin Belousov union {
148975d633cbSKonstantin Belousov struct shmid_ds shmid_ds;
149075d633cbSKonstantin Belousov struct shm_info shm_info;
149175d633cbSKonstantin Belousov struct shminfo shminfo;
149275d633cbSKonstantin Belousov } u;
149375d633cbSKonstantin Belousov union {
14943b0cd7e5SBrooks Davis struct shmid_ds_old32 shmid_ds32;
149575d633cbSKonstantin Belousov struct shm_info32 shm_info32;
149675d633cbSKonstantin Belousov struct shminfo32 shminfo32;
149775d633cbSKonstantin Belousov } u32;
149875d633cbSKonstantin Belousov size_t sz;
149975d633cbSKonstantin Belousov
150075d633cbSKonstantin Belousov if (uap->cmd == IPC_SET) {
150175d633cbSKonstantin Belousov if ((error = copyin(uap->buf, &u32.shmid_ds32,
150275d633cbSKonstantin Belousov sizeof(u32.shmid_ds32))))
150375d633cbSKonstantin Belousov goto done;
150475d633cbSKonstantin Belousov freebsd32_ipcperm_old_in(&u32.shmid_ds32.shm_perm,
150575d633cbSKonstantin Belousov &u.shmid_ds.shm_perm);
150675d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
150775d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
150875d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
150975d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
151075d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
151175d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
151275d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
151375d633cbSKonstantin Belousov }
151475d633cbSKonstantin Belousov
151575d633cbSKonstantin Belousov error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
151675d633cbSKonstantin Belousov if (error)
151775d633cbSKonstantin Belousov goto done;
151875d633cbSKonstantin Belousov
151975d633cbSKonstantin Belousov /* Cases in which we need to copyout */
152075d633cbSKonstantin Belousov switch (uap->cmd) {
152175d633cbSKonstantin Belousov case IPC_INFO:
152275d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmax);
152375d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmin);
152475d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmni);
152575d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmseg);
152675d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmall);
152775d633cbSKonstantin Belousov error = copyout(&u32.shminfo32, uap->buf,
152875d633cbSKonstantin Belousov sizeof(u32.shminfo32));
152975d633cbSKonstantin Belousov break;
153075d633cbSKonstantin Belousov case SHM_INFO:
153175d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, used_ids);
153275d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_rss);
153375d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_tot);
153475d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_swp);
153575d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, swap_attempts);
153675d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, swap_successes);
153775d633cbSKonstantin Belousov error = copyout(&u32.shm_info32, uap->buf,
153875d633cbSKonstantin Belousov sizeof(u32.shm_info32));
153975d633cbSKonstantin Belousov break;
154075d633cbSKonstantin Belousov case SHM_STAT:
154175d633cbSKonstantin Belousov case IPC_STAT:
1542fb441a88SKonstantin Belousov memset(&u32.shmid_ds32, 0, sizeof(u32.shmid_ds32));
154375d633cbSKonstantin Belousov freebsd32_ipcperm_old_out(&u.shmid_ds.shm_perm,
154475d633cbSKonstantin Belousov &u32.shmid_ds32.shm_perm);
154575d633cbSKonstantin Belousov if (u.shmid_ds.shm_segsz > INT32_MAX)
154675d633cbSKonstantin Belousov u32.shmid_ds32.shm_segsz = INT32_MAX;
154775d633cbSKonstantin Belousov else
154875d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
154975d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
155075d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
155175d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
155275d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
155375d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
155475d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
155575d633cbSKonstantin Belousov u32.shmid_ds32.shm_internal = 0;
155675d633cbSKonstantin Belousov error = copyout(&u32.shmid_ds32, uap->buf,
155775d633cbSKonstantin Belousov sizeof(u32.shmid_ds32));
155875d633cbSKonstantin Belousov break;
155975d633cbSKonstantin Belousov }
156075d633cbSKonstantin Belousov
156175d633cbSKonstantin Belousov done:
156275d633cbSKonstantin Belousov if (error) {
156375d633cbSKonstantin Belousov /* Invalidate the return value */
156475d633cbSKonstantin Belousov td->td_retval[0] = -1;
156575d633cbSKonstantin Belousov }
156675d633cbSKonstantin Belousov return (error);
156775d633cbSKonstantin Belousov }
156875d633cbSKonstantin Belousov #endif
156975d633cbSKonstantin Belousov
157075d633cbSKonstantin Belousov int
freebsd32_shmctl(struct thread * td,struct freebsd32_shmctl_args * uap)157175d633cbSKonstantin Belousov freebsd32_shmctl(struct thread *td, struct freebsd32_shmctl_args *uap)
157275d633cbSKonstantin Belousov {
1573e2f5418eSMateusz Guzik int error;
157475d633cbSKonstantin Belousov union {
157575d633cbSKonstantin Belousov struct shmid_ds shmid_ds;
157675d633cbSKonstantin Belousov struct shm_info shm_info;
157775d633cbSKonstantin Belousov struct shminfo shminfo;
157875d633cbSKonstantin Belousov } u;
157975d633cbSKonstantin Belousov union {
158075d633cbSKonstantin Belousov struct shmid_ds32 shmid_ds32;
158175d633cbSKonstantin Belousov struct shm_info32 shm_info32;
158275d633cbSKonstantin Belousov struct shminfo32 shminfo32;
158375d633cbSKonstantin Belousov } u32;
158475d633cbSKonstantin Belousov size_t sz;
158575d633cbSKonstantin Belousov
158675d633cbSKonstantin Belousov if (uap->cmd == IPC_SET) {
158775d633cbSKonstantin Belousov if ((error = copyin(uap->buf, &u32.shmid_ds32,
158875d633cbSKonstantin Belousov sizeof(u32.shmid_ds32))))
158975d633cbSKonstantin Belousov goto done;
159075d633cbSKonstantin Belousov freebsd32_ipcperm_in(&u32.shmid_ds32.shm_perm,
159175d633cbSKonstantin Belousov &u.shmid_ds.shm_perm);
159275d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
159375d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
159475d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
159575d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
159675d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
159775d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
159875d633cbSKonstantin Belousov CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
159975d633cbSKonstantin Belousov }
160075d633cbSKonstantin Belousov
160175d633cbSKonstantin Belousov error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
160275d633cbSKonstantin Belousov if (error)
160375d633cbSKonstantin Belousov goto done;
160475d633cbSKonstantin Belousov
160575d633cbSKonstantin Belousov /* Cases in which we need to copyout */
160675d633cbSKonstantin Belousov switch (uap->cmd) {
160775d633cbSKonstantin Belousov case IPC_INFO:
160875d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmax);
160975d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmin);
161075d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmmni);
161175d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmseg);
161275d633cbSKonstantin Belousov CP(u.shminfo, u32.shminfo32, shmall);
161375d633cbSKonstantin Belousov error = copyout(&u32.shminfo32, uap->buf,
161475d633cbSKonstantin Belousov sizeof(u32.shminfo32));
161575d633cbSKonstantin Belousov break;
161675d633cbSKonstantin Belousov case SHM_INFO:
161775d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, used_ids);
161875d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_rss);
161975d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_tot);
162075d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, shm_swp);
162175d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, swap_attempts);
162275d633cbSKonstantin Belousov CP(u.shm_info, u32.shm_info32, swap_successes);
162375d633cbSKonstantin Belousov error = copyout(&u32.shm_info32, uap->buf,
162475d633cbSKonstantin Belousov sizeof(u32.shm_info32));
162575d633cbSKonstantin Belousov break;
162675d633cbSKonstantin Belousov case SHM_STAT:
162775d633cbSKonstantin Belousov case IPC_STAT:
162875d633cbSKonstantin Belousov freebsd32_ipcperm_out(&u.shmid_ds.shm_perm,
162975d633cbSKonstantin Belousov &u32.shmid_ds32.shm_perm);
163075d633cbSKonstantin Belousov if (u.shmid_ds.shm_segsz > INT32_MAX)
163175d633cbSKonstantin Belousov u32.shmid_ds32.shm_segsz = INT32_MAX;
163275d633cbSKonstantin Belousov else
163375d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
163475d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
163575d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
163675d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
163775d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
163875d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
163975d633cbSKonstantin Belousov CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
164075d633cbSKonstantin Belousov error = copyout(&u32.shmid_ds32, uap->buf,
164175d633cbSKonstantin Belousov sizeof(u32.shmid_ds32));
164275d633cbSKonstantin Belousov break;
164375d633cbSKonstantin Belousov }
164475d633cbSKonstantin Belousov
164575d633cbSKonstantin Belousov done:
164675d633cbSKonstantin Belousov if (error) {
164775d633cbSKonstantin Belousov /* Invalidate the return value */
164875d633cbSKonstantin Belousov td->td_retval[0] = -1;
164975d633cbSKonstantin Belousov }
165075d633cbSKonstantin Belousov return (error);
165175d633cbSKonstantin Belousov }
165275d633cbSKonstantin Belousov #endif
165375d633cbSKonstantin Belousov
1654b648d480SJohn Baldwin #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1655b648d480SJohn Baldwin defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1656b648d480SJohn Baldwin
1657b648d480SJohn Baldwin #ifndef _SYS_SYSPROTO_H_
1658b648d480SJohn Baldwin struct freebsd7_shmctl_args {
1659b648d480SJohn Baldwin int shmid;
1660b648d480SJohn Baldwin int cmd;
1661b648d480SJohn Baldwin struct shmid_ds_old *buf;
1662b648d480SJohn Baldwin };
1663b648d480SJohn Baldwin #endif
1664b648d480SJohn Baldwin int
freebsd7_shmctl(struct thread * td,struct freebsd7_shmctl_args * uap)16650555fb35SKonstantin Belousov freebsd7_shmctl(struct thread *td, struct freebsd7_shmctl_args *uap)
1666b648d480SJohn Baldwin {
1667e2f5418eSMateusz Guzik int error;
1668b648d480SJohn Baldwin struct shmid_ds_old old;
1669b648d480SJohn Baldwin struct shmid_ds buf;
1670b648d480SJohn Baldwin size_t bufsz;
1671b648d480SJohn Baldwin
1672b648d480SJohn Baldwin /*
1673b648d480SJohn Baldwin * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
1674b648d480SJohn Baldwin * Linux binaries. If we see the call come through the FreeBSD ABI,
1675b648d480SJohn Baldwin * return an error back to the user since we do not to support this.
1676b648d480SJohn Baldwin */
1677b648d480SJohn Baldwin if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
1678b648d480SJohn Baldwin uap->cmd == SHM_STAT)
1679b648d480SJohn Baldwin return (EINVAL);
1680b648d480SJohn Baldwin
1681b648d480SJohn Baldwin /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
1682b648d480SJohn Baldwin if (uap->cmd == IPC_SET) {
1683b648d480SJohn Baldwin if ((error = copyin(uap->buf, &old, sizeof(old))))
1684b648d480SJohn Baldwin goto done;
1685b648d480SJohn Baldwin ipcperm_old2new(&old.shm_perm, &buf.shm_perm);
1686b648d480SJohn Baldwin CP(old, buf, shm_segsz);
1687b648d480SJohn Baldwin CP(old, buf, shm_lpid);
1688b648d480SJohn Baldwin CP(old, buf, shm_cpid);
1689b648d480SJohn Baldwin CP(old, buf, shm_nattch);
1690b648d480SJohn Baldwin CP(old, buf, shm_atime);
1691b648d480SJohn Baldwin CP(old, buf, shm_dtime);
1692b648d480SJohn Baldwin CP(old, buf, shm_ctime);
1693b648d480SJohn Baldwin }
1694b648d480SJohn Baldwin
1695b648d480SJohn Baldwin error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
1696b648d480SJohn Baldwin if (error)
1697b648d480SJohn Baldwin goto done;
1698b648d480SJohn Baldwin
1699b648d480SJohn Baldwin /* Cases in which we need to copyout */
1700b648d480SJohn Baldwin switch (uap->cmd) {
1701b648d480SJohn Baldwin case IPC_STAT:
1702fb441a88SKonstantin Belousov memset(&old, 0, sizeof(old));
1703b648d480SJohn Baldwin ipcperm_new2old(&buf.shm_perm, &old.shm_perm);
1704b648d480SJohn Baldwin if (buf.shm_segsz > INT_MAX)
1705b648d480SJohn Baldwin old.shm_segsz = INT_MAX;
1706b648d480SJohn Baldwin else
1707b648d480SJohn Baldwin CP(buf, old, shm_segsz);
1708b648d480SJohn Baldwin CP(buf, old, shm_lpid);
1709b648d480SJohn Baldwin CP(buf, old, shm_cpid);
1710b648d480SJohn Baldwin if (buf.shm_nattch > SHRT_MAX)
1711b648d480SJohn Baldwin old.shm_nattch = SHRT_MAX;
1712b648d480SJohn Baldwin else
1713b648d480SJohn Baldwin CP(buf, old, shm_nattch);
1714b648d480SJohn Baldwin CP(buf, old, shm_atime);
1715b648d480SJohn Baldwin CP(buf, old, shm_dtime);
1716b648d480SJohn Baldwin CP(buf, old, shm_ctime);
1717b648d480SJohn Baldwin old.shm_internal = NULL;
1718b648d480SJohn Baldwin error = copyout(&old, uap->buf, sizeof(old));
1719b648d480SJohn Baldwin break;
1720b648d480SJohn Baldwin }
1721b648d480SJohn Baldwin
1722b648d480SJohn Baldwin done:
1723b648d480SJohn Baldwin if (error) {
1724b648d480SJohn Baldwin /* Invalidate the return value */
1725b648d480SJohn Baldwin td->td_retval[0] = -1;
1726b648d480SJohn Baldwin }
1727b648d480SJohn Baldwin return (error);
1728b648d480SJohn Baldwin }
1729b648d480SJohn Baldwin
1730b648d480SJohn Baldwin #endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1731b648d480SJohn Baldwin COMPAT_FREEBSD7 */
1732b648d480SJohn Baldwin
1733a723c4e1SDima Dorfman static int
sysvshm_modload(struct module * module,int cmd,void * arg)173478525ce3SAlfred Perlstein sysvshm_modload(struct module *module, int cmd, void *arg)
173578525ce3SAlfred Perlstein {
173678525ce3SAlfred Perlstein int error = 0;
173778525ce3SAlfred Perlstein
173878525ce3SAlfred Perlstein switch (cmd) {
173978525ce3SAlfred Perlstein case MOD_LOAD:
174075d633cbSKonstantin Belousov error = shminit();
174175d633cbSKonstantin Belousov if (error != 0)
174275d633cbSKonstantin Belousov shmunload();
174378525ce3SAlfred Perlstein break;
174478525ce3SAlfred Perlstein case MOD_UNLOAD:
174578525ce3SAlfred Perlstein error = shmunload();
174678525ce3SAlfred Perlstein break;
174778525ce3SAlfred Perlstein case MOD_SHUTDOWN:
174878525ce3SAlfred Perlstein break;
174978525ce3SAlfred Perlstein default:
175078525ce3SAlfred Perlstein error = EINVAL;
175178525ce3SAlfred Perlstein break;
175278525ce3SAlfred Perlstein }
175378525ce3SAlfred Perlstein return (error);
175478525ce3SAlfred Perlstein }
175578525ce3SAlfred Perlstein
1756faa784b7SDag-Erling Smørgrav static moduledata_t sysvshm_mod = {
1757faa784b7SDag-Erling Smørgrav "sysvshm",
175878525ce3SAlfred Perlstein &sysvshm_modload,
175978525ce3SAlfred Perlstein NULL
176078525ce3SAlfred Perlstein };
176178525ce3SAlfred Perlstein
176271361470SJohn Baldwin DECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
1763faa784b7SDag-Erling Smørgrav MODULE_VERSION(sysvshm, 1);
1764