Annotation of Net2/kern/sysv_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 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:  *     @(#)sysv_shm.c  7.15 (Berkeley) 5/13/91
                     41:  */
                     42: 
                     43: /*
                     44:  * System V shared memory routines.
                     45:  * TEMPORARY, until mmap is in place;
                     46:  * needed now for HP-UX compatibility and X server (yech!).
                     47:  */
                     48: 
                     49: #ifdef SYSVSHM
                     50: 
                     51: #include "param.h"
                     52: #include "systm.h"
                     53: #include "kernel.h"
                     54: #include "proc.h"
                     55: #include "shm.h"
                     56: #include "malloc.h"
                     57: #include "mman.h"
                     58: #include "vm/vm.h"
                     59: #include "vm/vm_kern.h"
                     60: #include "vm/vm_inherit.h"
                     61: #include "vm/vm_pager.h"
                     62: 
                     63: #ifdef HPUXCOMPAT
                     64: #include "hp300/hpux/hpux.h"
                     65: #endif
                     66: 
                     67: int    shmat(), shmctl(), shmdt(), shmget();
                     68: int    (*shmcalls[])() = { shmat, shmctl, shmdt, shmget };
                     69: int    shmtot = 0;
                     70: 
                     71: /*
                     72:  * Per process internal structure for managing segments.
                     73:  * Each process using shm will have an array of ``shmseg'' of these.
                     74:  */
                     75: struct shmdesc {
                     76:        vm_offset_t     shmd_uva;
                     77:        int             shmd_id;
                     78: };
                     79: 
                     80: /*
                     81:  * Per segment internal structure (shm_handle).
                     82:  */
                     83: struct shmhandle {
                     84:        vm_offset_t     shmh_kva;
                     85:        caddr_t         shmh_id;
                     86: };
                     87: 
                     88: vm_map_t shm_map;      /* address space for shared memory segments */
                     89: 
                     90: shminit()
                     91: {
                     92:        register int i;
                     93:        vm_offset_t whocares1, whocares2;
                     94: 
                     95:        shm_map = kmem_suballoc(kernel_map, &whocares1, &whocares2,
                     96:                                shminfo.shmall * NBPG, FALSE);
                     97:        if (shminfo.shmmni > SHMMMNI)
                     98:                shminfo.shmmni = SHMMMNI;
                     99:        for (i = 0; i < shminfo.shmmni; i++) {
                    100:                shmsegs[i].shm_perm.mode = 0;
                    101:                shmsegs[i].shm_perm.seq = 0;
                    102:        }
                    103: }
                    104: 
                    105: /*
                    106:  * Entry point for all SHM calls
                    107:  */
                    108: shmsys(p, uap, retval)
                    109:        struct proc *p;
                    110:        struct args {
                    111:                u_int which;
                    112:        } *uap;
                    113:        int *retval;
                    114: {
                    115: 
                    116:        if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
                    117:                return (EINVAL);
                    118:        return ((*shmcalls[uap->which])(p, &uap[1], retval));
                    119: }
                    120: 
                    121: /*
                    122:  * Get a shared memory segment
                    123:  */
                    124: shmget(p, uap, retval)
                    125:        struct proc *p;
                    126:        register struct args {
                    127:                key_t key;
                    128:                int size;
                    129:                int shmflg;
                    130:        } *uap;
                    131:        int *retval;
                    132: {
                    133:        register struct shmid_ds *shp;
                    134:        register struct ucred *cred = p->p_ucred;
                    135:        register int i;
                    136:        int error, size, rval = 0;
                    137:        register struct shmhandle *shmh;
                    138: 
                    139:        /* look up the specified shm_id */
                    140:        if (uap->key != IPC_PRIVATE) {
                    141:                for (i = 0; i < shminfo.shmmni; i++)
                    142:                        if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) &&
                    143:                            shmsegs[i].shm_perm.key == uap->key) {
                    144:                                rval = i;
                    145:                                break;
                    146:                        }
                    147:        } else
                    148:                i = shminfo.shmmni;
                    149: 
                    150:        /* create a new shared segment if necessary */
                    151:        if (i == shminfo.shmmni) {
                    152:                if ((uap->shmflg & IPC_CREAT) == 0)
                    153:                        return (ENOENT);
                    154:                if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
                    155:                        return (EINVAL);
                    156:                for (i = 0; i < shminfo.shmmni; i++)
                    157:                        if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) == 0) {
                    158:                                rval = i;
                    159:                                break;
                    160:                        }
                    161:                if (i == shminfo.shmmni)
                    162:                        return (ENOSPC);
                    163:                size = clrnd(btoc(uap->size));
                    164:                if (shmtot + size > shminfo.shmall)
                    165:                        return (ENOMEM);
                    166:                shp = &shmsegs[rval];
                    167:                /*
                    168:                 * We need to do a couple of things to ensure consistency
                    169:                 * in case we sleep in malloc().  We mark segment as
                    170:                 * allocated so that other shmgets() will not allocate it.
                    171:                 * We mark it as "destroyed" to insure that shmvalid() is
                    172:                 * false making most operations fail (XXX).  We set the key,
                    173:                 * so that other shmget()s will fail.
                    174:                 */
                    175:                shp->shm_perm.mode = SHM_ALLOC | SHM_DEST;
                    176:                shp->shm_perm.key = uap->key;
                    177:                shmh = (struct shmhandle *)
                    178:                        malloc(sizeof(struct shmhandle), M_SHM, M_WAITOK);
                    179:                shmh->shmh_kva = 0;
                    180:                shmh->shmh_id = (caddr_t)(0xc0000000|rval);     /* XXX */
                    181:                error = vm_mmap(shm_map, &shmh->shmh_kva, ctob(size),
                    182:                                VM_PROT_ALL, MAP_ANON, shmh->shmh_id, 0);
                    183:                if (error) {
                    184:                        free((caddr_t)shmh, M_SHM);
                    185:                        shp->shm_perm.mode = 0;
                    186:                        return(ENOMEM);
                    187:                }
                    188:                shp->shm_handle = (void *) shmh;
                    189:                shmtot += size;
                    190:                shp->shm_perm.cuid = shp->shm_perm.uid = cred->cr_uid;
                    191:                shp->shm_perm.cgid = shp->shm_perm.gid = cred->cr_gid;
                    192:                shp->shm_perm.mode = SHM_ALLOC | (uap->shmflg&0777);
                    193:                shp->shm_segsz = uap->size;
                    194:                shp->shm_cpid = p->p_pid;
                    195:                shp->shm_lpid = shp->shm_nattch = 0;
                    196:                shp->shm_atime = shp->shm_dtime = 0;
                    197:                shp->shm_ctime = time.tv_sec;
                    198:        } else {
                    199:                shp = &shmsegs[rval];
                    200:                /* XXX: probably not the right thing to do */
                    201:                if (shp->shm_perm.mode & SHM_DEST)
                    202:                        return (EBUSY);
                    203:                if (error = ipcaccess(&shp->shm_perm, uap->shmflg&0777, cred))
                    204:                        return (error);
                    205:                if (uap->size && uap->size > shp->shm_segsz)
                    206:                        return (EINVAL);
                    207:                if ((uap->shmflg&IPC_CREAT) && (uap->shmflg&IPC_EXCL))
                    208:                        return (EEXIST);
                    209:        }
                    210:        *retval = shp->shm_perm.seq * SHMMMNI + rval;
                    211:        return (0);
                    212: }
                    213: 
                    214: /*
                    215:  * Shared memory control
                    216:  */
                    217: /* ARGSUSED */
                    218: shmctl(p, uap, retval)
                    219:        struct proc *p;
                    220:        register struct args {
                    221:                int shmid;
                    222:                int cmd;
                    223:                caddr_t buf;
                    224:        } *uap;
                    225:        int *retval;
                    226: {
                    227:        register struct shmid_ds *shp;
                    228:        register struct ucred *cred = p->p_ucred;
                    229:        struct shmid_ds sbuf;
                    230:        int error;
                    231: 
                    232:        if (error = shmvalid(uap->shmid))
                    233:                return (error);
                    234:        shp = &shmsegs[uap->shmid % SHMMMNI];
                    235:        switch (uap->cmd) {
                    236:        case IPC_STAT:
                    237:                if (error = ipcaccess(&shp->shm_perm, IPC_R, cred))
                    238:                        return (error);
                    239:                return (copyout((caddr_t)shp, uap->buf, sizeof(*shp)));
                    240: 
                    241:        case IPC_SET:
                    242:                if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
                    243:                    cred->cr_uid != shp->shm_perm.cuid)
                    244:                        return (EPERM);
                    245:                if (error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf))
                    246:                        return (error);
                    247:                shp->shm_perm.uid = sbuf.shm_perm.uid;
                    248:                shp->shm_perm.gid = sbuf.shm_perm.gid;
                    249:                shp->shm_perm.mode = (shp->shm_perm.mode & ~0777)
                    250:                        | (sbuf.shm_perm.mode & 0777);
                    251:                shp->shm_ctime = time.tv_sec;
                    252:                break;
                    253: 
                    254:        case IPC_RMID:
                    255:                if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
                    256:                    cred->cr_uid != shp->shm_perm.cuid)
                    257:                        return (EPERM);
                    258:                /* set ctime? */
                    259:                shp->shm_perm.key = IPC_PRIVATE;
                    260:                shp->shm_perm.mode |= SHM_DEST;
                    261:                if (shp->shm_nattch <= 0)
                    262:                        shmfree(shp);
                    263:                break;
                    264: 
                    265: #ifdef HPUXCOMPAT
                    266:        case SHM_LOCK:
                    267:        case SHM_UNLOCK:
                    268:                /* don't really do anything, but make them think we did */
                    269:                if ((p->p_flag & SHPUX) == 0)
                    270:                        return (EINVAL);
                    271:                if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
                    272:                    cred->cr_uid != shp->shm_perm.cuid)
                    273:                        return (EPERM);
                    274:                break;
                    275: #endif
                    276: 
                    277:        default:
                    278:                return (EINVAL);
                    279:        }
                    280:        return (0);
                    281: }
                    282: 
                    283: /*
                    284:  * Attach to shared memory segment.
                    285:  */
                    286: shmat(p, uap, retval)
                    287:        struct proc *p;
                    288:        register struct args {
                    289:                int     shmid;
                    290:                caddr_t shmaddr;
                    291:                int     shmflg;
                    292:        } *uap;
                    293:        int *retval;
                    294: {
                    295:        register struct shmid_ds *shp;
                    296:        register int size;
                    297:        caddr_t uva;
                    298:        int error;
                    299:        int flags;
                    300:        vm_prot_t prot;
                    301:        struct shmdesc *shmd;
                    302: 
                    303:        /*
                    304:         * Allocate descriptors now (before validity check)
                    305:         * in case malloc() blocks.
                    306:         */
                    307:        shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
                    308:        size = shminfo.shmseg * sizeof(struct shmdesc);
                    309:        if (shmd == NULL) {
                    310:                shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
                    311:                bzero((caddr_t)shmd, size);
                    312:                p->p_vmspace->vm_shm = (caddr_t)shmd;
                    313:        }
                    314:        if (error = shmvalid(uap->shmid))
                    315:                return (error);
                    316:        shp = &shmsegs[uap->shmid % SHMMMNI];
                    317:        if (shp->shm_handle == NULL)
                    318:                panic("shmat NULL handle");
                    319:        if (error = ipcaccess(&shp->shm_perm,
                    320:            (uap->shmflg&SHM_RDONLY) ? IPC_R : IPC_R|IPC_W, p->p_ucred))
                    321:                return (error);
                    322:        uva = uap->shmaddr;
                    323:        if (uva && ((int)uva & (SHMLBA-1))) {
                    324:                if (uap->shmflg & SHM_RND)
                    325:                        uva = (caddr_t) ((int)uva & ~(SHMLBA-1));
                    326:                else
                    327:                        return (EINVAL);
                    328:        }
                    329:        /*
                    330:         * Make sure user doesn't use more than their fair share
                    331:         */
                    332:        for (size = 0; size < shminfo.shmseg; size++) {
                    333:                if (shmd->shmd_uva == 0)
                    334:                        break;
                    335:                shmd++;
                    336:        }
                    337:        if (size >= shminfo.shmseg)
                    338:                return (EMFILE);
                    339:        size = ctob(clrnd(btoc(shp->shm_segsz)));
                    340:        prot = VM_PROT_READ;
                    341:        if ((uap->shmflg & SHM_RDONLY) == 0)
                    342:                prot |= VM_PROT_WRITE;
                    343:        flags = MAP_ANON|MAP_SHARED;
                    344:        if (uva)
                    345:                flags |= MAP_FIXED;
                    346:        else
                    347:                uva = (caddr_t)0x1000000;       /* XXX */
                    348:        error = vm_mmap(&p->p_vmspace->vm_map, &uva, (vm_size_t)size, prot,
                    349:            flags, ((struct shmhandle *)shp->shm_handle)->shmh_id, 0);
                    350:        if (error)
                    351:                return(error);
                    352:        shmd->shmd_uva = (vm_offset_t)uva;
                    353:        shmd->shmd_id = uap->shmid;
                    354:        /*
                    355:         * Fill in the remaining fields
                    356:         */
                    357:        shp->shm_lpid = p->p_pid;
                    358:        shp->shm_atime = time.tv_sec;
                    359:        shp->shm_nattch++;
                    360:        *retval = (int) uva;
                    361:        return (0);
                    362: }
                    363: 
                    364: /*
                    365:  * Detach from shared memory segment.
                    366:  */
                    367: /* ARGSUSED */
                    368: shmdt(p, uap, retval)
                    369:        struct proc *p;
                    370:        struct args {
                    371:                caddr_t shmaddr;
                    372:        } *uap;
                    373:        int *retval;
                    374: {
                    375:        register struct shmdesc *shmd;
                    376:        register int i;
                    377: 
                    378:        shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
                    379:        for (i = 0; i < shminfo.shmseg; i++, shmd++)
                    380:                if (shmd->shmd_uva &&
                    381:                    shmd->shmd_uva == (vm_offset_t)uap->shmaddr)
                    382:                        break;
                    383:        if (i == shminfo.shmseg)
                    384:                return(EINVAL);
                    385:        shmufree(p, shmd);
                    386:        shmsegs[shmd->shmd_id % SHMMMNI].shm_lpid = p->p_pid;
                    387: }
                    388: 
                    389: shmfork(p1, p2, isvfork)
                    390:        struct proc *p1, *p2;
                    391:        int isvfork;
                    392: {
                    393:        register struct shmdesc *shmd;
                    394:        register int size;
                    395: 
                    396:        /*
                    397:         * Copy parents descriptive information
                    398:         */
                    399:        size = shminfo.shmseg * sizeof(struct shmdesc);
                    400:        shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
                    401:        bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmd, size);
                    402:        p2->p_vmspace->vm_shm = (caddr_t)shmd;
                    403:        /*
                    404:         * Increment reference counts
                    405:         */
                    406:        for (size = 0; size < shminfo.shmseg; size++, shmd++)
                    407:                if (shmd->shmd_uva)
                    408:                        shmsegs[shmd->shmd_id % SHMMMNI].shm_nattch++;
                    409: }
                    410: 
                    411: shmexit(p)
                    412:        struct proc *p;
                    413: {
                    414:        register struct shmdesc *shmd;
                    415:        register int i;
                    416: 
                    417:        shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
                    418:        for (i = 0; i < shminfo.shmseg; i++, shmd++)
                    419:                if (shmd->shmd_uva)
                    420:                        shmufree(p, shmd);
                    421:        free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
                    422:        p->p_vmspace->vm_shm = NULL;
                    423: }
                    424: 
                    425: shmvalid(id)
                    426:        register int id;
                    427: {
                    428:        register struct shmid_ds *shp;
                    429: 
                    430:        if (id < 0 || (id % SHMMMNI) >= shminfo.shmmni)
                    431:                return(EINVAL);
                    432:        shp = &shmsegs[id % SHMMMNI];
                    433:        if (shp->shm_perm.seq == (id / SHMMMNI) &&
                    434:            (shp->shm_perm.mode & (SHM_ALLOC|SHM_DEST)) == SHM_ALLOC)
                    435:                return(0);
                    436:        return(EINVAL);
                    437: }
                    438: 
                    439: /*
                    440:  * Free user resources associated with a shared memory segment
                    441:  */
                    442: shmufree(p, shmd)
                    443:        struct proc *p;
                    444:        struct shmdesc *shmd;
                    445: {
                    446:        register struct shmid_ds *shp;
                    447: 
                    448:        shp = &shmsegs[shmd->shmd_id % SHMMMNI];
                    449:        (void) vm_deallocate(&p->p_vmspace->vm_map, shmd->shmd_uva,
                    450:                             ctob(clrnd(btoc(shp->shm_segsz))));
                    451:        shmd->shmd_id = 0;
                    452:        shmd->shmd_uva = 0;
                    453:        shp->shm_dtime = time.tv_sec;
                    454:        if (--shp->shm_nattch <= 0 && (shp->shm_perm.mode & SHM_DEST))
                    455:                shmfree(shp);
                    456: }
                    457: 
                    458: /*
                    459:  * Deallocate resources associated with a shared memory segment
                    460:  */
                    461: shmfree(shp)
                    462:        register struct shmid_ds *shp;
                    463: {
                    464: 
                    465:        if (shp->shm_handle == NULL)
                    466:                panic("shmfree");
                    467:        /*
                    468:         * Lose our lingering object reference by deallocating space
                    469:         * in kernel.  Pager will also be deallocated as a side-effect.
                    470:         */
                    471:        vm_deallocate(shm_map,
                    472:                      ((struct shmhandle *)shp->shm_handle)->shmh_kva,
                    473:                      ctob(clrnd(btoc(shp->shm_segsz))));
                    474:        free((caddr_t)shp->shm_handle, M_SHM);
                    475:        shp->shm_handle = NULL;
                    476:        shmtot -= clrnd(btoc(shp->shm_segsz));
                    477:        shp->shm_perm.mode = 0;
                    478:        /*
                    479:         * Increment the sequence number to ensure that outstanding
                    480:         * shmids for this segment will be invalid in the event that
                    481:         * the segment is reallocated.  Note that shmids must be
                    482:         * positive as decreed by SVID.
                    483:         */
                    484:        shp->shm_perm.seq++;
                    485:        if ((int)(shp->shm_perm.seq * SHMMMNI) < 0)
                    486:                shp->shm_perm.seq = 0;
                    487: }
                    488: 
                    489: /*
                    490:  * XXX This routine would be common to all sysV style IPC
                    491:  *     (if the others were implemented).
                    492:  */
                    493: ipcaccess(ipc, mode, cred)
                    494:        register struct ipc_perm *ipc;
                    495:        int mode;
                    496:        register struct ucred *cred;
                    497: {
                    498:        register int m;
                    499: 
                    500:        if (cred->cr_uid == 0)
                    501:                return(0);
                    502:        /*
                    503:         * Access check is based on only one of owner, group, public.
                    504:         * If not owner, then check group.
                    505:         * If not a member of the group, then check public access.
                    506:         */
                    507:        mode &= 0700;
                    508:        m = ipc->mode;
                    509:        if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) {
                    510:                m <<= 3;
                    511:                if (!groupmember(ipc->gid, cred) &&
                    512:                    !groupmember(ipc->cgid, cred))
                    513:                        m <<= 3;
                    514:        }
                    515:        if ((mode&m) == mode)
                    516:                return (0);
                    517:        return (EACCES);
                    518: }
                    519: #endif /* SYSVSHM */

unix.superglobalmegacorp.com

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