|
|
1.1.1.3 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. Originally from University of Wisconsin. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$ ! 39: * ! 40: * from: @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91 ! 41: * sysv_shm.c,v 1.5 1993/07/17 15:24:39 mycroft Exp ! 42: */ ! 43: ! 44: /* ! 45: * System V shared memory routines. ! 46: * TEMPORARY, until mmap is in place; ! 47: * needed now for HP-UX compatibility and X server (yech!). ! 48: */ ! 49: ! 50: #ifdef SYSVSHM ! 51: ! 52: #include "param.h" ! 53: #include "systm.h" ! 54: #include "kernel.h" ! 55: #include "proc.h" ! 56: #include "shm.h" ! 57: #include "malloc.h" ! 58: #include "mman.h" ! 59: #include "vm/vm.h" ! 60: #include "vm/vm_kern.h" ! 61: #include "vm/vm_inherit.h" ! 62: #include "vm/vm_pager.h" ! 63: ! 64: #ifdef HPUXCOMPAT ! 65: #include "hp300/hpux/hpux.h" ! 66: #endif ! 67: ! 68: int shmat(), shmctl(), shmdt(), shmget(); ! 69: int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget }; ! 70: int shmtot = 0; ! 71: ! 72: /* ! 73: * Per process internal structure for managing segments. ! 74: * Each process using shm will have an array of ``shmseg'' of these. ! 75: */ ! 76: struct shmdesc { ! 77: vm_offset_t shmd_uva; ! 78: int shmd_id; ! 79: }; ! 80: ! 81: /* ! 82: * Per segment internal structure (shm_handle). ! 83: */ ! 84: struct shmhandle { ! 85: vm_offset_t shmh_kva; ! 86: caddr_t shmh_id; ! 87: }; ! 88: ! 89: vm_map_t shm_map; /* address space for shared memory segments */ ! 90: ! 91: void ! 92: shminit() ! 93: { ! 94: register int i; ! 95: vm_offset_t whocares1, whocares2; ! 96: ! 97: shm_map = kmem_suballoc(kernel_map, &whocares1, &whocares2, ! 98: shminfo.shmall * NBPG, FALSE); ! 99: if (shminfo.shmmni > SHMMMNI) ! 100: shminfo.shmmni = SHMMMNI; ! 101: for (i = 0; i < shminfo.shmmni; i++) { ! 102: shmsegs[i].shm_perm.mode = 0; ! 103: shmsegs[i].shm_perm.seq = 0; ! 104: } ! 105: } ! 106: ! 107: /* ! 108: * Entry point for all SHM calls ! 109: */ ! 110: struct shmsys_args { ! 111: u_int which; ! 112: }; ! 113: ! 114: shmsys(p, uap, retval) ! 115: struct proc *p; ! 116: struct shmsys_args *uap; ! 117: int *retval; ! 118: { ! 119: ! 120: if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) ! 121: return (EINVAL); ! 122: return ((*shmcalls[uap->which])(p, &uap[1], retval)); ! 123: } ! 124: ! 125: /* ! 126: * Get a shared memory segment ! 127: */ ! 128: struct shmget_args { ! 129: key_t key; ! 130: int size; ! 131: int shmflg; ! 132: }; ! 133: ! 134: shmget(p, uap, retval) ! 135: struct proc *p; ! 136: register struct shmget_args *uap; ! 137: int *retval; ! 138: { ! 139: register struct shmid_ds *shp; ! 140: register struct ucred *cred = p->p_ucred; ! 141: register int i; ! 142: int error, size, rval = 0; ! 143: register struct shmhandle *shmh; ! 144: ! 145: /* look up the specified shm_id */ ! 146: if (uap->key != IPC_PRIVATE) { ! 147: for (i = 0; i < shminfo.shmmni; i++) ! 148: if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) && ! 149: shmsegs[i].shm_perm.key == uap->key) { ! 150: rval = i; ! 151: break; ! 152: } ! 153: } else ! 154: i = shminfo.shmmni; ! 155: ! 156: /* create a new shared segment if necessary */ ! 157: if (i == shminfo.shmmni) { ! 158: if ((uap->shmflg & IPC_CREAT) == 0) ! 159: return (ENOENT); ! 160: if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) ! 161: return (EINVAL); ! 162: for (i = 0; i < shminfo.shmmni; i++) ! 163: if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) == 0) { ! 164: rval = i; ! 165: break; ! 166: } ! 167: if (i == shminfo.shmmni) ! 168: return (ENOSPC); ! 169: size = clrnd(btoc(uap->size)); ! 170: if (shmtot + size > shminfo.shmall) ! 171: return (ENOMEM); ! 172: shp = &shmsegs[rval]; ! 173: /* ! 174: * We need to do a couple of things to ensure consistency ! 175: * in case we sleep in malloc(). We mark segment as ! 176: * allocated so that other shmgets() will not allocate it. ! 177: * We mark it as "destroyed" to insure that shmvalid() is ! 178: * false making most operations fail (XXX). We set the key, ! 179: * so that other shmget()s will fail. ! 180: */ ! 181: shp->shm_perm.mode = SHM_ALLOC | SHM_DEST; ! 182: shp->shm_perm.key = uap->key; ! 183: shmh = (struct shmhandle *) ! 184: malloc(sizeof(struct shmhandle), M_SHM, M_WAITOK); ! 185: shmh->shmh_kva = 0; ! 186: shmh->shmh_id = (caddr_t)(0xc0000000|rval); /* XXX */ ! 187: error = vm_mmap(shm_map, &shmh->shmh_kva, ctob(size), ! 188: VM_PROT_ALL, VM_PROT_DEFAULT, MAP_ANON, shmh->shmh_id, 0); ! 189: if (error) { ! 190: free((caddr_t)shmh, M_SHM); ! 191: shp->shm_perm.mode = 0; ! 192: return(ENOMEM); ! 193: } ! 194: shp->shm_handle = (void *) shmh; ! 195: shmtot += size; ! 196: shp->shm_perm.cuid = shp->shm_perm.uid = cred->cr_uid; ! 197: shp->shm_perm.cgid = shp->shm_perm.gid = cred->cr_gid; ! 198: shp->shm_perm.mode = SHM_ALLOC | (uap->shmflg&0777); ! 199: shp->shm_segsz = uap->size; ! 200: shp->shm_cpid = p->p_pid; ! 201: shp->shm_lpid = shp->shm_nattch = 0; ! 202: shp->shm_atime = shp->shm_dtime = 0; ! 203: shp->shm_ctime = time.tv_sec; ! 204: } else { ! 205: shp = &shmsegs[rval]; ! 206: /* XXX: probably not the right thing to do */ ! 207: if (shp->shm_perm.mode & SHM_DEST) ! 208: return (EBUSY); ! 209: if (error = ipcaccess(&shp->shm_perm, uap->shmflg&0777, cred)) ! 210: return (error); ! 211: if (uap->size && uap->size > shp->shm_segsz) ! 212: return (EINVAL); ! 213: if ((uap->shmflg&IPC_CREAT) && (uap->shmflg&IPC_EXCL)) ! 214: return (EEXIST); ! 215: } ! 216: *retval = shp->shm_perm.seq * SHMMMNI + rval; ! 217: return (0); ! 218: } ! 219: ! 220: /* ! 221: * Shared memory control ! 222: */ ! 223: struct shmctl_args { ! 224: int shmid; ! 225: int cmd; ! 226: caddr_t buf; ! 227: }; ! 228: ! 229: /* ARGSUSED */ ! 230: shmctl(p, uap, retval) ! 231: struct proc *p; ! 232: register struct shmctl_args *uap; ! 233: int *retval; ! 234: { ! 235: register struct shmid_ds *shp; ! 236: register struct ucred *cred = p->p_ucred; ! 237: struct shmid_ds sbuf; ! 238: int error; ! 239: ! 240: if (error = shmvalid(uap->shmid)) ! 241: return (error); ! 242: shp = &shmsegs[uap->shmid % SHMMMNI]; ! 243: switch (uap->cmd) { ! 244: case IPC_STAT: ! 245: if (error = ipcaccess(&shp->shm_perm, IPC_R, cred)) ! 246: return (error); ! 247: return (copyout((caddr_t)shp, uap->buf, sizeof(*shp))); ! 248: ! 249: case IPC_SET: ! 250: if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid && ! 251: cred->cr_uid != shp->shm_perm.cuid) ! 252: return (EPERM); ! 253: if (error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf)) ! 254: return (error); ! 255: shp->shm_perm.uid = sbuf.shm_perm.uid; ! 256: shp->shm_perm.gid = sbuf.shm_perm.gid; ! 257: shp->shm_perm.mode = (shp->shm_perm.mode & ~0777) ! 258: | (sbuf.shm_perm.mode & 0777); ! 259: shp->shm_ctime = time.tv_sec; ! 260: break; ! 261: ! 262: case IPC_RMID: ! 263: if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid && ! 264: cred->cr_uid != shp->shm_perm.cuid) ! 265: return (EPERM); ! 266: /* set ctime? */ ! 267: shp->shm_perm.key = IPC_PRIVATE; ! 268: shp->shm_perm.mode |= SHM_DEST; ! 269: if (shp->shm_nattch <= 0) ! 270: shmfree(shp); ! 271: break; ! 272: ! 273: #ifdef HPUXCOMPAT ! 274: case SHM_LOCK: ! 275: case SHM_UNLOCK: ! 276: /* don't really do anything, but make them think we did */ ! 277: if ((p->p_flag & SHPUX) == 0) ! 278: return (EINVAL); ! 279: if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid && ! 280: cred->cr_uid != shp->shm_perm.cuid) ! 281: return (EPERM); ! 282: break; ! 283: #endif ! 284: ! 285: default: ! 286: return (EINVAL); ! 287: } ! 288: return (0); ! 289: } ! 290: ! 291: /* ! 292: * Attach to shared memory segment. ! 293: */ ! 294: struct shmat_args { ! 295: int shmid; ! 296: caddr_t shmaddr; ! 297: int shmflg; ! 298: }; ! 299: ! 300: shmat(p, uap, retval) ! 301: struct proc *p; ! 302: register struct shmat_args *uap; ! 303: int *retval; ! 304: { ! 305: register struct shmid_ds *shp; ! 306: register int size; ! 307: caddr_t uva; ! 308: int error; ! 309: int flags; ! 310: vm_prot_t prot; ! 311: struct shmdesc *shmd; ! 312: ! 313: /* ! 314: * Allocate descriptors now (before validity check) ! 315: * in case malloc() blocks. ! 316: */ ! 317: shmd = (struct shmdesc *)p->p_vmspace->vm_shm; ! 318: size = shminfo.shmseg * sizeof(struct shmdesc); ! 319: if (shmd == NULL) { ! 320: shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK); ! 321: bzero((caddr_t)shmd, size); ! 322: p->p_vmspace->vm_shm = (caddr_t)shmd; ! 323: } ! 324: if (error = shmvalid(uap->shmid)) ! 325: return (error); ! 326: shp = &shmsegs[uap->shmid % SHMMMNI]; ! 327: if (shp->shm_handle == NULL) ! 328: panic("shmat NULL handle"); ! 329: if (error = ipcaccess(&shp->shm_perm, ! 330: (uap->shmflg&SHM_RDONLY) ? IPC_R : IPC_R|IPC_W, p->p_ucred)) ! 331: return (error); ! 332: uva = uap->shmaddr; ! 333: if (uva && ((int)uva & (SHMLBA-1))) { ! 334: if (uap->shmflg & SHM_RND) ! 335: uva = (caddr_t) ((int)uva & ~(SHMLBA-1)); ! 336: else ! 337: return (EINVAL); ! 338: } ! 339: /* ! 340: * Make sure user doesn't use more than their fair share ! 341: */ ! 342: for (size = 0; size < shminfo.shmseg; size++) { ! 343: if (shmd->shmd_uva == 0) ! 344: break; ! 345: shmd++; ! 346: } ! 347: if (size >= shminfo.shmseg) ! 348: return (EMFILE); ! 349: size = ctob(clrnd(btoc(shp->shm_segsz))); ! 350: prot = VM_PROT_READ; ! 351: if ((uap->shmflg & SHM_RDONLY) == 0) ! 352: prot |= VM_PROT_WRITE; ! 353: flags = MAP_ANON|MAP_SHARED; ! 354: if (uva) ! 355: flags |= MAP_FIXED; ! 356: else ! 357: uva = (caddr_t)0x1000000; /* XXX */ ! 358: error = vm_mmap(&p->p_vmspace->vm_map, &uva, (vm_size_t)size, prot, VM_PROT_DEFAULT, ! 359: flags, ((struct shmhandle *)shp->shm_handle)->shmh_id, 0); ! 360: if (error) ! 361: return(error); ! 362: shmd->shmd_uva = (vm_offset_t)uva; ! 363: shmd->shmd_id = uap->shmid; ! 364: /* ! 365: * Fill in the remaining fields ! 366: */ ! 367: shp->shm_lpid = p->p_pid; ! 368: shp->shm_atime = time.tv_sec; ! 369: shp->shm_nattch++; ! 370: *retval = (int) uva; ! 371: return (0); ! 372: } ! 373: ! 374: /* ! 375: * Detach from shared memory segment. ! 376: */ ! 377: struct shmdt_args { ! 378: caddr_t shmaddr; ! 379: }; ! 380: ! 381: /* ARGSUSED */ ! 382: shmdt(p, uap, retval) ! 383: struct proc *p; ! 384: struct shmdt_args *uap; ! 385: int *retval; ! 386: { ! 387: register struct shmdesc *shmd; ! 388: register int i; ! 389: ! 390: shmd = (struct shmdesc *)p->p_vmspace->vm_shm; ! 391: for (i = 0; i < shminfo.shmseg; i++, shmd++) ! 392: if (shmd->shmd_uva && ! 393: shmd->shmd_uva == (vm_offset_t)uap->shmaddr) ! 394: break; ! 395: if (i == shminfo.shmseg) ! 396: return(EINVAL); ! 397: shmufree(p, shmd); ! 398: shmsegs[shmd->shmd_id % SHMMMNI].shm_lpid = p->p_pid; ! 399: } ! 400: ! 401: shmfork(p1, p2, isvfork) ! 402: struct proc *p1, *p2; ! 403: int isvfork; ! 404: { ! 405: register struct shmdesc *shmd; ! 406: register int size; ! 407: ! 408: /* ! 409: * Copy parents descriptive information ! 410: */ ! 411: size = shminfo.shmseg * sizeof(struct shmdesc); ! 412: shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK); ! 413: bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmd, size); ! 414: p2->p_vmspace->vm_shm = (caddr_t)shmd; ! 415: /* ! 416: * Increment reference counts ! 417: */ ! 418: for (size = 0; size < shminfo.shmseg; size++, shmd++) ! 419: if (shmd->shmd_uva) ! 420: shmsegs[shmd->shmd_id % SHMMMNI].shm_nattch++; ! 421: } ! 422: ! 423: shmexit(p) ! 424: struct proc *p; ! 425: { ! 426: register struct shmdesc *shmd; ! 427: register int i; ! 428: ! 429: shmd = (struct shmdesc *)p->p_vmspace->vm_shm; ! 430: for (i = 0; i < shminfo.shmseg; i++, shmd++) ! 431: if (shmd->shmd_uva) ! 432: shmufree(p, shmd); ! 433: free((caddr_t)p->p_vmspace->vm_shm, M_SHM); ! 434: p->p_vmspace->vm_shm = NULL; ! 435: } ! 436: ! 437: shmvalid(id) ! 438: register int id; ! 439: { ! 440: register struct shmid_ds *shp; ! 441: ! 442: if (id < 0 || (id % SHMMMNI) >= shminfo.shmmni) ! 443: return(EINVAL); ! 444: shp = &shmsegs[id % SHMMMNI]; ! 445: if (shp->shm_perm.seq == (id / SHMMMNI) && ! 446: (shp->shm_perm.mode & (SHM_ALLOC|SHM_DEST)) == SHM_ALLOC) ! 447: return(0); ! 448: return(EINVAL); ! 449: } ! 450: ! 451: /* ! 452: * Free user resources associated with a shared memory segment ! 453: */ ! 454: shmufree(p, shmd) ! 455: struct proc *p; ! 456: struct shmdesc *shmd; ! 457: { ! 458: register struct shmid_ds *shp; ! 459: ! 460: shp = &shmsegs[shmd->shmd_id % SHMMMNI]; ! 461: (void) vm_deallocate(&p->p_vmspace->vm_map, shmd->shmd_uva, ! 462: ctob(clrnd(btoc(shp->shm_segsz)))); ! 463: shmd->shmd_id = 0; ! 464: shmd->shmd_uva = 0; ! 465: shp->shm_dtime = time.tv_sec; ! 466: if (--shp->shm_nattch <= 0 && (shp->shm_perm.mode & SHM_DEST)) ! 467: shmfree(shp); ! 468: } ! 469: ! 470: /* ! 471: * Deallocate resources associated with a shared memory segment ! 472: */ ! 473: shmfree(shp) ! 474: register struct shmid_ds *shp; ! 475: { ! 476: ! 477: if (shp->shm_handle == NULL) ! 478: panic("shmfree"); ! 479: /* ! 480: * Lose our lingering object reference by deallocating space ! 481: * in kernel. Pager will also be deallocated as a side-effect. ! 482: */ ! 483: vm_deallocate(shm_map, ! 484: ((struct shmhandle *)shp->shm_handle)->shmh_kva, ! 485: ctob(clrnd(btoc(shp->shm_segsz)))); ! 486: free((caddr_t)shp->shm_handle, M_SHM); ! 487: shp->shm_handle = NULL; ! 488: shmtot -= clrnd(btoc(shp->shm_segsz)); ! 489: shp->shm_perm.mode = 0; ! 490: /* ! 491: * Increment the sequence number to ensure that outstanding ! 492: * shmids for this segment will be invalid in the event that ! 493: * the segment is reallocated. Note that shmids must be ! 494: * positive as decreed by SVID. ! 495: */ ! 496: shp->shm_perm.seq++; ! 497: if ((int)(shp->shm_perm.seq * SHMMMNI) < 0) ! 498: shp->shm_perm.seq = 0; ! 499: } ! 500: ! 501: /* ! 502: * XXX This routine would be common to all sysV style IPC ! 503: * (if the others were implemented). ! 504: */ ! 505: ipcaccess(ipc, mode, cred) ! 506: register struct ipc_perm *ipc; ! 507: int mode; ! 508: register struct ucred *cred; ! 509: { ! 510: register int m; ! 511: ! 512: if (cred->cr_uid == 0) ! 513: return(0); ! 514: /* ! 515: * Access check is based on only one of owner, group, public. ! 516: * If not owner, then check group. ! 517: * If not a member of the group, then check public access. ! 518: */ ! 519: mode &= 0700; ! 520: m = ipc->mode; ! 521: if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) { ! 522: m <<= 3; ! 523: if (!groupmember(ipc->gid, cred) && ! 524: !groupmember(ipc->cgid, cred)) ! 525: m <<= 3; ! 526: } ! 527: if ((mode&m) == mode) ! 528: return (0); ! 529: return (EACCES); ! 530: } ! 531: #endif /* SYSVSHM */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.