Annotation of 43BSDReno/sys/kern/uipc_shm.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.