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