|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.