1*41490Smckusick /* 2*41490Smckusick * Copyright (c) 1988 University of Utah. 3*41490Smckusick * Copyright (c) 1990 The Regents of the University of California. 4*41490Smckusick * All rights reserved. 5*41490Smckusick * 6*41490Smckusick * This code is derived from software contributed to Berkeley by 7*41490Smckusick * the Systems Programming Group of the University of Utah Computer 8*41490Smckusick * Science Department. Originally from University of Wisconsin. 9*41490Smckusick * 10*41490Smckusick * %sccs.include.redist.c% 11*41490Smckusick * 12*41490Smckusick * from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$ 13*41490Smckusick * 14*41490Smckusick * @(#)sysv_shm.c 7.1 (Berkeley) 05/08/90 15*41490Smckusick */ 16*41490Smckusick 17*41490Smckusick /* 18*41490Smckusick * System V shared memory routines. 19*41490Smckusick */ 20*41490Smckusick 21*41490Smckusick #ifdef SYSVSHM 22*41490Smckusick 23*41490Smckusick #include "machine/pte.h" 24*41490Smckusick 25*41490Smckusick #include "param.h" 26*41490Smckusick #include "systm.h" 27*41490Smckusick #include "user.h" 28*41490Smckusick #include "kernel.h" 29*41490Smckusick #include "proc.h" 30*41490Smckusick #include "vm.h" 31*41490Smckusick #include "shm.h" 32*41490Smckusick #include "mapmem.h" 33*41490Smckusick #include "malloc.h" 34*41490Smckusick 35*41490Smckusick #ifdef HPUXCOMPAT 36*41490Smckusick #include "../hpux/hpux.h" 37*41490Smckusick #endif 38*41490Smckusick 39*41490Smckusick int shmat(), shmctl(), shmdt(), shmget(); 40*41490Smckusick int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget }; 41*41490Smckusick int shmtot = 0; 42*41490Smckusick 43*41490Smckusick int shmfork(), shmexit(); 44*41490Smckusick struct mapmemops shmops = { shmfork, (int (*)())0, shmexit, shmexit }; 45*41490Smckusick 46*41490Smckusick shminit() 47*41490Smckusick { 48*41490Smckusick register int i; 49*41490Smckusick 50*41490Smckusick if (shminfo.shmmni > SHMMMNI) 51*41490Smckusick shminfo.shmmni = SHMMMNI; 52*41490Smckusick for (i = 0; i < shminfo.shmmni; i++) { 53*41490Smckusick shmsegs[i].shm_perm.mode = 0; 54*41490Smckusick shmsegs[i].shm_perm.seq = 0; 55*41490Smckusick } 56*41490Smckusick } 57*41490Smckusick 58*41490Smckusick /* entry point for all SHM calls */ 59*41490Smckusick shmsys() 60*41490Smckusick { 61*41490Smckusick struct a { 62*41490Smckusick int which; 63*41490Smckusick } *uap = (struct a *)u.u_ap; 64*41490Smckusick 65*41490Smckusick if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) { 66*41490Smckusick u.u_error = EINVAL; 67*41490Smckusick return; 68*41490Smckusick } 69*41490Smckusick (*shmcalls[uap->which])(u.u_ap+1); 70*41490Smckusick } 71*41490Smckusick 72*41490Smckusick /* get a shared memory segment */ 73*41490Smckusick shmget(ap) 74*41490Smckusick int *ap; 75*41490Smckusick { 76*41490Smckusick register struct a { 77*41490Smckusick key_t key; 78*41490Smckusick int size; 79*41490Smckusick int shmflg; 80*41490Smckusick } *uap = (struct a *)ap; 81*41490Smckusick register struct shmid_ds *shp; 82*41490Smckusick register int i; 83*41490Smckusick int rval = 0, size; 84*41490Smckusick caddr_t kva; 85*41490Smckusick 86*41490Smckusick /* look up the specified shm_id */ 87*41490Smckusick if (uap->key != IPC_PRIVATE) { 88*41490Smckusick for (i = 0; i < shminfo.shmmni; i++) 89*41490Smckusick if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) && 90*41490Smckusick shmsegs[i].shm_perm.key == uap->key) { 91*41490Smckusick rval = i; 92*41490Smckusick break; 93*41490Smckusick } 94*41490Smckusick } else 95*41490Smckusick i = shminfo.shmmni; 96*41490Smckusick 97*41490Smckusick /* create a new shared segment if necessary */ 98*41490Smckusick if (i == shminfo.shmmni) { 99*41490Smckusick if ((uap->shmflg & IPC_CREAT) == 0) { 100*41490Smckusick u.u_error = ENOENT; 101*41490Smckusick return; 102*41490Smckusick } 103*41490Smckusick if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) { 104*41490Smckusick u.u_error = EINVAL; 105*41490Smckusick return; 106*41490Smckusick } 107*41490Smckusick for (i = 0; i < shminfo.shmmni; i++) 108*41490Smckusick if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) == 0) { 109*41490Smckusick rval = i; 110*41490Smckusick break; 111*41490Smckusick } 112*41490Smckusick if (i == shminfo.shmmni) { 113*41490Smckusick u.u_error = ENOSPC; 114*41490Smckusick return; 115*41490Smckusick } 116*41490Smckusick size = clrnd(btoc(uap->size)); 117*41490Smckusick if (shmtot + size > shminfo.shmall) { 118*41490Smckusick u.u_error = ENOMEM; 119*41490Smckusick return; 120*41490Smckusick } 121*41490Smckusick shp = &shmsegs[rval]; 122*41490Smckusick /* 123*41490Smckusick * We need to do a couple of things to ensure consistency 124*41490Smckusick * in case we sleep in malloc(). We mark segment as 125*41490Smckusick * allocated so that other shmgets() will not allocate it. 126*41490Smckusick * We mark it as "destroyed" to insure that shmvalid() is 127*41490Smckusick * false making most operations fail (XXX). We set the key, 128*41490Smckusick * so that other shmget()s will fail. 129*41490Smckusick */ 130*41490Smckusick shp->shm_perm.mode = SHM_ALLOC | SHM_DEST; 131*41490Smckusick shp->shm_perm.key = uap->key; 132*41490Smckusick kva = (caddr_t) malloc((u_long)ctob(size), M_SHM, M_WAITOK); 133*41490Smckusick if (kva == NULL) { 134*41490Smckusick shp->shm_perm.mode = 0; 135*41490Smckusick u.u_error = ENOMEM; 136*41490Smckusick return; 137*41490Smckusick } 138*41490Smckusick if (!claligned(kva)) 139*41490Smckusick panic("shmget: non-aligned memory"); 140*41490Smckusick bzero(kva, (u_int)ctob(size)); 141*41490Smckusick shmtot += size; 142*41490Smckusick shp->shm_perm.cuid = shp->shm_perm.uid = u.u_uid; 143*41490Smckusick shp->shm_perm.cgid = shp->shm_perm.gid = u.u_gid; 144*41490Smckusick shp->shm_perm.mode = SHM_ALLOC | (uap->shmflg&0777); 145*41490Smckusick shp->shm_handle = (void *) kvtopte(kva); 146*41490Smckusick shp->shm_segsz = uap->size; 147*41490Smckusick shp->shm_cpid = u.u_procp->p_pid; 148*41490Smckusick shp->shm_lpid = shp->shm_nattch = 0; 149*41490Smckusick shp->shm_atime = shp->shm_dtime = 0; 150*41490Smckusick shp->shm_ctime = time.tv_sec; 151*41490Smckusick } else { 152*41490Smckusick shp = &shmsegs[rval]; 153*41490Smckusick /* XXX: probably not the right thing to do */ 154*41490Smckusick if (shp->shm_perm.mode & SHM_DEST) { 155*41490Smckusick u.u_error = EBUSY; 156*41490Smckusick return; 157*41490Smckusick } 158*41490Smckusick if (!ipcaccess(&shp->shm_perm, uap->shmflg&0777)) 159*41490Smckusick return; 160*41490Smckusick if (uap->size && uap->size > shp->shm_segsz) { 161*41490Smckusick u.u_error = EINVAL; 162*41490Smckusick return; 163*41490Smckusick } 164*41490Smckusick if ((uap->shmflg&IPC_CREAT) && (uap->shmflg&IPC_EXCL)) { 165*41490Smckusick u.u_error = EEXIST; 166*41490Smckusick return; 167*41490Smckusick } 168*41490Smckusick } 169*41490Smckusick u.u_r.r_val1 = shp->shm_perm.seq * SHMMMNI + rval; 170*41490Smckusick } 171*41490Smckusick 172*41490Smckusick /* shared memory control */ 173*41490Smckusick shmctl(ap) 174*41490Smckusick int *ap; 175*41490Smckusick { 176*41490Smckusick register struct a { 177*41490Smckusick int shmid; 178*41490Smckusick int cmd; 179*41490Smckusick caddr_t buf; 180*41490Smckusick } *uap = (struct a *)ap; 181*41490Smckusick register struct shmid_ds *shp; 182*41490Smckusick struct shmid_ds sbuf; 183*41490Smckusick 184*41490Smckusick if (!shmvalid(uap->shmid)) 185*41490Smckusick return; 186*41490Smckusick shp = &shmsegs[uap->shmid % SHMMMNI]; 187*41490Smckusick switch (uap->cmd) { 188*41490Smckusick case IPC_STAT: 189*41490Smckusick if (ipcaccess(&shp->shm_perm, IPC_R)) 190*41490Smckusick u.u_error = 191*41490Smckusick copyout((caddr_t)shp, uap->buf, sizeof(*shp)); 192*41490Smckusick break; 193*41490Smckusick 194*41490Smckusick case IPC_SET: 195*41490Smckusick if (u.u_uid && u.u_uid != shp->shm_perm.uid && 196*41490Smckusick u.u_uid != shp->shm_perm.cuid) { 197*41490Smckusick u.u_error = EPERM; 198*41490Smckusick break; 199*41490Smckusick } 200*41490Smckusick u.u_error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf); 201*41490Smckusick if (!u.u_error) { 202*41490Smckusick shp->shm_perm.uid = sbuf.shm_perm.uid; 203*41490Smckusick shp->shm_perm.gid = sbuf.shm_perm.gid; 204*41490Smckusick shp->shm_perm.mode = (shp->shm_perm.mode & ~0777) 205*41490Smckusick | (sbuf.shm_perm.mode & 0777); 206*41490Smckusick shp->shm_ctime = time.tv_sec; 207*41490Smckusick } 208*41490Smckusick break; 209*41490Smckusick 210*41490Smckusick case IPC_RMID: 211*41490Smckusick if (u.u_uid && u.u_uid != shp->shm_perm.uid && 212*41490Smckusick u.u_uid != shp->shm_perm.cuid) { 213*41490Smckusick u.u_error = EPERM; 214*41490Smckusick break; 215*41490Smckusick } 216*41490Smckusick /* set ctime? */ 217*41490Smckusick shp->shm_perm.key = IPC_PRIVATE; 218*41490Smckusick shp->shm_perm.mode |= SHM_DEST; 219*41490Smckusick if (shp->shm_nattch <= 0) 220*41490Smckusick shmfree(shp); 221*41490Smckusick break; 222*41490Smckusick 223*41490Smckusick #ifdef HPUXCOMPAT 224*41490Smckusick case SHM_LOCK: 225*41490Smckusick case SHM_UNLOCK: 226*41490Smckusick /* don't really do anything, but make them think we did */ 227*41490Smckusick if ((u.u_procp->p_flag & SHPUX) == 0) 228*41490Smckusick u.u_error = EINVAL; 229*41490Smckusick else if (u.u_uid && u.u_uid != shp->shm_perm.uid && 230*41490Smckusick u.u_uid != shp->shm_perm.cuid) 231*41490Smckusick u.u_error = EPERM; 232*41490Smckusick break; 233*41490Smckusick #endif 234*41490Smckusick 235*41490Smckusick default: 236*41490Smckusick u.u_error = EINVAL; 237*41490Smckusick break; 238*41490Smckusick } 239*41490Smckusick } 240*41490Smckusick 241*41490Smckusick shmat(ap) 242*41490Smckusick int *ap; 243*41490Smckusick { 244*41490Smckusick struct a { 245*41490Smckusick int shmid; 246*41490Smckusick caddr_t shmaddr; 247*41490Smckusick int shmflg; 248*41490Smckusick } *uap = (struct a *)ap; 249*41490Smckusick register struct shmid_ds *shp; 250*41490Smckusick register int size; 251*41490Smckusick struct mapmem *mp; 252*41490Smckusick caddr_t uva; 253*41490Smckusick int prot, shmmapin(); 254*41490Smckusick 255*41490Smckusick if (!shmvalid(uap->shmid)) 256*41490Smckusick return; 257*41490Smckusick shp = &shmsegs[uap->shmid % SHMMMNI]; 258*41490Smckusick if (shp->shm_handle == NULL) 259*41490Smckusick panic("shmat NULL ptbl"); 260*41490Smckusick if (!ipcaccess(&shp->shm_perm, 261*41490Smckusick (uap->shmflg&SHM_RDONLY) ? IPC_R : IPC_R|IPC_W)) 262*41490Smckusick return; 263*41490Smckusick uva = uap->shmaddr; 264*41490Smckusick if (uva && ((int)uva & (SHMLBA-1))) { 265*41490Smckusick if (uap->shmflg & SHM_RND) 266*41490Smckusick uva = (caddr_t) ((int)uva & ~(SHMLBA-1)); 267*41490Smckusick else { 268*41490Smckusick u.u_error = EINVAL; 269*41490Smckusick return; 270*41490Smckusick } 271*41490Smckusick } 272*41490Smckusick /* 273*41490Smckusick * Make sure user doesn't use more than their fair share 274*41490Smckusick */ 275*41490Smckusick size = 0; 276*41490Smckusick for (mp = u.u_mmap; mp; mp = mp->mm_next) 277*41490Smckusick if (mp->mm_ops == &shmops) 278*41490Smckusick size++; 279*41490Smckusick if (size >= shminfo.shmseg) { 280*41490Smckusick u.u_error = EMFILE; 281*41490Smckusick return; 282*41490Smckusick } 283*41490Smckusick /* 284*41490Smckusick * Allocate a mapped memory region descriptor and 285*41490Smckusick * attempt to expand the user page table to allow for region 286*41490Smckusick */ 287*41490Smckusick prot = (uap->shmflg & SHM_RDONLY) ? MM_RO : MM_RW; 288*41490Smckusick #if defined(hp300) 289*41490Smckusick prot |= MM_CI; 290*41490Smckusick #endif 291*41490Smckusick size = ctob(clrnd(btoc(shp->shm_segsz))); 292*41490Smckusick mp = mmalloc(uap->shmid, &uva, (size_t)size, prot, &shmops); 293*41490Smckusick if (mp == MMNIL) 294*41490Smckusick return; 295*41490Smckusick if (!mmmapin(mp, shmmapin)) { 296*41490Smckusick mmfree(mp); 297*41490Smckusick return; 298*41490Smckusick } 299*41490Smckusick /* 300*41490Smckusick * Fill in the remaining fields 301*41490Smckusick */ 302*41490Smckusick shp->shm_lpid = u.u_procp->p_pid; 303*41490Smckusick shp->shm_atime = time.tv_sec; 304*41490Smckusick shp->shm_nattch++; 305*41490Smckusick u.u_r.r_val1 = (int) uva; 306*41490Smckusick } 307*41490Smckusick 308*41490Smckusick shmdt(ap) 309*41490Smckusick int *ap; 310*41490Smckusick { 311*41490Smckusick register struct a { 312*41490Smckusick caddr_t shmaddr; 313*41490Smckusick } *uap = (struct a *)ap; 314*41490Smckusick register struct mapmem *mp; 315*41490Smckusick 316*41490Smckusick for (mp = u.u_mmap; mp; mp = mp->mm_next) 317*41490Smckusick if (mp->mm_ops == &shmops && mp->mm_uva == uap->shmaddr) 318*41490Smckusick break; 319*41490Smckusick if (mp == MMNIL) { 320*41490Smckusick u.u_error = EINVAL; 321*41490Smckusick return; 322*41490Smckusick } 323*41490Smckusick shmsegs[mp->mm_id % SHMMMNI].shm_lpid = u.u_procp->p_pid; 324*41490Smckusick shmufree(mp); 325*41490Smckusick } 326*41490Smckusick 327*41490Smckusick shmmapin(mp, off) 328*41490Smckusick struct mapmem *mp; 329*41490Smckusick { 330*41490Smckusick register struct shmid_ds *shp; 331*41490Smckusick 332*41490Smckusick shp = &shmsegs[mp->mm_id % SHMMMNI]; 333*41490Smckusick if (off >= ctob(clrnd(btoc(shp->shm_segsz)))) 334*41490Smckusick return(-1); 335*41490Smckusick return(((struct pte *)shp->shm_handle)[btop(off)].pg_pfnum); 336*41490Smckusick } 337*41490Smckusick 338*41490Smckusick /* 339*41490Smckusick * Increment attach count on fork 340*41490Smckusick */ 341*41490Smckusick shmfork(mp, ischild) 342*41490Smckusick register struct mapmem *mp; 343*41490Smckusick { 344*41490Smckusick if (!ischild) 345*41490Smckusick shmsegs[mp->mm_id % SHMMMNI].shm_nattch++; 346*41490Smckusick } 347*41490Smckusick 348*41490Smckusick /* 349*41490Smckusick * Detach from shared memory segment on exit (or exec) 350*41490Smckusick */ 351*41490Smckusick shmexit(mp) 352*41490Smckusick register struct mapmem *mp; 353*41490Smckusick { 354*41490Smckusick shmufree(mp); 355*41490Smckusick } 356*41490Smckusick 357*41490Smckusick shmvalid(id) 358*41490Smckusick register int id; 359*41490Smckusick { 360*41490Smckusick register struct shmid_ds *shp; 361*41490Smckusick 362*41490Smckusick if (id < 0 || (id % SHMMMNI) >= shminfo.shmmni) 363*41490Smckusick return(0); 364*41490Smckusick shp = &shmsegs[id % SHMMMNI]; 365*41490Smckusick if (shp->shm_perm.seq == (id / SHMMMNI) && 366*41490Smckusick (shp->shm_perm.mode & (SHM_ALLOC|SHM_DEST)) == SHM_ALLOC) 367*41490Smckusick return(1); 368*41490Smckusick u.u_error = EINVAL; 369*41490Smckusick return(0); 370*41490Smckusick } 371*41490Smckusick 372*41490Smckusick /* 373*41490Smckusick * Free user resources associated with a shared memory segment 374*41490Smckusick */ 375*41490Smckusick shmufree(mp) 376*41490Smckusick struct mapmem *mp; 377*41490Smckusick { 378*41490Smckusick register struct shmid_ds *shp; 379*41490Smckusick 380*41490Smckusick shp = &shmsegs[mp->mm_id % SHMMMNI]; 381*41490Smckusick mmmapout(mp); 382*41490Smckusick mmfree(mp); 383*41490Smckusick shp->shm_dtime = time.tv_sec; 384*41490Smckusick if (--shp->shm_nattch <= 0 && (shp->shm_perm.mode & SHM_DEST)) 385*41490Smckusick shmfree(shp); 386*41490Smckusick } 387*41490Smckusick 388*41490Smckusick /* 389*41490Smckusick * Deallocate resources associated with a shared memory segment 390*41490Smckusick */ 391*41490Smckusick shmfree(shp) 392*41490Smckusick register struct shmid_ds *shp; 393*41490Smckusick { 394*41490Smckusick caddr_t kva; 395*41490Smckusick 396*41490Smckusick if (shp->shm_handle == NULL) 397*41490Smckusick panic("shmfree"); 398*41490Smckusick kva = (caddr_t) ptetokv(shp->shm_handle); 399*41490Smckusick free(kva, M_SHM); 400*41490Smckusick shp->shm_handle = NULL; 401*41490Smckusick shmtot -= clrnd(btoc(shp->shm_segsz)); 402*41490Smckusick shp->shm_perm.mode = 0; 403*41490Smckusick /* 404*41490Smckusick * Increment the sequence number to ensure that outstanding 405*41490Smckusick * shmids for this segment will be invalid in the event that 406*41490Smckusick * the segment is reallocated. Note that shmids must be 407*41490Smckusick * positive as decreed by SVID. 408*41490Smckusick */ 409*41490Smckusick shp->shm_perm.seq++; 410*41490Smckusick if ((int)(shp->shm_perm.seq * SHMMMNI) < 0) 411*41490Smckusick shp->shm_perm.seq = 0; 412*41490Smckusick } 413*41490Smckusick 414*41490Smckusick /* 415*41490Smckusick * XXX This routine would be common to all sysV style IPC 416*41490Smckusick * (if the others were implemented). 417*41490Smckusick */ 418*41490Smckusick ipcaccess(ipc, mode) 419*41490Smckusick register struct ipc_perm *ipc; 420*41490Smckusick { 421*41490Smckusick register int m; 422*41490Smckusick 423*41490Smckusick if (u.u_uid == 0) 424*41490Smckusick return(0); 425*41490Smckusick /* 426*41490Smckusick * Access check is based on only one of owner, group, public. 427*41490Smckusick * If not owner, then check group. 428*41490Smckusick * If not a member of the group, then check public access. 429*41490Smckusick */ 430*41490Smckusick mode &= 0700; 431*41490Smckusick m = ipc->mode; 432*41490Smckusick if (u.u_uid != ipc->uid && u.u_uid != ipc->cuid) { 433*41490Smckusick m <<= 3; 434*41490Smckusick if (!groupmember(ipc->gid, u.u_cred) && 435*41490Smckusick !groupmember(ipc->cgid, u.u_cred)) 436*41490Smckusick m <<= 3; 437*41490Smckusick } 438*41490Smckusick if ((mode&m) == mode) 439*41490Smckusick return (1); 440*41490Smckusick u.u_error = EACCES; 441*41490Smckusick return (0); 442*41490Smckusick } 443*41490Smckusick 444*41490Smckusick #endif /* SYSVSHM */ 445