|
|
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.