12729Sdfr/* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */ 2139804Simp/*- 32729Sdfr * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. 42729Sdfr * 52729Sdfr * Redistribution and use in source and binary forms, with or without 62729Sdfr * modification, are permitted provided that the following conditions 72729Sdfr * are met: 82729Sdfr * 1. Redistributions of source code must retain the above copyright 92729Sdfr * notice, this list of conditions and the following disclaimer. 102729Sdfr * 2. Redistributions in binary form must reproduce the above copyright 112729Sdfr * notice, this list of conditions and the following disclaimer in the 122729Sdfr * documentation and/or other materials provided with the distribution. 132729Sdfr * 3. All advertising materials mentioning features or use of this software 142729Sdfr * must display the following acknowledgement: 152729Sdfr * This product includes software developed by Adam Glass and Charles 162729Sdfr * Hannum. 172729Sdfr * 4. The names of the authors may not be used to endorse or promote products 182729Sdfr * derived from this software without specific prior written permission. 192729Sdfr * 202729Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 212729Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 222729Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 232729Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 242729Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 252729Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 262729Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 272729Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 282729Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 292729Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 302729Sdfr */ 31140617Srwatson/*- 32140617Srwatson * Copyright (c) 2003-2005 McAfee, Inc. 33140617Srwatson * All rights reserved. 34140617Srwatson * 35140617Srwatson * This software was developed for the FreeBSD Project in part by McAfee 36140617Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 37140617Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 38140617Srwatson * program. 39140617Srwatson * 40140617Srwatson * Redistribution and use in source and binary forms, with or without 41140617Srwatson * modification, are permitted provided that the following conditions 42140617Srwatson * are met: 43140617Srwatson * 1. Redistributions of source code must retain the above copyright 44140617Srwatson * notice, this list of conditions and the following disclaimer. 45140617Srwatson * 2. Redistributions in binary form must reproduce the above copyright 46140617Srwatson * notice, this list of conditions and the following disclaimer in the 47140617Srwatson * documentation and/or other materials provided with the distribution. 48140617Srwatson * 49140617Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 50140617Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51140617Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52140617Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 53140617Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54140617Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55140617Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56140617Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57140617Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58140617Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59140617Srwatson * SUCH DAMAGE. 60140617Srwatson */ 612729Sdfr 62116182Sobrien#include <sys/cdefs.h> 63116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/sysv_shm.c 367601 2020-11-11 22:00:30Z brooks $"); 64116182Sobrien 6531778Seivind#include "opt_compat.h" 6658820Speter#include "opt_sysvipc.h" 6713255Swollman 682729Sdfr#include <sys/param.h> 6911626Sbde#include <sys/systm.h> 70360451Sbrooks#include <sys/abi_compat.h> 712729Sdfr#include <sys/kernel.h> 72194910Sjhb#include <sys/limits.h> 7376166Smarkm#include <sys/lock.h> 7458820Speter#include <sys/sysctl.h> 752729Sdfr#include <sys/shm.h> 762729Sdfr#include <sys/proc.h> 772729Sdfr#include <sys/malloc.h> 7876941Sjhb#include <sys/mman.h> 79129882Sphk#include <sys/module.h> 8076827Salfred#include <sys/mutex.h> 81220398Strasz#include <sys/racct.h> 82130730Stjr#include <sys/resourcevar.h> 83248084Sattilio#include <sys/rwlock.h> 842729Sdfr#include <sys/stat.h> 8569449Salfred#include <sys/syscall.h> 86114724Smbr#include <sys/syscallsubr.h> 8711626Sbde#include <sys/sysent.h> 8876166Smarkm#include <sys/sysproto.h> 8968024Srwatson#include <sys/jail.h> 902729Sdfr 91163606Srwatson#include <security/mac/mac_framework.h> 92163606Srwatson 932729Sdfr#include <vm/vm.h> 9412662Sdg#include <vm/vm_param.h> 9512662Sdg#include <vm/pmap.h> 9618098Sdyson#include <vm/vm_object.h> 972729Sdfr#include <vm/vm_map.h> 9842957Sdillon#include <vm/vm_page.h> 9918199Sdyson#include <vm/vm_pager.h> 1002729Sdfr 101219028SnetchildFEATURE(sysv_shm, "System V shared memory segments support"); 102219028Snetchild 10330354Sphkstatic MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments"); 10430309Sphk 1052729Sdfr#define SHMSEG_FREE 0x0200 1062729Sdfr#define SHMSEG_REMOVED 0x0400 1072729Sdfr#define SHMSEG_ALLOCATED 0x0800 1082729Sdfr 109189283Skibstatic int shm_last_free, shm_nused, shmalloced; 110189398Skibvm_size_t shm_committed; 111298585Sjamiestatic struct shmid_kernel *shmsegs; 112298585Sjamiestatic unsigned shm_prison_slot; 1132729Sdfr 1142729Sdfrstruct shmmap_state { 1152729Sdfr vm_offset_t va; 1162729Sdfr int shmid; 1172729Sdfr}; 1182729Sdfr 119137613Srwatsonstatic void shm_deallocate_segment(struct shmid_kernel *); 120298585Sjamiestatic int shm_find_segment_by_key(struct prison *, key_t); 121298585Sjamiestatic struct shmid_kernel *shm_find_segment(struct prison *, int, bool); 122109205Sdillonstatic int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); 123367601Sbrooksstatic int shmget_allocate_segment(struct thread *td, key_t key, size_t size, 124367601Sbrooks int mode); 125367601Sbrooksstatic int shmget_existing(struct thread *td, size_t size, int shmflg, 126367601Sbrooks int mode, int segnum); 12792723Salfredstatic void shmrealloc(void); 128205323Skibstatic int shminit(void); 12992723Salfredstatic int sysvshm_modload(struct module *, int, void *); 13092723Salfredstatic int shmunload(void); 131109205Sdillonstatic void shmexit_myhook(struct vmspace *vm); 13292723Salfredstatic void shmfork_myhook(struct proc *p1, struct proc *p2); 13392723Salfredstatic int sysctl_shmsegs(SYSCTL_HANDLER_ARGS); 134298585Sjamiestatic void shm_remove(struct shmid_kernel *, int); 135298585Sjamiestatic struct prison *shm_find_prison(struct ucred *); 136298585Sjamiestatic int shm_prison_cansee(struct prison *, struct shmid_kernel *); 137298585Sjamiestatic int shm_prison_check(void *, void *); 138298585Sjamiestatic int shm_prison_set(void *, void *); 139298585Sjamiestatic int shm_prison_get(void *, void *); 140298585Sjamiestatic int shm_prison_remove(void *, void *); 141298585Sjamiestatic void shm_prison_cleanup(struct prison *); 1422729Sdfr 14358820Speter/* 14477104Sdd * Tuneable values. 14558820Speter */ 14658820Speter#ifndef SHMMAXPGS 147209037Sivoras#define SHMMAXPGS 131072 /* Note: sysv shared memory is swap backed. */ 14858820Speter#endif 14958820Speter#ifndef SHMMAX 15058820Speter#define SHMMAX (SHMMAXPGS*PAGE_SIZE) 15158820Speter#endif 15258820Speter#ifndef SHMMIN 15358820Speter#define SHMMIN 1 15458820Speter#endif 15558820Speter#ifndef SHMMNI 15676275Sdillon#define SHMMNI 192 15758820Speter#endif 15858820Speter#ifndef SHMSEG 15976275Sdillon#define SHMSEG 128 16058820Speter#endif 16158820Speter#ifndef SHMALL 16258820Speter#define SHMALL (SHMMAXPGS) 16358820Speter#endif 16458820Speter 16558820Speterstruct shminfo shminfo = { 166267992Shselasky .shmmax = SHMMAX, 167267992Shselasky .shmmin = SHMMIN, 168267992Shselasky .shmmni = SHMMNI, 169267992Shselasky .shmseg = SHMSEG, 170267992Shselasky .shmall = SHMALL 17158820Speter}; 17258820Speter 17361081Sdillonstatic int shm_use_phys; 174289112Straszstatic int shm_allow_removed = 1; 17561081Sdillon 176267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RWTUN, &shminfo.shmmax, 0, 177141710Scsjp "Maximum shared memory segment size"); 178267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RWTUN, &shminfo.shmmin, 0, 179141710Scsjp "Minimum shared memory segment size"); 180148782ScsjpSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0, 181141710Scsjp "Number of shared memory identifiers"); 182148782ScsjpSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0, 183141710Scsjp "Number of segments per process"); 184267992ShselaskySYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RWTUN, &shminfo.shmall, 0, 185141710Scsjp "Maximum number of pages available for shared memory"); 186267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RWTUN, 187141710Scsjp &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core"); 188267992ShselaskySYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RWTUN, 189141710Scsjp &shm_allow_removed, 0, 190141710Scsjp "Enable/Disable attachment to attached segments marked for removal"); 191280323SkibSYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD | 192280323Skib CTLFLAG_MPSAFE, NULL, 0, sysctl_shmsegs, "", 193329739Sbrooks "Array of struct shmid_kernel for each potential shared memory segment"); 19458820Speter 195280323Skibstatic struct sx sysvshmsx; 196280323Skib#define SYSVSHM_LOCK() sx_xlock(&sysvshmsx) 197280323Skib#define SYSVSHM_UNLOCK() sx_xunlock(&sysvshmsx) 198280323Skib#define SYSVSHM_ASSERT_LOCKED() sx_assert(&sysvshmsx, SA_XLOCKED) 199280323Skib 2002729Sdfrstatic int 201298585Sjamieshm_find_segment_by_key(struct prison *pr, key_t key) 2022729Sdfr{ 2032729Sdfr int i; 2042729Sdfr 20558820Speter for (i = 0; i < shmalloced; i++) 206137613Srwatson if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) && 207298585Sjamie shmsegs[i].cred != NULL && 208298585Sjamie shmsegs[i].cred->cr_prison == pr && 209137613Srwatson shmsegs[i].u.shm_perm.key == key) 210101891Salfred return (i); 211101891Salfred return (-1); 2122729Sdfr} 2132729Sdfr 214280323Skib/* 215280323Skib * Finds segment either by shmid if is_shmid is true, or by segnum if 216280323Skib * is_shmid is false. 217280323Skib */ 218137613Srwatsonstatic struct shmid_kernel * 219298585Sjamieshm_find_segment(struct prison *rpr, int arg, bool is_shmid) 2202729Sdfr{ 221280323Skib struct shmid_kernel *shmseg; 2222729Sdfr int segnum; 2232729Sdfr 224280323Skib segnum = is_shmid ? IPCID_TO_IX(arg) : arg; 22558820Speter if (segnum < 0 || segnum >= shmalloced) 226101891Salfred return (NULL); 2272729Sdfr shmseg = &shmsegs[segnum]; 228137613Srwatson if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || 229122088Sfjoe (!shm_allow_removed && 230285057Smjg (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) || 231298585Sjamie (is_shmid && shmseg->u.shm_perm.seq != IPCID_TO_SEQ(arg)) || 232298597Sjamie shm_prison_cansee(rpr, shmseg) != 0) 233101891Salfred return (NULL); 234101891Salfred return (shmseg); 2352729Sdfr} 2362729Sdfr 2372729Sdfrstatic void 238280323Skibshm_deallocate_segment(struct shmid_kernel *shmseg) 2392729Sdfr{ 240189398Skib vm_size_t size; 2412729Sdfr 242280323Skib SYSVSHM_ASSERT_LOCKED(); 24379224Sdillon 244194910Sjhb vm_object_deallocate(shmseg->object); 245194910Sjhb shmseg->object = NULL; 246194910Sjhb size = round_page(shmseg->u.shm_segsz); 2472729Sdfr shm_committed -= btoc(size); 2482729Sdfr shm_nused--; 249137613Srwatson shmseg->u.shm_perm.mode = SHMSEG_FREE; 250140617Srwatson#ifdef MAC 251172930Srwatson mac_sysvshm_cleanup(shmseg); 252140617Srwatson#endif 253220398Strasz racct_sub_cred(shmseg->cred, RACCT_NSHM, 1); 254220398Strasz racct_sub_cred(shmseg->cred, RACCT_SHMSIZE, size); 255220388Strasz crfree(shmseg->cred); 256220388Strasz shmseg->cred = NULL; 2572729Sdfr} 2582729Sdfr 2592729Sdfrstatic int 260109205Sdillonshm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) 2612729Sdfr{ 262137613Srwatson struct shmid_kernel *shmseg; 2632729Sdfr int segnum, result; 264189398Skib vm_size_t size; 2658876Srgrimes 266280323Skib SYSVSHM_ASSERT_LOCKED(); 267280323Skib segnum = IPCID_TO_IX(shmmap_s->shmid); 268280323Skib KASSERT(segnum >= 0 && segnum < shmalloced, 269280323Skib ("segnum %d shmalloced %d", segnum, shmalloced)); 27077104Sdd 2712729Sdfr shmseg = &shmsegs[segnum]; 272194910Sjhb size = round_page(shmseg->u.shm_segsz); 273109205Sdillon result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); 2742729Sdfr if (result != KERN_SUCCESS) 275101891Salfred return (EINVAL); 2762729Sdfr shmmap_s->shmid = -1; 277137613Srwatson shmseg->u.shm_dtime = time_second; 278137613Srwatson if ((--shmseg->u.shm_nattch <= 0) && 279137613Srwatson (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) { 2802729Sdfr shm_deallocate_segment(shmseg); 2812729Sdfr shm_last_free = segnum; 2822729Sdfr } 283101891Salfred return (0); 2842729Sdfr} 2852729Sdfr 286298585Sjamiestatic void 287298585Sjamieshm_remove(struct shmid_kernel *shmseg, int segnum) 288298585Sjamie{ 289298585Sjamie 290298585Sjamie shmseg->u.shm_perm.key = IPC_PRIVATE; 291298585Sjamie shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; 292298585Sjamie if (shmseg->u.shm_nattch <= 0) { 293298585Sjamie shm_deallocate_segment(shmseg); 294298585Sjamie shm_last_free = segnum; 295298585Sjamie } 296298585Sjamie} 297298585Sjamie 298298585Sjamiestatic struct prison * 299298585Sjamieshm_find_prison(struct ucred *cred) 300298585Sjamie{ 301298585Sjamie struct prison *pr, *rpr; 302298585Sjamie 303298585Sjamie pr = cred->cr_prison; 304298585Sjamie prison_lock(pr); 305298585Sjamie rpr = osd_jail_get(pr, shm_prison_slot); 306298585Sjamie prison_unlock(pr); 307298585Sjamie return rpr; 308298585Sjamie} 309298585Sjamie 310280323Skibstatic int 311298585Sjamieshm_prison_cansee(struct prison *rpr, struct shmid_kernel *shmseg) 312298585Sjamie{ 313298585Sjamie 314298585Sjamie if (shmseg->cred == NULL || 315298585Sjamie !(rpr == shmseg->cred->cr_prison || 316298585Sjamie prison_ischild(rpr, shmseg->cred->cr_prison))) 317298585Sjamie return (EINVAL); 318298585Sjamie return (0); 319298585Sjamie} 320298585Sjamie 321298585Sjamiestatic int 322280323Skibkern_shmdt_locked(struct thread *td, const void *shmaddr) 3232729Sdfr{ 32483366Sjulian struct proc *p = td->td_proc; 3252729Sdfr struct shmmap_state *shmmap_s; 326140617Srwatson#ifdef MAC 327140617Srwatson struct shmid_kernel *shmsegptr; 328285057Smjg int error; 329140617Srwatson#endif 330285057Smjg int i; 3312729Sdfr 332280323Skib SYSVSHM_ASSERT_LOCKED(); 333298585Sjamie if (shm_find_prison(td->td_ucred) == NULL) 33491703Sjhb return (ENOSYS); 335100512Salfred shmmap_s = p->p_vmspace->vm_shm; 336280323Skib if (shmmap_s == NULL) 337280323Skib return (EINVAL); 33882607Sdillon for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { 3392729Sdfr if (shmmap_s->shmid != -1 && 340280323Skib shmmap_s->va == (vm_offset_t)shmaddr) { 3412729Sdfr break; 34282607Sdillon } 34382607Sdillon } 344280323Skib if (i == shminfo.shmseg) 345280323Skib return (EINVAL); 346140617Srwatson#ifdef MAC 347140617Srwatson shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)]; 348172930Srwatson error = mac_sysvshm_check_shmdt(td->td_ucred, shmsegptr); 349162468Srwatson if (error != 0) 350280323Skib return (error); 351140617Srwatson#endif 352285057Smjg return (shm_delete_mapping(p->p_vmspace, shmmap_s)); 3532729Sdfr} 3542729Sdfr 35512866Speter#ifndef _SYS_SYSPROTO_H_ 356280323Skibstruct shmdt_args { 357109831Salfred const void *shmaddr; 3582729Sdfr}; 35912866Speter#endif 3602729Sdfrint 361280323Skibsys_shmdt(struct thread *td, struct shmdt_args *uap) 3622729Sdfr{ 363280323Skib int error; 364280323Skib 365280323Skib SYSVSHM_LOCK(); 366280323Skib error = kern_shmdt_locked(td, uap->shmaddr); 367280323Skib SYSVSHM_UNLOCK(); 368280323Skib return (error); 369280323Skib} 370280323Skib 371280323Skibstatic int 372280323Skibkern_shmat_locked(struct thread *td, int shmid, const void *shmaddr, 373280323Skib int shmflg) 374280323Skib{ 375298585Sjamie struct prison *rpr; 37683366Sjulian struct proc *p = td->td_proc; 377137613Srwatson struct shmid_kernel *shmseg; 378281071Skib struct shmmap_state *shmmap_s; 3792729Sdfr vm_offset_t attach_va; 3802729Sdfr vm_prot_t prot; 3812729Sdfr vm_size_t size; 382343426Skib int cow, error, find_space, i, rv; 3832729Sdfr 384280323Skib SYSVSHM_ASSERT_LOCKED(); 385298585Sjamie rpr = shm_find_prison(td->td_ucred); 386298585Sjamie if (rpr == NULL) 38791703Sjhb return (ENOSYS); 388100512Salfred shmmap_s = p->p_vmspace->vm_shm; 3892729Sdfr if (shmmap_s == NULL) { 390189398Skib shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state), 391189398Skib M_SHM, M_WAITOK); 392280323Skib for (i = 0; i < shminfo.shmseg; i++) 393280323Skib shmmap_s[i].shmid = -1; 394280323Skib KASSERT(p->p_vmspace->vm_shm == NULL, ("raced")); 395280323Skib p->p_vmspace->vm_shm = shmmap_s; 3962729Sdfr } 397298585Sjamie shmseg = shm_find_segment(rpr, shmid, true); 398280323Skib if (shmseg == NULL) 399280323Skib return (EINVAL); 400137613Srwatson error = ipcperm(td, &shmseg->u.shm_perm, 401114724Smbr (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); 402280323Skib if (error != 0) 403280323Skib return (error); 404140617Srwatson#ifdef MAC 405172930Srwatson error = mac_sysvshm_check_shmat(td->td_ucred, shmseg, shmflg); 406162468Srwatson if (error != 0) 407280323Skib return (error); 408140617Srwatson#endif 4092729Sdfr for (i = 0; i < shminfo.shmseg; i++) { 4102729Sdfr if (shmmap_s->shmid == -1) 4112729Sdfr break; 4122729Sdfr shmmap_s++; 4132729Sdfr } 414280323Skib if (i >= shminfo.shmseg) 415280323Skib return (EMFILE); 416194910Sjhb size = round_page(shmseg->u.shm_segsz); 4172729Sdfr prot = VM_PROT_READ; 418343426Skib cow = MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL; 419114724Smbr if ((shmflg & SHM_RDONLY) == 0) 4202729Sdfr prot |= VM_PROT_WRITE; 421280323Skib if (shmaddr != NULL) { 422280323Skib if ((shmflg & SHM_RND) != 0) 423298433Spfg attach_va = rounddown2((vm_offset_t)shmaddr, SHMLBA); 424280323Skib else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) 425114724Smbr attach_va = (vm_offset_t)shmaddr; 426280323Skib else 427280323Skib return (EINVAL); 428343426Skib if ((shmflg & SHM_REMAP) != 0) 429343426Skib cow |= MAP_REMAP; 430343426Skib find_space = VMFS_NO_SPACE; 4312729Sdfr } else { 43277104Sdd /* 43377104Sdd * This is just a hint to vm_map_find() about where to 43477104Sdd * put it. 43577104Sdd */ 436130730Stjr attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr + 437285056Smjg lim_max(td, RLIMIT_DATA)); 438343426Skib find_space = VMFS_OPTIMAL_SPACE; 4392729Sdfr } 44018098Sdyson 441194910Sjhb vm_object_reference(shmseg->object); 442270883Salc rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va, 443343426Skib size, 0, find_space, prot, prot, cow); 44418098Sdyson if (rv != KERN_SUCCESS) { 445194910Sjhb vm_object_deallocate(shmseg->object); 446280323Skib return (ENOMEM); 44718098Sdyson } 44818231Sdyson 4492729Sdfr shmmap_s->va = attach_va; 450114724Smbr shmmap_s->shmid = shmid; 451137613Srwatson shmseg->u.shm_lpid = p->p_pid; 452137613Srwatson shmseg->u.shm_atime = time_second; 453137613Srwatson shmseg->u.shm_nattch++; 45483366Sjulian td->td_retval[0] = attach_va; 45582607Sdillon return (error); 4562729Sdfr} 4572729Sdfr 458122201Srwatsonint 459280323Skibkern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg) 460114724Smbr{ 461280323Skib int error; 462280323Skib 463280323Skib SYSVSHM_LOCK(); 464280323Skib error = kern_shmat_locked(td, shmid, shmaddr, shmflg); 465280323Skib SYSVSHM_UNLOCK(); 466280323Skib return (error); 467114724Smbr} 468114724Smbr 469280323Skib#ifndef _SYS_SYSPROTO_H_ 470280323Skibstruct shmat_args { 471280323Skib int shmid; 472280323Skib const void *shmaddr; 473280323Skib int shmflg; 474280323Skib}; 475280323Skib#endif 4762729Sdfrint 477280323Skibsys_shmat(struct thread *td, struct shmat_args *uap) 4782729Sdfr{ 479280323Skib 480280323Skib return (kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg)); 481280323Skib} 482280323Skib 483280323Skibstatic int 484280323Skibkern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf, 485280323Skib size_t *bufsz) 486280323Skib{ 487298585Sjamie struct prison *rpr; 488137613Srwatson struct shmid_kernel *shmseg; 489280323Skib struct shmid_ds *shmidp; 490280323Skib struct shm_info shm_info; 491280323Skib int error; 4922729Sdfr 493280323Skib SYSVSHM_ASSERT_LOCKED(); 494280323Skib 495298585Sjamie rpr = shm_find_prison(td->td_ucred); 496298585Sjamie if (rpr == NULL) 49791703Sjhb return (ENOSYS); 498114724Smbr 499114724Smbr switch (cmd) { 500176221Scsjp /* 501176221Scsjp * It is possible that kern_shmctl is being called from the Linux ABI 502176221Scsjp * layer, in which case, we will need to implement IPC_INFO. It should 503176221Scsjp * be noted that other shmctl calls will be funneled through here for 504176221Scsjp * Linix binaries as well. 505176221Scsjp * 506176221Scsjp * NB: The Linux ABI layer will convert this data to structure(s) more 507176221Scsjp * consistent with the Linux ABI. 508176221Scsjp */ 50985623Smr case IPC_INFO: 510114724Smbr memcpy(buf, &shminfo, sizeof(shminfo)); 511114724Smbr if (bufsz) 512114724Smbr *bufsz = sizeof(shminfo); 51385623Smr td->td_retval[0] = shmalloced; 514280323Skib return (0); 51585623Smr case SHM_INFO: { 51685623Smr shm_info.used_ids = shm_nused; 51785623Smr shm_info.shm_rss = 0; /*XXX where to get from ? */ 51885623Smr shm_info.shm_tot = 0; /*XXX where to get from ? */ 51985623Smr shm_info.shm_swp = 0; /*XXX where to get from ? */ 52085623Smr shm_info.swap_attempts = 0; /*XXX where to get from ? */ 52185623Smr shm_info.swap_successes = 0; /*XXX where to get from ? */ 522114724Smbr memcpy(buf, &shm_info, sizeof(shm_info)); 523280323Skib if (bufsz != NULL) 524114724Smbr *bufsz = sizeof(shm_info); 52585623Smr td->td_retval[0] = shmalloced; 526280323Skib return (0); 52785623Smr } 52885623Smr } 529298585Sjamie shmseg = shm_find_segment(rpr, shmid, cmd != SHM_STAT); 530280323Skib if (shmseg == NULL) 531280323Skib return (EINVAL); 532140617Srwatson#ifdef MAC 533172930Srwatson error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd); 534162468Srwatson if (error != 0) 535280323Skib return (error); 536140617Srwatson#endif 537114724Smbr switch (cmd) { 53885623Smr case SHM_STAT: 5392729Sdfr case IPC_STAT: 540298585Sjamie shmidp = (struct shmid_ds *)buf; 541137613Srwatson error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); 542280323Skib if (error != 0) 543280323Skib return (error); 544298585Sjamie memcpy(shmidp, &shmseg->u, sizeof(struct shmid_ds)); 545298585Sjamie if (td->td_ucred->cr_prison != shmseg->cred->cr_prison) 546298585Sjamie shmidp->shm_perm.key = IPC_PRIVATE; 547280323Skib if (bufsz != NULL) 548114724Smbr *bufsz = sizeof(struct shmid_ds); 549280323Skib if (cmd == SHM_STAT) { 550280323Skib td->td_retval[0] = IXSEQ_TO_IPCID(shmid, 551280323Skib shmseg->u.shm_perm); 552280323Skib } 5532729Sdfr break; 554280323Skib case IPC_SET: 555280323Skib shmidp = (struct shmid_ds *)buf; 556137613Srwatson error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); 557280323Skib if (error != 0) 558280323Skib return (error); 559280323Skib shmseg->u.shm_perm.uid = shmidp->shm_perm.uid; 560280323Skib shmseg->u.shm_perm.gid = shmidp->shm_perm.gid; 561137613Srwatson shmseg->u.shm_perm.mode = 562137613Srwatson (shmseg->u.shm_perm.mode & ~ACCESSPERMS) | 563280323Skib (shmidp->shm_perm.mode & ACCESSPERMS); 564137613Srwatson shmseg->u.shm_ctime = time_second; 5652729Sdfr break; 5662729Sdfr case IPC_RMID: 567137613Srwatson error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); 568280323Skib if (error != 0) 569280323Skib return (error); 570298585Sjamie shm_remove(shmseg, IPCID_TO_IX(shmid)); 5712729Sdfr break; 5722729Sdfr#if 0 5732729Sdfr case SHM_LOCK: 5742729Sdfr case SHM_UNLOCK: 5752729Sdfr#endif 5762729Sdfr default: 57782607Sdillon error = EINVAL; 57882607Sdillon break; 5792729Sdfr } 58082607Sdillon return (error); 5812729Sdfr} 5822729Sdfr 583280323Skibint 584280323Skibkern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz) 585280323Skib{ 586280323Skib int error; 587280323Skib 588280323Skib SYSVSHM_LOCK(); 589280323Skib error = kern_shmctl_locked(td, shmid, cmd, buf, bufsz); 590280323Skib SYSVSHM_UNLOCK(); 591280323Skib return (error); 592280323Skib} 593280323Skib 594280323Skib 595194832Sjhb#ifndef _SYS_SYSPROTO_H_ 596194832Sjhbstruct shmctl_args { 597194832Sjhb int shmid; 598194832Sjhb int cmd; 599194832Sjhb struct shmid_ds *buf; 600194832Sjhb}; 601194832Sjhb#endif 602114724Smbrint 603280323Skibsys_shmctl(struct thread *td, struct shmctl_args *uap) 604114724Smbr{ 605285057Smjg int error; 606114724Smbr struct shmid_ds buf; 607114724Smbr size_t bufsz; 608285057Smjg 609176221Scsjp /* 610176221Scsjp * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support 611176221Scsjp * Linux binaries. If we see the call come through the FreeBSD ABI, 612176221Scsjp * return an error back to the user since we do not to support this. 613176221Scsjp */ 614176221Scsjp if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO || 615176221Scsjp uap->cmd == SHM_STAT) 616176221Scsjp return (EINVAL); 617176221Scsjp 618114724Smbr /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ 619114724Smbr if (uap->cmd == IPC_SET) { 620114724Smbr if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds)))) 621114724Smbr goto done; 622114724Smbr } 623285057Smjg 624122088Sfjoe error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); 625114724Smbr if (error) 626114724Smbr goto done; 627285057Smjg 628114724Smbr /* Cases in which we need to copyout */ 629114724Smbr switch (uap->cmd) { 630114724Smbr case IPC_STAT: 631114724Smbr error = copyout(&buf, uap->buf, bufsz); 632114724Smbr break; 633114724Smbr } 634114724Smbr 635114724Smbrdone: 636114724Smbr if (error) { 637114724Smbr /* Invalidate the return value */ 638114724Smbr td->td_retval[0] = -1; 639114724Smbr } 640114724Smbr return (error); 641114724Smbr} 642114724Smbr 643114724Smbr 6442729Sdfrstatic int 645367601Sbrooksshmget_existing(struct thread *td, size_t size, int shmflg, int mode, 646280323Skib int segnum) 6472729Sdfr{ 648137613Srwatson struct shmid_kernel *shmseg; 649280325Scognet#ifdef MAC 6502729Sdfr int error; 651280325Scognet#endif 6522729Sdfr 653280323Skib SYSVSHM_ASSERT_LOCKED(); 654280323Skib KASSERT(segnum >= 0 && segnum < shmalloced, 655280323Skib ("segnum %d shmalloced %d", segnum, shmalloced)); 6562729Sdfr shmseg = &shmsegs[segnum]; 657367601Sbrooks if ((shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) 658101891Salfred return (EEXIST); 659140617Srwatson#ifdef MAC 660367601Sbrooks error = mac_sysvshm_check_shmget(td->td_ucred, shmseg, shmflg); 661162468Srwatson if (error != 0) 662150937Srwatson return (error); 663140617Srwatson#endif 664367601Sbrooks if (size != 0 && size > shmseg->u.shm_segsz) 665101891Salfred return (EINVAL); 666137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); 667101891Salfred return (0); 6682729Sdfr} 6692729Sdfr 6702729Sdfrstatic int 671367601Sbrooksshmget_allocate_segment(struct thread *td, key_t key, size_t size, int mode) 6722729Sdfr{ 67391406Sjhb struct ucred *cred = td->td_ucred; 674137613Srwatson struct shmid_kernel *shmseg; 675131857Salc vm_object_t shm_object; 676280323Skib int i, segnum; 6778876Srgrimes 678280323Skib SYSVSHM_ASSERT_LOCKED(); 67979224Sdillon 680367601Sbrooks if (size < shminfo.shmmin || size > shminfo.shmmax) 681101891Salfred return (EINVAL); 68277104Sdd if (shm_nused >= shminfo.shmmni) /* Any shmids left? */ 683101891Salfred return (ENOSPC); 684367601Sbrooks size = round_page(size); 6852729Sdfr if (shm_committed + btoc(size) > shminfo.shmall) 686101891Salfred return (ENOMEM); 6872729Sdfr if (shm_last_free < 0) { 68877104Sdd shmrealloc(); /* Maybe expand the shmsegs[] array. */ 68958820Speter for (i = 0; i < shmalloced; i++) 690137613Srwatson if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE) 6912729Sdfr break; 69258820Speter if (i == shmalloced) 693101891Salfred return (ENOSPC); 6942729Sdfr segnum = i; 6952729Sdfr } else { 6962729Sdfr segnum = shm_last_free; 6972729Sdfr shm_last_free = -1; 6982729Sdfr } 699280323Skib KASSERT(segnum >= 0 && segnum < shmalloced, 700280323Skib ("segnum %d shmalloced %d", segnum, shmalloced)); 7012729Sdfr shmseg = &shmsegs[segnum]; 702223825Strasz#ifdef RACCT 703282213Strasz if (racct_enable) { 704282213Strasz PROC_LOCK(td->td_proc); 705282213Strasz if (racct_add(td->td_proc, RACCT_NSHM, 1)) { 706282213Strasz PROC_UNLOCK(td->td_proc); 707282213Strasz return (ENOSPC); 708282213Strasz } 709282213Strasz if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) { 710282213Strasz racct_sub(td->td_proc, RACCT_NSHM, 1); 711282213Strasz PROC_UNLOCK(td->td_proc); 712282213Strasz return (ENOMEM); 713282213Strasz } 714220398Strasz PROC_UNLOCK(td->td_proc); 715220398Strasz } 716223825Strasz#endif 717280323Skib 7182729Sdfr /* 71918199Sdyson * We make sure that we have allocated a pager before we need 72018199Sdyson * to. 72118199Sdyson */ 722194766Skib shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP, 723194766Skib 0, size, VM_PROT_DEFAULT, 0, cred); 724220398Strasz if (shm_object == NULL) { 725223825Strasz#ifdef RACCT 726282213Strasz if (racct_enable) { 727282213Strasz PROC_LOCK(td->td_proc); 728282213Strasz racct_sub(td->td_proc, RACCT_NSHM, 1); 729282213Strasz racct_sub(td->td_proc, RACCT_SHMSIZE, size); 730282213Strasz PROC_UNLOCK(td->td_proc); 731282213Strasz } 732223825Strasz#endif 733194766Skib return (ENOMEM); 734220398Strasz } 735278697Salc shm_object->pg_color = 0; 736248084Sattilio VM_OBJECT_WLOCK(shm_object); 737131857Salc vm_object_clear_flag(shm_object, OBJ_ONEMAPPING); 738278697Salc vm_object_set_flag(shm_object, OBJ_COLORED | OBJ_NOSPLIT); 739248084Sattilio VM_OBJECT_WUNLOCK(shm_object); 74035669Sdyson 741194910Sjhb shmseg->object = shm_object; 742137613Srwatson shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid; 743137613Srwatson shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid; 744280323Skib shmseg->u.shm_perm.mode = (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; 745367601Sbrooks shmseg->u.shm_perm.key = key; 746280323Skib shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff; 747220399Strasz shmseg->cred = crhold(cred); 748367601Sbrooks shmseg->u.shm_segsz = size; 749137613Srwatson shmseg->u.shm_cpid = td->td_proc->p_pid; 750137613Srwatson shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0; 751137613Srwatson shmseg->u.shm_atime = shmseg->u.shm_dtime = 0; 752140617Srwatson#ifdef MAC 753172930Srwatson mac_sysvshm_create(cred, shmseg); 754140617Srwatson#endif 755137613Srwatson shmseg->u.shm_ctime = time_second; 7562729Sdfr shm_committed += btoc(size); 7572729Sdfr shm_nused++; 758280323Skib td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); 759280323Skib 760101891Salfred return (0); 7612729Sdfr} 7622729Sdfr 763194832Sjhb#ifndef _SYS_SYSPROTO_H_ 764194832Sjhbstruct shmget_args { 765194832Sjhb key_t key; 766194832Sjhb size_t size; 767194832Sjhb int shmflg; 768194832Sjhb}; 769194832Sjhb#endif 7702729Sdfrint 771280323Skibsys_shmget(struct thread *td, struct shmget_args *uap) 7722729Sdfr{ 77382607Sdillon int segnum, mode; 77482607Sdillon int error; 7752729Sdfr 776298585Sjamie if (shm_find_prison(td->td_ucred) == NULL) 77791703Sjhb return (ENOSYS); 7782729Sdfr mode = uap->shmflg & ACCESSPERMS; 779280323Skib SYSVSHM_LOCK(); 780280323Skib if (uap->key == IPC_PRIVATE) { 781367601Sbrooks error = shmget_allocate_segment(td, uap->key, uap->size, mode); 782280323Skib } else { 783298585Sjamie segnum = shm_find_segment_by_key(td->td_ucred->cr_prison, 784298585Sjamie uap->key); 785280323Skib if (segnum >= 0) 786367601Sbrooks error = shmget_existing(td, uap->size, uap->shmflg, 787367601Sbrooks mode, segnum); 788280323Skib else if ((uap->shmflg & IPC_CREAT) == 0) 78982607Sdillon error = ENOENT; 790280323Skib else 791367601Sbrooks error = shmget_allocate_segment(td, uap->key, 792367601Sbrooks uap->size, mode); 7932729Sdfr } 794280323Skib SYSVSHM_UNLOCK(); 79582607Sdillon return (error); 7962729Sdfr} 7972729Sdfr 79869449Salfredstatic void 799280323Skibshmfork_myhook(struct proc *p1, struct proc *p2) 8002729Sdfr{ 8012729Sdfr struct shmmap_state *shmmap_s; 8022729Sdfr size_t size; 8032729Sdfr int i; 8042729Sdfr 805280323Skib SYSVSHM_LOCK(); 8062729Sdfr size = shminfo.shmseg * sizeof(struct shmmap_state); 807111119Simp shmmap_s = malloc(size, M_SHM, M_WAITOK); 808100511Salfred bcopy(p1->p_vmspace->vm_shm, shmmap_s, size); 809100511Salfred p2->p_vmspace->vm_shm = shmmap_s; 810280323Skib for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { 811280323Skib if (shmmap_s->shmid != -1) { 812280323Skib KASSERT(IPCID_TO_IX(shmmap_s->shmid) >= 0 && 813280323Skib IPCID_TO_IX(shmmap_s->shmid) < shmalloced, 814280323Skib ("segnum %d shmalloced %d", 815280323Skib IPCID_TO_IX(shmmap_s->shmid), shmalloced)); 816137613Srwatson shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++; 817280323Skib } 818280323Skib } 819280323Skib SYSVSHM_UNLOCK(); 8202729Sdfr} 8212729Sdfr 82269449Salfredstatic void 823109205Sdillonshmexit_myhook(struct vmspace *vm) 8242729Sdfr{ 825109205Sdillon struct shmmap_state *base, *shm; 8262729Sdfr int i; 8272729Sdfr 828280323Skib base = vm->vm_shm; 829280323Skib if (base != NULL) { 830109205Sdillon vm->vm_shm = NULL; 831280323Skib SYSVSHM_LOCK(); 832109205Sdillon for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { 833109205Sdillon if (shm->shmid != -1) 834109205Sdillon shm_delete_mapping(vm, shm); 835109205Sdillon } 836280323Skib SYSVSHM_UNLOCK(); 837109205Sdillon free(base, M_SHM); 838109205Sdillon } 8392729Sdfr} 8402729Sdfr 84158820Speterstatic void 84258820Spetershmrealloc(void) 84358820Speter{ 844280323Skib struct shmid_kernel *newsegs; 84558820Speter int i; 84658820Speter 847280323Skib SYSVSHM_ASSERT_LOCKED(); 848280323Skib 84958820Speter if (shmalloced >= shminfo.shmmni) 85058820Speter return; 85158820Speter 852329177Sbrooks newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, 853329177Sbrooks M_WAITOK | M_ZERO); 85458820Speter for (i = 0; i < shmalloced; i++) 85558820Speter bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0])); 85658820Speter for (; i < shminfo.shmmni; i++) { 857285055Smjg newsegs[i].u.shm_perm.mode = SHMSEG_FREE; 858285055Smjg newsegs[i].u.shm_perm.seq = 0; 859140617Srwatson#ifdef MAC 860285055Smjg mac_sysvshm_init(&newsegs[i]); 861140617Srwatson#endif 86258820Speter } 86358820Speter free(shmsegs, M_SHM); 86458820Speter shmsegs = newsegs; 86558820Speter shmalloced = shminfo.shmmni; 86658820Speter} 86758820Speter 868205323Skibstatic struct syscall_helper_data shm_syscalls[] = { 869205323Skib SYSCALL_INIT_HELPER(shmat), 870205323Skib SYSCALL_INIT_HELPER(shmctl), 871205323Skib SYSCALL_INIT_HELPER(shmdt), 872205323Skib SYSCALL_INIT_HELPER(shmget), 873205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 874205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 875225617Skmacy SYSCALL_INIT_HELPER_COMPAT(freebsd7_shmctl), 876205323Skib#endif 877205323Skib#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 878205323Skib SYSCALL_INIT_HELPER(shmsys), 879205323Skib#endif 880205323Skib SYSCALL_INIT_LAST 881205323Skib}; 882205323Skib 883205323Skib#ifdef COMPAT_FREEBSD32 884205323Skib#include <compat/freebsd32/freebsd32.h> 885205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 886205323Skib#include <compat/freebsd32/freebsd32_proto.h> 887205323Skib#include <compat/freebsd32/freebsd32_signal.h> 888205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 889205323Skib#include <compat/freebsd32/freebsd32_util.h> 890205323Skib 891205323Skibstatic struct syscall_helper_data shm32_syscalls[] = { 892225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(shmat), 893225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(shmdt), 894225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(shmget), 895205323Skib SYSCALL32_INIT_HELPER(freebsd32_shmsys), 896205323Skib SYSCALL32_INIT_HELPER(freebsd32_shmctl), 897205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 898205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 899205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_shmctl), 900205323Skib#endif 901205323Skib SYSCALL_INIT_LAST 902205323Skib}; 903205323Skib#endif 904205323Skib 905205323Skibstatic int 906280323Skibshminit(void) 9072729Sdfr{ 908298585Sjamie struct prison *pr; 909298661Scem void **rsv; 910205323Skib int i, error; 911298585Sjamie osd_method_t methods[PR_MAXMETHOD] = { 912298585Sjamie [PR_METHOD_CHECK] = shm_prison_check, 913298585Sjamie [PR_METHOD_SET] = shm_prison_set, 914298585Sjamie [PR_METHOD_GET] = shm_prison_get, 915298585Sjamie [PR_METHOD_REMOVE] = shm_prison_remove, 916298585Sjamie }; 91758820Speter 918198449Sru#ifndef BURN_BRIDGES 919198449Sru if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0) 920198449Sru printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n"); 921198449Sru#endif 922267992Shselasky if (shminfo.shmmax == SHMMAX) { 923231195Spjd /* Initialize shmmax dealing with possible overflow. */ 924267992Shselasky for (i = PAGE_SIZE; i != 0; i--) { 925231195Spjd shminfo.shmmax = shminfo.shmall * i; 926267992Shselasky if ((shminfo.shmmax / shminfo.shmall) == (u_long)i) 927231195Spjd break; 928231195Spjd } 929110982Salfred } 93058820Speter shmalloced = shminfo.shmmni; 931329177Sbrooks shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, 932329177Sbrooks M_WAITOK|M_ZERO); 93358820Speter for (i = 0; i < shmalloced; i++) { 934137613Srwatson shmsegs[i].u.shm_perm.mode = SHMSEG_FREE; 935137613Srwatson shmsegs[i].u.shm_perm.seq = 0; 936140617Srwatson#ifdef MAC 937172930Srwatson mac_sysvshm_init(&shmsegs[i]); 938140617Srwatson#endif 9392729Sdfr } 9402729Sdfr shm_last_free = 0; 9412729Sdfr shm_nused = 0; 9422729Sdfr shm_committed = 0; 943280323Skib sx_init(&sysvshmsx, "sysvshmsx"); 94469449Salfred shmexit_hook = &shmexit_myhook; 94569449Salfred shmfork_hook = &shmfork_myhook; 946205323Skib 947298585Sjamie /* Set current prisons according to their allow.sysvipc. */ 948298585Sjamie shm_prison_slot = osd_jail_register(NULL, methods); 949298585Sjamie rsv = osd_reserve(shm_prison_slot); 950298585Sjamie prison_lock(&prison0); 951298585Sjamie (void)osd_jail_set_reserved(&prison0, shm_prison_slot, rsv, &prison0); 952298585Sjamie prison_unlock(&prison0); 953298585Sjamie rsv = NULL; 954298585Sjamie sx_slock(&allprison_lock); 955298585Sjamie TAILQ_FOREACH(pr, &allprison, pr_list) { 956298585Sjamie if (rsv == NULL) 957298585Sjamie rsv = osd_reserve(shm_prison_slot); 958298585Sjamie prison_lock(pr); 959298585Sjamie if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { 960298585Sjamie (void)osd_jail_set_reserved(pr, shm_prison_slot, rsv, 961298585Sjamie &prison0); 962298585Sjamie rsv = NULL; 963298585Sjamie } 964298585Sjamie prison_unlock(pr); 965298585Sjamie } 966298585Sjamie if (rsv != NULL) 967298585Sjamie osd_free_reserved(rsv); 968298585Sjamie sx_sunlock(&allprison_lock); 969298585Sjamie 970273707Smjg error = syscall_helper_register(shm_syscalls, SY_THR_STATIC_KLD); 971205323Skib if (error != 0) 972205323Skib return (error); 973205323Skib#ifdef COMPAT_FREEBSD32 974273707Smjg error = syscall32_helper_register(shm32_syscalls, SY_THR_STATIC_KLD); 975205323Skib if (error != 0) 976205323Skib return (error); 977205323Skib#endif 978205323Skib return (0); 9792729Sdfr} 98069449Salfred 98169449Salfredstatic int 982280323Skibshmunload(void) 98369449Salfred{ 984285057Smjg int i; 98569449Salfred 98669449Salfred if (shm_nused > 0) 98769449Salfred return (EBUSY); 98869449Salfred 989205323Skib#ifdef COMPAT_FREEBSD32 990205323Skib syscall32_helper_unregister(shm32_syscalls); 991205323Skib#endif 992205323Skib syscall_helper_unregister(shm_syscalls); 993298585Sjamie if (shm_prison_slot != 0) 994298585Sjamie osd_jail_deregister(shm_prison_slot); 995205323Skib 996209580Skib for (i = 0; i < shmalloced; i++) { 997140617Srwatson#ifdef MAC 998172930Srwatson mac_sysvshm_destroy(&shmsegs[i]); 999140617Srwatson#endif 1000209580Skib /* 1001209580Skib * Objects might be still mapped into the processes 1002209580Skib * address spaces. Actual free would happen on the 1003209580Skib * last mapping destruction. 1004209580Skib */ 1005209580Skib if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE) 1006209580Skib vm_object_deallocate(shmsegs[i].object); 1007209580Skib } 100869449Salfred free(shmsegs, M_SHM); 100969449Salfred shmexit_hook = NULL; 101069449Salfred shmfork_hook = NULL; 1011280323Skib sx_destroy(&sysvshmsx); 101269449Salfred return (0); 101369449Salfred} 101469449Salfred 101569449Salfredstatic int 101677461Sddsysctl_shmsegs(SYSCTL_HANDLER_ARGS) 101777461Sdd{ 1018298656Sjamie struct shmid_kernel tshmseg; 1019329177Sbrooks#ifdef COMPAT_FREEBSD32 1020329177Sbrooks struct shmid_kernel32 tshmseg32; 1021329177Sbrooks#endif 1022298656Sjamie struct prison *pr, *rpr; 1023329177Sbrooks void *outaddr; 1024329177Sbrooks size_t outsize; 1025298585Sjamie int error, i; 102677461Sdd 1027280323Skib SYSVSHM_LOCK(); 1028298656Sjamie pr = req->td->td_ucred->cr_prison; 1029298585Sjamie rpr = shm_find_prison(req->td->td_ucred); 1030298656Sjamie error = 0; 1031298585Sjamie for (i = 0; i < shmalloced; i++) { 1032298656Sjamie if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || 1033298585Sjamie rpr == NULL || shm_prison_cansee(rpr, &shmsegs[i]) != 0) { 1034298656Sjamie bzero(&tshmseg, sizeof(tshmseg)); 1035298656Sjamie tshmseg.u.shm_perm.mode = SHMSEG_FREE; 1036298656Sjamie } else { 1037298656Sjamie tshmseg = shmsegs[i]; 1038298656Sjamie if (tshmseg.cred->cr_prison != pr) 1039298656Sjamie tshmseg.u.shm_perm.key = IPC_PRIVATE; 1040298585Sjamie } 1041329177Sbrooks#ifdef COMPAT_FREEBSD32 1042329177Sbrooks if (SV_CURPROC_FLAG(SV_ILP32)) { 1043329177Sbrooks bzero(&tshmseg32, sizeof(tshmseg32)); 1044329177Sbrooks freebsd32_ipcperm_out(&tshmseg.u.shm_perm, 1045329177Sbrooks &tshmseg32.u.shm_perm); 1046329177Sbrooks CP(tshmseg, tshmseg32, u.shm_segsz); 1047329177Sbrooks CP(tshmseg, tshmseg32, u.shm_lpid); 1048329177Sbrooks CP(tshmseg, tshmseg32, u.shm_cpid); 1049329177Sbrooks CP(tshmseg, tshmseg32, u.shm_nattch); 1050329177Sbrooks CP(tshmseg, tshmseg32, u.shm_atime); 1051329177Sbrooks CP(tshmseg, tshmseg32, u.shm_dtime); 1052329177Sbrooks CP(tshmseg, tshmseg32, u.shm_ctime); 1053329177Sbrooks /* Don't copy object, label, or cred */ 1054329177Sbrooks outaddr = &tshmseg32; 1055329177Sbrooks outsize = sizeof(tshmseg32); 1056329177Sbrooks } else 1057329177Sbrooks#endif 1058329177Sbrooks { 1059329177Sbrooks tshmseg.object = NULL; 1060329177Sbrooks tshmseg.label = NULL; 1061329177Sbrooks tshmseg.cred = NULL; 1062329177Sbrooks outaddr = &tshmseg; 1063329177Sbrooks outsize = sizeof(tshmseg); 1064329177Sbrooks } 1065329177Sbrooks error = SYSCTL_OUT(req, outaddr, outsize); 1066298656Sjamie if (error != 0) 1067298656Sjamie break; 1068298585Sjamie } 1069280323Skib SYSVSHM_UNLOCK(); 1070280323Skib return (error); 107177461Sdd} 107277461Sdd 1073298585Sjamiestatic int 1074298585Sjamieshm_prison_check(void *obj, void *data) 1075298585Sjamie{ 1076298585Sjamie struct prison *pr = obj; 1077298585Sjamie struct prison *prpr; 1078298585Sjamie struct vfsoptlist *opts = data; 1079298585Sjamie int error, jsys; 1080298585Sjamie 1081298585Sjamie /* 1082298585Sjamie * sysvshm is a jailsys integer. 1083298585Sjamie * It must be "disable" if the parent jail is disabled. 1084298585Sjamie */ 1085298585Sjamie error = vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys)); 1086298585Sjamie if (error != ENOENT) { 1087298585Sjamie if (error != 0) 1088298585Sjamie return (error); 1089298585Sjamie switch (jsys) { 1090298585Sjamie case JAIL_SYS_DISABLE: 1091298585Sjamie break; 1092298585Sjamie case JAIL_SYS_NEW: 1093298585Sjamie case JAIL_SYS_INHERIT: 1094298585Sjamie prison_lock(pr->pr_parent); 1095298585Sjamie prpr = osd_jail_get(pr->pr_parent, shm_prison_slot); 1096298585Sjamie prison_unlock(pr->pr_parent); 1097298585Sjamie if (prpr == NULL) 1098298585Sjamie return (EPERM); 1099298585Sjamie break; 1100298585Sjamie default: 1101298585Sjamie return (EINVAL); 1102298585Sjamie } 1103298585Sjamie } 1104298585Sjamie 1105298585Sjamie return (0); 1106298585Sjamie} 1107298585Sjamie 1108298585Sjamiestatic int 1109298585Sjamieshm_prison_set(void *obj, void *data) 1110298585Sjamie{ 1111298585Sjamie struct prison *pr = obj; 1112298585Sjamie struct prison *tpr, *orpr, *nrpr, *trpr; 1113298585Sjamie struct vfsoptlist *opts = data; 1114298585Sjamie void *rsv; 1115298585Sjamie int jsys, descend; 1116298585Sjamie 1117298585Sjamie /* 1118298585Sjamie * sysvshm controls which jail is the root of the associated segments 1119298585Sjamie * (this jail or same as the parent), or if the feature is available 1120298585Sjamie * at all. 1121298585Sjamie */ 1122298585Sjamie if (vfs_copyopt(opts, "sysvshm", &jsys, sizeof(jsys)) == ENOENT) 1123298585Sjamie jsys = vfs_flagopt(opts, "allow.sysvipc", NULL, 0) 1124298585Sjamie ? JAIL_SYS_INHERIT 1125298585Sjamie : vfs_flagopt(opts, "allow.nosysvipc", NULL, 0) 1126298585Sjamie ? JAIL_SYS_DISABLE 1127298585Sjamie : -1; 1128298585Sjamie if (jsys == JAIL_SYS_DISABLE) { 1129298585Sjamie prison_lock(pr); 1130298585Sjamie orpr = osd_jail_get(pr, shm_prison_slot); 1131298585Sjamie if (orpr != NULL) 1132298585Sjamie osd_jail_del(pr, shm_prison_slot); 1133298585Sjamie prison_unlock(pr); 1134298585Sjamie if (orpr != NULL) { 1135298585Sjamie if (orpr == pr) 1136298585Sjamie shm_prison_cleanup(pr); 1137298585Sjamie /* Disable all child jails as well. */ 1138298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1139298585Sjamie prison_lock(tpr); 1140298585Sjamie trpr = osd_jail_get(tpr, shm_prison_slot); 1141298585Sjamie if (trpr != NULL) { 1142298585Sjamie osd_jail_del(tpr, shm_prison_slot); 1143298585Sjamie prison_unlock(tpr); 1144298585Sjamie if (trpr == tpr) 1145298585Sjamie shm_prison_cleanup(tpr); 1146298585Sjamie } else { 1147298585Sjamie prison_unlock(tpr); 1148298585Sjamie descend = 0; 1149298585Sjamie } 1150298585Sjamie } 1151298585Sjamie } 1152298585Sjamie } else if (jsys != -1) { 1153298585Sjamie if (jsys == JAIL_SYS_NEW) 1154298585Sjamie nrpr = pr; 1155298585Sjamie else { 1156298585Sjamie prison_lock(pr->pr_parent); 1157298585Sjamie nrpr = osd_jail_get(pr->pr_parent, shm_prison_slot); 1158298585Sjamie prison_unlock(pr->pr_parent); 1159298585Sjamie } 1160298585Sjamie rsv = osd_reserve(shm_prison_slot); 1161298585Sjamie prison_lock(pr); 1162298585Sjamie orpr = osd_jail_get(pr, shm_prison_slot); 1163298585Sjamie if (orpr != nrpr) 1164298585Sjamie (void)osd_jail_set_reserved(pr, shm_prison_slot, rsv, 1165298585Sjamie nrpr); 1166298585Sjamie else 1167298585Sjamie osd_free_reserved(rsv); 1168298585Sjamie prison_unlock(pr); 1169298585Sjamie if (orpr != nrpr) { 1170298585Sjamie if (orpr == pr) 1171298585Sjamie shm_prison_cleanup(pr); 1172298585Sjamie if (orpr != NULL) { 1173298585Sjamie /* Change child jails matching the old root, */ 1174298585Sjamie FOREACH_PRISON_DESCENDANT(pr, tpr, descend) { 1175298585Sjamie prison_lock(tpr); 1176298585Sjamie trpr = osd_jail_get(tpr, 1177298585Sjamie shm_prison_slot); 1178298585Sjamie if (trpr == orpr) { 1179298585Sjamie (void)osd_jail_set(tpr, 1180298585Sjamie shm_prison_slot, nrpr); 1181298585Sjamie prison_unlock(tpr); 1182298585Sjamie if (trpr == tpr) 1183298585Sjamie shm_prison_cleanup(tpr); 1184298585Sjamie } else { 1185298585Sjamie prison_unlock(tpr); 1186298585Sjamie descend = 0; 1187298585Sjamie } 1188298585Sjamie } 1189298585Sjamie } 1190298585Sjamie } 1191298585Sjamie } 1192298585Sjamie 1193298585Sjamie return (0); 1194298585Sjamie} 1195298585Sjamie 1196298585Sjamiestatic int 1197298585Sjamieshm_prison_get(void *obj, void *data) 1198298585Sjamie{ 1199298585Sjamie struct prison *pr = obj; 1200298585Sjamie struct prison *rpr; 1201298585Sjamie struct vfsoptlist *opts = data; 1202298585Sjamie int error, jsys; 1203298585Sjamie 1204298585Sjamie /* Set sysvshm based on the jail's root prison. */ 1205298585Sjamie prison_lock(pr); 1206298585Sjamie rpr = osd_jail_get(pr, shm_prison_slot); 1207298585Sjamie prison_unlock(pr); 1208298585Sjamie jsys = rpr == NULL ? JAIL_SYS_DISABLE 1209298585Sjamie : rpr == pr ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; 1210298585Sjamie error = vfs_setopt(opts, "sysvshm", &jsys, sizeof(jsys)); 1211298585Sjamie if (error == ENOENT) 1212298585Sjamie error = 0; 1213298585Sjamie return (error); 1214298585Sjamie} 1215298585Sjamie 1216298585Sjamiestatic int 1217298585Sjamieshm_prison_remove(void *obj, void *data __unused) 1218298585Sjamie{ 1219298585Sjamie struct prison *pr = obj; 1220298585Sjamie struct prison *rpr; 1221298585Sjamie 1222298585Sjamie SYSVSHM_LOCK(); 1223298585Sjamie prison_lock(pr); 1224298585Sjamie rpr = osd_jail_get(pr, shm_prison_slot); 1225298585Sjamie prison_unlock(pr); 1226298585Sjamie if (rpr == pr) 1227298585Sjamie shm_prison_cleanup(pr); 1228298585Sjamie SYSVSHM_UNLOCK(); 1229298585Sjamie return (0); 1230298585Sjamie} 1231298585Sjamie 1232298585Sjamiestatic void 1233298585Sjamieshm_prison_cleanup(struct prison *pr) 1234298585Sjamie{ 1235298585Sjamie struct shmid_kernel *shmseg; 1236298585Sjamie int i; 1237298585Sjamie 1238298585Sjamie /* Remove any segments that belong to this jail. */ 1239298585Sjamie for (i = 0; i < shmalloced; i++) { 1240298585Sjamie shmseg = &shmsegs[i]; 1241298585Sjamie if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) && 1242298585Sjamie shmseg->cred != NULL && shmseg->cred->cr_prison == pr) { 1243298585Sjamie shm_remove(shmseg, i); 1244298585Sjamie } 1245298585Sjamie } 1246298585Sjamie} 1247298585Sjamie 1248298585SjamieSYSCTL_JAIL_PARAM_SYS_NODE(sysvshm, CTLFLAG_RW, "SYSV shared memory"); 1249298585Sjamie 1250194894Sjhb#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 1251194894Sjhbstruct oshmid_ds { 1252194894Sjhb struct ipc_perm_old shm_perm; /* operation perms */ 1253194894Sjhb int shm_segsz; /* size of segment (bytes) */ 1254194894Sjhb u_short shm_cpid; /* pid, creator */ 1255194894Sjhb u_short shm_lpid; /* pid, last operation */ 1256194894Sjhb short shm_nattch; /* no. of current attaches */ 1257194894Sjhb time_t shm_atime; /* last attach time */ 1258194894Sjhb time_t shm_dtime; /* last detach time */ 1259194894Sjhb time_t shm_ctime; /* last change time */ 1260194894Sjhb void *shm_handle; /* internal handle for shm segment */ 1261194894Sjhb}; 1262194894Sjhb 1263194894Sjhbstruct oshmctl_args { 1264194894Sjhb int shmid; 1265194894Sjhb int cmd; 1266194894Sjhb struct oshmid_ds *ubuf; 1267194894Sjhb}; 1268194894Sjhb 126977461Sddstatic int 1270194959Sjhboshmctl(struct thread *td, struct oshmctl_args *uap) 1271194894Sjhb{ 1272194894Sjhb#ifdef COMPAT_43 1273194894Sjhb int error = 0; 1274298585Sjamie struct prison *rpr; 1275194894Sjhb struct shmid_kernel *shmseg; 1276194894Sjhb struct oshmid_ds outbuf; 1277194894Sjhb 1278298585Sjamie rpr = shm_find_prison(td->td_ucred); 1279298585Sjamie if (rpr == NULL) 1280194894Sjhb return (ENOSYS); 1281282084Skib if (uap->cmd != IPC_STAT) { 1282282084Skib return (freebsd7_shmctl(td, 1283282084Skib (struct freebsd7_shmctl_args *)uap)); 1284282084Skib } 1285280323Skib SYSVSHM_LOCK(); 1286298585Sjamie shmseg = shm_find_segment(rpr, uap->shmid, true); 1287194894Sjhb if (shmseg == NULL) { 1288280323Skib SYSVSHM_UNLOCK(); 1289281094Skib return (EINVAL); 1290194894Sjhb } 1291282084Skib error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); 1292282084Skib if (error != 0) { 1293282084Skib SYSVSHM_UNLOCK(); 1294282084Skib return (error); 1295282084Skib } 1296194894Sjhb#ifdef MAC 1297282084Skib error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd); 1298282084Skib if (error != 0) { 1299282084Skib SYSVSHM_UNLOCK(); 1300282084Skib return (error); 1301282084Skib } 1302194894Sjhb#endif 1303282084Skib ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm); 1304282084Skib outbuf.shm_segsz = shmseg->u.shm_segsz; 1305282084Skib outbuf.shm_cpid = shmseg->u.shm_cpid; 1306282084Skib outbuf.shm_lpid = shmseg->u.shm_lpid; 1307282084Skib outbuf.shm_nattch = shmseg->u.shm_nattch; 1308282084Skib outbuf.shm_atime = shmseg->u.shm_atime; 1309282084Skib outbuf.shm_dtime = shmseg->u.shm_dtime; 1310282084Skib outbuf.shm_ctime = shmseg->u.shm_ctime; 1311282084Skib outbuf.shm_handle = shmseg->object; 1312280323Skib SYSVSHM_UNLOCK(); 1313285057Smjg return (copyout(&outbuf, uap->ubuf, sizeof(outbuf))); 1314194894Sjhb#else 1315194894Sjhb return (EINVAL); 1316194894Sjhb#endif 1317194894Sjhb} 1318194894Sjhb 1319194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1320194894Sjhbstatic sy_call_t *shmcalls[] = { 1321225617Skmacy (sy_call_t *)sys_shmat, (sy_call_t *)oshmctl, 1322225617Skmacy (sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget, 1323194910Sjhb (sy_call_t *)freebsd7_shmctl 1324194894Sjhb}; 1325194894Sjhb 1326280323Skib#ifndef _SYS_SYSPROTO_H_ 1327280323Skib/* XXX actually varargs. */ 1328280323Skibstruct shmsys_args { 1329280323Skib int which; 1330280323Skib int a2; 1331280323Skib int a3; 1332280323Skib int a4; 1333280323Skib}; 1334280323Skib#endif 1335194894Sjhbint 1336280323Skibsys_shmsys(struct thread *td, struct shmsys_args *uap) 1337194894Sjhb{ 1338194894Sjhb 1339280323Skib if (uap->which < 0 || uap->which >= nitems(shmcalls)) 1340194894Sjhb return (EINVAL); 1341285057Smjg return ((*shmcalls[uap->which])(td, &uap->a2)); 1342194894Sjhb} 1343194894Sjhb 1344194894Sjhb#endif /* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */ 1345194894Sjhb 1346205323Skib#ifdef COMPAT_FREEBSD32 1347205323Skib 1348205323Skibint 1349205323Skibfreebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap) 1350205323Skib{ 1351205323Skib 1352194910Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1353194910Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1354205323Skib switch (uap->which) { 1355205323Skib case 0: { /* shmat */ 1356205323Skib struct shmat_args ap; 1357194910Sjhb 1358205323Skib ap.shmid = uap->a2; 1359205323Skib ap.shmaddr = PTRIN(uap->a3); 1360205323Skib ap.shmflg = uap->a4; 1361205323Skib return (sysent[SYS_shmat].sy_call(td, &ap)); 1362205323Skib } 1363205323Skib case 2: { /* shmdt */ 1364205323Skib struct shmdt_args ap; 1365205323Skib 1366205323Skib ap.shmaddr = PTRIN(uap->a2); 1367205323Skib return (sysent[SYS_shmdt].sy_call(td, &ap)); 1368205323Skib } 1369205323Skib case 3: { /* shmget */ 1370205323Skib struct shmget_args ap; 1371205323Skib 1372205323Skib ap.key = uap->a2; 1373205323Skib ap.size = uap->a3; 1374205323Skib ap.shmflg = uap->a4; 1375205323Skib return (sysent[SYS_shmget].sy_call(td, &ap)); 1376205323Skib } 1377205323Skib case 4: { /* shmctl */ 1378205323Skib struct freebsd7_freebsd32_shmctl_args ap; 1379205323Skib 1380205323Skib ap.shmid = uap->a2; 1381205323Skib ap.cmd = uap->a3; 1382205323Skib ap.buf = PTRIN(uap->a4); 1383205323Skib return (freebsd7_freebsd32_shmctl(td, &ap)); 1384205323Skib } 1385205323Skib case 1: /* oshmctl */ 1386205323Skib default: 1387205323Skib return (EINVAL); 1388205323Skib } 1389205323Skib#else 1390205323Skib return (nosys(td, NULL)); 1391205323Skib#endif 1392205323Skib} 1393205323Skib 1394205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1395205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1396205323Skibint 1397205323Skibfreebsd7_freebsd32_shmctl(struct thread *td, 1398205323Skib struct freebsd7_freebsd32_shmctl_args *uap) 1399205323Skib{ 1400285057Smjg int error; 1401205323Skib union { 1402205323Skib struct shmid_ds shmid_ds; 1403205323Skib struct shm_info shm_info; 1404205323Skib struct shminfo shminfo; 1405205323Skib } u; 1406205323Skib union { 1407205323Skib struct shmid_ds32_old shmid_ds32; 1408205323Skib struct shm_info32 shm_info32; 1409205323Skib struct shminfo32 shminfo32; 1410205323Skib } u32; 1411205323Skib size_t sz; 1412205323Skib 1413205323Skib if (uap->cmd == IPC_SET) { 1414205323Skib if ((error = copyin(uap->buf, &u32.shmid_ds32, 1415205323Skib sizeof(u32.shmid_ds32)))) 1416205323Skib goto done; 1417205323Skib freebsd32_ipcperm_old_in(&u32.shmid_ds32.shm_perm, 1418205323Skib &u.shmid_ds.shm_perm); 1419205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_segsz); 1420205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_lpid); 1421205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_cpid); 1422205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_nattch); 1423205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_atime); 1424205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_dtime); 1425205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_ctime); 1426205323Skib } 1427285057Smjg 1428205323Skib error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz); 1429205323Skib if (error) 1430205323Skib goto done; 1431285057Smjg 1432205323Skib /* Cases in which we need to copyout */ 1433205323Skib switch (uap->cmd) { 1434205323Skib case IPC_INFO: 1435205323Skib CP(u.shminfo, u32.shminfo32, shmmax); 1436205323Skib CP(u.shminfo, u32.shminfo32, shmmin); 1437205323Skib CP(u.shminfo, u32.shminfo32, shmmni); 1438205323Skib CP(u.shminfo, u32.shminfo32, shmseg); 1439205323Skib CP(u.shminfo, u32.shminfo32, shmall); 1440205323Skib error = copyout(&u32.shminfo32, uap->buf, 1441205323Skib sizeof(u32.shminfo32)); 1442205323Skib break; 1443205323Skib case SHM_INFO: 1444205323Skib CP(u.shm_info, u32.shm_info32, used_ids); 1445205323Skib CP(u.shm_info, u32.shm_info32, shm_rss); 1446205323Skib CP(u.shm_info, u32.shm_info32, shm_tot); 1447205323Skib CP(u.shm_info, u32.shm_info32, shm_swp); 1448205323Skib CP(u.shm_info, u32.shm_info32, swap_attempts); 1449205323Skib CP(u.shm_info, u32.shm_info32, swap_successes); 1450205323Skib error = copyout(&u32.shm_info32, uap->buf, 1451205323Skib sizeof(u32.shm_info32)); 1452205323Skib break; 1453205323Skib case SHM_STAT: 1454205323Skib case IPC_STAT: 1455331922Skib memset(&u32.shmid_ds32, 0, sizeof(u32.shmid_ds32)); 1456205323Skib freebsd32_ipcperm_old_out(&u.shmid_ds.shm_perm, 1457205323Skib &u32.shmid_ds32.shm_perm); 1458205323Skib if (u.shmid_ds.shm_segsz > INT32_MAX) 1459205323Skib u32.shmid_ds32.shm_segsz = INT32_MAX; 1460205323Skib else 1461205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_segsz); 1462205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_lpid); 1463205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_cpid); 1464205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_nattch); 1465205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_atime); 1466205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_dtime); 1467205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_ctime); 1468205323Skib u32.shmid_ds32.shm_internal = 0; 1469205323Skib error = copyout(&u32.shmid_ds32, uap->buf, 1470205323Skib sizeof(u32.shmid_ds32)); 1471205323Skib break; 1472205323Skib } 1473205323Skib 1474205323Skibdone: 1475205323Skib if (error) { 1476205323Skib /* Invalidate the return value */ 1477205323Skib td->td_retval[0] = -1; 1478205323Skib } 1479205323Skib return (error); 1480205323Skib} 1481205323Skib#endif 1482205323Skib 1483205323Skibint 1484205323Skibfreebsd32_shmctl(struct thread *td, struct freebsd32_shmctl_args *uap) 1485205323Skib{ 1486285057Smjg int error; 1487205323Skib union { 1488205323Skib struct shmid_ds shmid_ds; 1489205323Skib struct shm_info shm_info; 1490205323Skib struct shminfo shminfo; 1491205323Skib } u; 1492205323Skib union { 1493205323Skib struct shmid_ds32 shmid_ds32; 1494205323Skib struct shm_info32 shm_info32; 1495205323Skib struct shminfo32 shminfo32; 1496205323Skib } u32; 1497205323Skib size_t sz; 1498285057Smjg 1499205323Skib if (uap->cmd == IPC_SET) { 1500205323Skib if ((error = copyin(uap->buf, &u32.shmid_ds32, 1501205323Skib sizeof(u32.shmid_ds32)))) 1502205323Skib goto done; 1503205323Skib freebsd32_ipcperm_in(&u32.shmid_ds32.shm_perm, 1504205323Skib &u.shmid_ds.shm_perm); 1505205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_segsz); 1506205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_lpid); 1507205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_cpid); 1508205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_nattch); 1509205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_atime); 1510205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_dtime); 1511205323Skib CP(u32.shmid_ds32, u.shmid_ds, shm_ctime); 1512205323Skib } 1513285057Smjg 1514205323Skib error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz); 1515205323Skib if (error) 1516205323Skib goto done; 1517285057Smjg 1518205323Skib /* Cases in which we need to copyout */ 1519205323Skib switch (uap->cmd) { 1520205323Skib case IPC_INFO: 1521205323Skib CP(u.shminfo, u32.shminfo32, shmmax); 1522205323Skib CP(u.shminfo, u32.shminfo32, shmmin); 1523205323Skib CP(u.shminfo, u32.shminfo32, shmmni); 1524205323Skib CP(u.shminfo, u32.shminfo32, shmseg); 1525205323Skib CP(u.shminfo, u32.shminfo32, shmall); 1526205323Skib error = copyout(&u32.shminfo32, uap->buf, 1527205323Skib sizeof(u32.shminfo32)); 1528205323Skib break; 1529205323Skib case SHM_INFO: 1530205323Skib CP(u.shm_info, u32.shm_info32, used_ids); 1531205323Skib CP(u.shm_info, u32.shm_info32, shm_rss); 1532205323Skib CP(u.shm_info, u32.shm_info32, shm_tot); 1533205323Skib CP(u.shm_info, u32.shm_info32, shm_swp); 1534205323Skib CP(u.shm_info, u32.shm_info32, swap_attempts); 1535205323Skib CP(u.shm_info, u32.shm_info32, swap_successes); 1536205323Skib error = copyout(&u32.shm_info32, uap->buf, 1537205323Skib sizeof(u32.shm_info32)); 1538205323Skib break; 1539205323Skib case SHM_STAT: 1540205323Skib case IPC_STAT: 1541205323Skib freebsd32_ipcperm_out(&u.shmid_ds.shm_perm, 1542205323Skib &u32.shmid_ds32.shm_perm); 1543205323Skib if (u.shmid_ds.shm_segsz > INT32_MAX) 1544205323Skib u32.shmid_ds32.shm_segsz = INT32_MAX; 1545205323Skib else 1546205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_segsz); 1547205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_lpid); 1548205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_cpid); 1549205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_nattch); 1550205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_atime); 1551205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_dtime); 1552205323Skib CP(u.shmid_ds, u32.shmid_ds32, shm_ctime); 1553205323Skib error = copyout(&u32.shmid_ds32, uap->buf, 1554205323Skib sizeof(u32.shmid_ds32)); 1555205323Skib break; 1556205323Skib } 1557205323Skib 1558205323Skibdone: 1559205323Skib if (error) { 1560205323Skib /* Invalidate the return value */ 1561205323Skib td->td_retval[0] = -1; 1562205323Skib } 1563205323Skib return (error); 1564205323Skib} 1565205323Skib#endif 1566205323Skib 1567205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1568205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1569205323Skib 1570194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1571194910Sjhbstruct freebsd7_shmctl_args { 1572194910Sjhb int shmid; 1573194910Sjhb int cmd; 1574194910Sjhb struct shmid_ds_old *buf; 1575194910Sjhb}; 1576194910Sjhb#endif 1577194910Sjhbint 1578280323Skibfreebsd7_shmctl(struct thread *td, struct freebsd7_shmctl_args *uap) 1579194910Sjhb{ 1580285057Smjg int error; 1581194910Sjhb struct shmid_ds_old old; 1582194910Sjhb struct shmid_ds buf; 1583194910Sjhb size_t bufsz; 1584285057Smjg 1585194910Sjhb /* 1586194910Sjhb * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support 1587194910Sjhb * Linux binaries. If we see the call come through the FreeBSD ABI, 1588194910Sjhb * return an error back to the user since we do not to support this. 1589194910Sjhb */ 1590194910Sjhb if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO || 1591194910Sjhb uap->cmd == SHM_STAT) 1592194910Sjhb return (EINVAL); 1593194910Sjhb 1594194910Sjhb /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ 1595194910Sjhb if (uap->cmd == IPC_SET) { 1596194910Sjhb if ((error = copyin(uap->buf, &old, sizeof(old)))) 1597194910Sjhb goto done; 1598194910Sjhb ipcperm_old2new(&old.shm_perm, &buf.shm_perm); 1599194910Sjhb CP(old, buf, shm_segsz); 1600194910Sjhb CP(old, buf, shm_lpid); 1601194910Sjhb CP(old, buf, shm_cpid); 1602194910Sjhb CP(old, buf, shm_nattch); 1603194910Sjhb CP(old, buf, shm_atime); 1604194910Sjhb CP(old, buf, shm_dtime); 1605194910Sjhb CP(old, buf, shm_ctime); 1606194910Sjhb } 1607285057Smjg 1608194910Sjhb error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); 1609194910Sjhb if (error) 1610194910Sjhb goto done; 1611194910Sjhb 1612194910Sjhb /* Cases in which we need to copyout */ 1613194910Sjhb switch (uap->cmd) { 1614194910Sjhb case IPC_STAT: 1615331922Skib memset(&old, 0, sizeof(old)); 1616194910Sjhb ipcperm_new2old(&buf.shm_perm, &old.shm_perm); 1617194910Sjhb if (buf.shm_segsz > INT_MAX) 1618194910Sjhb old.shm_segsz = INT_MAX; 1619194910Sjhb else 1620194910Sjhb CP(buf, old, shm_segsz); 1621194910Sjhb CP(buf, old, shm_lpid); 1622194910Sjhb CP(buf, old, shm_cpid); 1623194910Sjhb if (buf.shm_nattch > SHRT_MAX) 1624194910Sjhb old.shm_nattch = SHRT_MAX; 1625194910Sjhb else 1626194910Sjhb CP(buf, old, shm_nattch); 1627194910Sjhb CP(buf, old, shm_atime); 1628194910Sjhb CP(buf, old, shm_dtime); 1629194910Sjhb CP(buf, old, shm_ctime); 1630194910Sjhb old.shm_internal = NULL; 1631194910Sjhb error = copyout(&old, uap->buf, sizeof(old)); 1632194910Sjhb break; 1633194910Sjhb } 1634194910Sjhb 1635194910Sjhbdone: 1636194910Sjhb if (error) { 1637194910Sjhb /* Invalidate the return value */ 1638194910Sjhb td->td_retval[0] = -1; 1639194910Sjhb } 1640194910Sjhb return (error); 1641194910Sjhb} 1642194910Sjhb 1643194910Sjhb#endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 || 1644194910Sjhb COMPAT_FREEBSD7 */ 1645194910Sjhb 1646194894Sjhbstatic int 164769449Salfredsysvshm_modload(struct module *module, int cmd, void *arg) 164869449Salfred{ 164969449Salfred int error = 0; 165069449Salfred 165169449Salfred switch (cmd) { 165269449Salfred case MOD_LOAD: 1653205323Skib error = shminit(); 1654205323Skib if (error != 0) 1655205323Skib shmunload(); 165669449Salfred break; 165769449Salfred case MOD_UNLOAD: 165869449Salfred error = shmunload(); 165969449Salfred break; 166069449Salfred case MOD_SHUTDOWN: 166169449Salfred break; 166269449Salfred default: 166369449Salfred error = EINVAL; 166469449Salfred break; 166569449Salfred } 166669449Salfred return (error); 166769449Salfred} 166869449Salfred 166971038Sdesstatic moduledata_t sysvshm_mod = { 167071038Sdes "sysvshm", 167169449Salfred &sysvshm_modload, 167269449Salfred NULL 167369449Salfred}; 167469449Salfred 1675194832SjhbDECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST); 167671038SdesMODULE_VERSION(sysvshm, 1); 1677