]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_shm.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / kern / posix_shm.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
25 * All Rights Reserved.
26 */
27 /*
28 * posix_shm.c : Support for POSIX shared memory APIs
29 *
30 * File: posix_shm.c
31 * Author: Ananthakrishna Ramesh
32 *
33 * HISTORY
34 * 2-Sep-1999 A.Ramesh
35 * Created for MacOSX
36 *
37 */
38
39 #include <sys/cdefs.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/file_internal.h>
44 #include <sys/filedesc.h>
45 #include <sys/stat.h>
46 #include <sys/proc_internal.h>
47 #include <sys/kauth.h>
48 #include <sys/mount.h>
49 #include <sys/namei.h>
50 #include <sys/vnode.h>
51 #include <sys/ioctl.h>
52 #include <sys/tty.h>
53 #include <sys/malloc.h>
54 #include <sys/mman.h>
55 #include <sys/stat.h>
56 #include <sys/sysproto.h>
57
58 #include <bsm/audit_kernel.h>
59
60 #include <mach/mach_types.h>
61 #include <mach/mach_vm.h>
62 #include <mach/vm_map.h>
63 #include <mach/vm_prot.h>
64 #include <mach/vm_inherit.h>
65 #include <mach/kern_return.h>
66 #include <mach/memory_object_control.h>
67
68 #include <vm/vm_map.h>
69 #include <vm/vm_protos.h>
70 #include <vm/vm_shared_memory_server.h>
71
72 #if KTRACE
73 #include <sys/ktrace.h>
74 #endif
75
76 #define f_flag f_fglob->fg_flag
77 #define f_type f_fglob->fg_type
78 #define f_msgcount f_fglob->fg_msgcount
79 #define f_cred f_fglob->fg_cred
80 #define f_ops f_fglob->fg_ops
81 #define f_offset f_fglob->fg_offset
82 #define f_data f_fglob->fg_data
83 #define PSHMNAMLEN 31 /* maximum name segment length we bother with */
84
85 struct pshminfo {
86 unsigned int pshm_flags;
87 unsigned int pshm_usecount;
88 off_t pshm_length;
89 mode_t pshm_mode;
90 uid_t pshm_uid;
91 gid_t pshm_gid;
92 char pshm_name[PSHMNAMLEN + 1]; /* segment name */
93 void * pshm_memobject;
94 #if DIAGNOSTIC
95 unsigned int pshm_readcount;
96 unsigned int pshm_writecount;
97 struct proc * pshm_proc;
98 #endif /* DIAGNOSTIC */
99 };
100 #define PSHMINFO_NULL (struct pshminfo *)0
101
102 #define PSHM_NONE 1
103 #define PSHM_DEFINED 2
104 #define PSHM_ALLOCATED 4
105 #define PSHM_MAPPED 8
106 #define PSHM_INUSE 0x10
107 #define PSHM_REMOVED 0x20
108 #define PSHM_INCREATE 0x40
109 #define PSHM_INDELETE 0x80
110
111 struct pshmcache {
112 LIST_ENTRY(pshmcache) pshm_hash; /* hash chain */
113 struct pshminfo *pshminfo; /* vnode the name refers to */
114 int pshm_nlen; /* length of name */
115 char pshm_name[PSHMNAMLEN + 1]; /* segment name */
116 };
117 #define PSHMCACHE_NULL (struct pshmcache *)0
118
119 struct pshmstats {
120 long goodhits; /* hits that we can really use */
121 long neghits; /* negative hits that we can use */
122 long badhits; /* hits we must drop */
123 long falsehits; /* hits with id mismatch */
124 long miss; /* misses */
125 long longnames; /* long names that ignore cache */
126 };
127
128 struct pshmname {
129 char *pshm_nameptr; /* pointer to looked up name */
130 long pshm_namelen; /* length of looked up component */
131 u_long pshm_hash; /* hash value of looked up name */
132 };
133
134 struct pshmnode {
135 off_t mapp_addr;
136 user_size_t map_size;
137 struct pshminfo *pinfo;
138 unsigned int pshm_usecount;
139 #if DIAGNOSTIC
140 unsigned int readcnt;
141 unsigned int writecnt;
142 #endif
143 };
144 #define PSHMNODE_NULL (struct pshmnode *)0
145
146
147 #define PSHMHASH(pnp) \
148 (&pshmhashtbl[(pnp)->pshm_hash & pshmhash])
149
150 LIST_HEAD(pshmhashhead, pshmcache) *pshmhashtbl; /* Hash Table */
151 u_long pshmhash; /* size of hash table - 1 */
152 long pshmnument; /* number of cache entries allocated */
153 struct pshmstats pshmstats; /* cache effectiveness statistics */
154
155 static int pshm_read (struct fileproc *fp, struct uio *uio,
156 kauth_cred_t cred, int flags, struct proc *p);
157 static int pshm_write (struct fileproc *fp, struct uio *uio,
158 kauth_cred_t cred, int flags, struct proc *p);
159 static int pshm_ioctl (struct fileproc *fp, u_long com,
160 caddr_t data, struct proc *p);
161 static int pshm_select (struct fileproc *fp, int which, void *wql, struct proc *p);
162 static int pshm_close(struct pshmnode *pnode);
163 static int pshm_closefile (struct fileglob *fg, struct proc *p);
164
165 static int pshm_kqfilter(struct fileproc *fp, struct knote *kn, struct proc *p);
166
167 int pshm_access(struct pshminfo *pinfo, int mode, kauth_cred_t cred, struct proc *p);
168 static int pshm_cache_add(struct pshminfo *pshmp, struct pshmname *pnp, struct pshmcache *pcp);
169 static void pshm_cache_delete(struct pshmcache *pcp);
170 #if NOT_USED
171 static void pshm_cache_purge(void);
172 #endif /* NOT_USED */
173 static int pshm_cache_search(struct pshminfo **pshmp, struct pshmname *pnp,
174 struct pshmcache **pcache);
175
176 struct fileops pshmops =
177 { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile, pshm_kqfilter, 0 };
178
179 static lck_grp_t *psx_shm_subsys_lck_grp;
180 static lck_grp_attr_t *psx_shm_subsys_lck_grp_attr;
181 static lck_attr_t *psx_shm_subsys_lck_attr;
182 static lck_mtx_t psx_shm_subsys_mutex;
183
184 #define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex)
185 #define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex)
186
187
188 /* Initialize the mutex governing access to the posix shm subsystem */
189 __private_extern__ void
190 pshm_lock_init( void )
191 {
192
193 psx_shm_subsys_lck_grp_attr = lck_grp_attr_alloc_init();
194 lck_grp_attr_setstat(psx_shm_subsys_lck_grp_attr);
195
196 psx_shm_subsys_lck_grp = lck_grp_alloc_init("posix shared memory", psx_shm_subsys_lck_grp_attr);
197
198 psx_shm_subsys_lck_attr = lck_attr_alloc_init();
199 /* lck_attr_setdebug(psx_shm_subsys_lck_attr); */
200 lck_mtx_init(& psx_shm_subsys_mutex, psx_shm_subsys_lck_grp, psx_shm_subsys_lck_attr);
201 }
202
203 /*
204 * Lookup an entry in the cache
205 *
206 *
207 * status of -1 is returned if matches
208 * If the lookup determines that the name does not exist
209 * (negative cacheing), a status of ENOENT is returned. If the lookup
210 * fails, a status of zero is returned.
211 */
212
213 static int
214 pshm_cache_search(struct pshminfo **pshmp, struct pshmname *pnp,
215 struct pshmcache **pcache)
216 {
217 struct pshmcache *pcp, *nnp;
218 struct pshmhashhead *pcpp;
219
220 if (pnp->pshm_namelen > PSHMNAMLEN) {
221 pshmstats.longnames++;
222 return (0);
223 }
224
225 pcpp = PSHMHASH(pnp);
226 for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) {
227 nnp = pcp->pshm_hash.le_next;
228 if (pcp->pshm_nlen == pnp->pshm_namelen &&
229 !bcmp(pcp->pshm_name, pnp->pshm_nameptr, (u_int)pcp-> pshm_nlen))
230 break;
231 }
232
233 if (pcp == 0) {
234 pshmstats.miss++;
235 return (0);
236 }
237
238 /* We found a "positive" match, return the vnode */
239 if (pcp->pshminfo) {
240 pshmstats.goodhits++;
241 /* TOUCH(ncp); */
242 *pshmp = pcp->pshminfo;
243 *pcache = pcp;
244 return (-1);
245 }
246
247 /*
248 * We found a "negative" match, ENOENT notifies client of this match.
249 * The nc_vpid field records whether this is a whiteout.
250 */
251 pshmstats.neghits++;
252 return (ENOENT);
253 }
254
255 /*
256 * Add an entry to the cache.
257 * XXX should be static?
258 */
259 static int
260 pshm_cache_add(struct pshminfo *pshmp, struct pshmname *pnp, struct pshmcache *pcp)
261 {
262 struct pshmhashhead *pcpp;
263 struct pshminfo *dpinfo;
264 struct pshmcache *dpcp;
265
266 #if DIAGNOSTIC
267 if (pnp->pshm_namelen > NCHNAMLEN)
268 panic("cache_enter: name too long");
269 #endif
270
271
272 /* if the entry has already been added by some one else return */
273 if (pshm_cache_search(&dpinfo, pnp, &dpcp) == -1) {
274 return(EEXIST);
275 }
276 pshmnument++;
277
278 /*
279 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
280 * For negative entries, we have to record whether it is a whiteout.
281 * the whiteout flag is stored in the nc_vpid field which is
282 * otherwise unused.
283 */
284 pcp->pshminfo = pshmp;
285 pcp->pshm_nlen = pnp->pshm_namelen;
286 bcopy(pnp->pshm_nameptr, pcp->pshm_name, (unsigned)pcp->pshm_nlen);
287 pcpp = PSHMHASH(pnp);
288 #if DIAGNOSTIC
289 {
290 struct pshmcache *p;
291
292 for (p = pcpp->lh_first; p != 0; p = p->pshm_hash.le_next)
293 if (p == pcp)
294 panic("cache_enter: duplicate");
295 }
296 #endif
297 LIST_INSERT_HEAD(pcpp, pcp, pshm_hash);
298 return(0);
299 }
300
301 /*
302 * Name cache initialization, from vfs_init() when we are booting
303 */
304 void
305 pshm_cache_init(void)
306 {
307 pshmhashtbl = hashinit(desiredvnodes, M_SHM, &pshmhash);
308 }
309
310 #if NOT_USED
311 /*
312 * Invalidate a all entries to particular vnode.
313 *
314 * We actually just increment the v_id, that will do it. The entries will
315 * be purged by lookup as they get found. If the v_id wraps around, we
316 * need to ditch the entire cache, to avoid confusion. No valid vnode will
317 * ever have (v_id == 0).
318 */
319 static void
320 pshm_cache_purge(void)
321 {
322 struct pshmcache *pcp;
323 struct pshmhashhead *pcpp;
324
325 for (pcpp = &pshmhashtbl[pshmhash]; pcpp >= pshmhashtbl; pcpp--) {
326 while ( (pcp = pcpp->lh_first) )
327 pshm_cache_delete(pcp);
328 }
329 }
330 #endif /* NOT_USED */
331
332 static void
333 pshm_cache_delete(struct pshmcache *pcp)
334 {
335 #if DIAGNOSTIC
336 if (pcp->pshm_hash.le_prev == 0)
337 panic("namecache purge le_prev");
338 if (pcp->pshm_hash.le_next == pcp)
339 panic("namecache purge le_next");
340 #endif /* DIAGNOSTIC */
341 LIST_REMOVE(pcp, pshm_hash);
342 pcp->pshm_hash.le_prev = 0;
343 pshmnument--;
344 }
345
346
347 int
348 shm_open(struct proc *p, struct shm_open_args *uap, register_t *retval)
349 {
350 struct fileproc *fp;
351 size_t i;
352 struct fileproc *nfp;
353 int indx, error;
354 struct pshmname nd;
355 struct pshminfo *pinfo;
356 char * pnbuf;
357 char * nameptr;
358 char * cp;
359 size_t pathlen, plen;
360 int fmode ;
361 int cmode = uap->mode;
362 int incache = 0;
363 struct pshmnode * pnode = PSHMNODE_NULL;
364 struct pshmcache * pcache = PSHMCACHE_NULL;
365 struct pshmcache *pcp;
366 int pinfo_alloc=0;
367
368 AUDIT_ARG(fflags, uap->oflag);
369 AUDIT_ARG(mode, uap->mode);
370
371 pinfo = PSHMINFO_NULL;
372
373 MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
374 if (pnbuf == NULL) {
375 return(ENOSPC);
376 }
377
378 pathlen = MAXPATHLEN;
379 error = copyinstr(uap->name, (void *)pnbuf, MAXPATHLEN, &pathlen);
380 if (error) {
381 goto bad;
382 }
383 AUDIT_ARG(text, pnbuf);
384 if (pathlen > PSHMNAMLEN) {
385 error = ENAMETOOLONG;
386 goto bad;
387 }
388
389
390 #ifdef PSXSHM_NAME_RESTRICT
391 nameptr = pnbuf;
392 if (*nameptr == '/') {
393 while (*(nameptr++) == '/') {
394 plen--;
395 error = EINVAL;
396 goto bad;
397 }
398 } else {
399 error = EINVAL;
400 goto bad;
401 }
402 #endif /* PSXSHM_NAME_RESTRICT */
403
404 plen = pathlen;
405 nameptr = pnbuf;
406 nd.pshm_nameptr = nameptr;
407 nd.pshm_namelen = plen;
408 nd. pshm_hash =0;
409
410 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
411 nd.pshm_hash += (unsigned char)*cp * i;
412 }
413
414 #if KTRACE
415 if (KTRPOINT(p, KTR_NAMEI))
416 ktrnamei(p->p_tracep, nameptr);
417 #endif
418
419 PSHM_SUBSYS_LOCK();
420 error = pshm_cache_search(&pinfo, &nd, &pcache);
421
422 if (error == ENOENT) {
423 PSHM_SUBSYS_UNLOCK();
424 error = EINVAL;
425 goto bad;
426
427 }
428 if (!error) {
429 incache = 0;
430 } else
431 incache = 1;
432 fmode = FFLAGS(uap->oflag);
433 if ((fmode & (FREAD | FWRITE))==0) {
434 PSHM_SUBSYS_UNLOCK();
435 error = EINVAL;
436 goto bad;
437 }
438
439 /*
440 * XXXXXXXXXX TBD XXXXXXXXXX
441 * There is a race that existed with the funnels as well.
442 * Need to be fixed later
443 */
444 PSHM_SUBSYS_UNLOCK();
445 error = falloc(p, &nfp, &indx);
446 if (error )
447 goto bad;
448 PSHM_SUBSYS_LOCK();
449
450 fp = nfp;
451
452 cmode &= ALLPERMS;
453
454 if (fmode & O_CREAT) {
455 if ((fmode & O_EXCL) && incache) {
456 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
457 pinfo->pshm_gid, pinfo->pshm_mode);
458
459 /* shm obj exists and opened O_EXCL */
460 #if notyet
461 if (pinfo->pshm_flags & PSHM_INDELETE) {
462 }
463 #endif
464 error = EEXIST;
465 PSHM_SUBSYS_UNLOCK();
466 goto bad1;
467 }
468 if (!incache) {
469 PSHM_SUBSYS_UNLOCK();
470 /* create a new one */
471 MALLOC(pinfo, struct pshminfo *, sizeof(struct pshminfo), M_SHM, M_WAITOK|M_ZERO);
472 if (pinfo == NULL) {
473 error = ENOSPC;
474 goto bad1;
475 }
476 PSHM_SUBSYS_LOCK();
477 pinfo_alloc = 1;
478 pinfo->pshm_flags = PSHM_DEFINED | PSHM_INCREATE;
479 pinfo->pshm_usecount = 1; /* existence reference */
480 pinfo->pshm_mode = cmode;
481 pinfo->pshm_uid = kauth_cred_getuid(kauth_cred_get());
482 pinfo->pshm_gid = kauth_cred_get()->cr_gid;
483 } else {
484 /* already exists */
485 if( pinfo->pshm_flags & PSHM_INDELETE) {
486 PSHM_SUBSYS_UNLOCK();
487 error = ENOENT;
488 goto bad1;
489 }
490 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
491 pinfo->pshm_gid, pinfo->pshm_mode);
492 if ( (error = pshm_access(pinfo, fmode, kauth_cred_get(), p)) ) {
493 PSHM_SUBSYS_UNLOCK();
494 goto bad1;
495 }
496 }
497 } else {
498 if (!incache) {
499 /* O_CREAT is not set and the shm obecj does not exist */
500 PSHM_SUBSYS_UNLOCK();
501 error = ENOENT;
502 goto bad1;
503 }
504 if( pinfo->pshm_flags & PSHM_INDELETE) {
505 PSHM_SUBSYS_UNLOCK();
506 error = ENOENT;
507 goto bad1;
508 }
509 if ( (error = pshm_access(pinfo, fmode, kauth_cred_get(), p)) ) {
510 PSHM_SUBSYS_UNLOCK();
511 goto bad1;
512 }
513 }
514 if (fmode & O_TRUNC) {
515 PSHM_SUBSYS_UNLOCK();
516 error = EINVAL;
517 goto bad2;
518 }
519 #if DIAGNOSTIC
520 if (fmode & FWRITE)
521 pinfo->pshm_writecount++;
522 if (fmode & FREAD)
523 pinfo->pshm_readcount++;
524 #endif
525 PSHM_SUBSYS_UNLOCK();
526 MALLOC(pnode, struct pshmnode *, sizeof(struct pshmnode), M_SHM, M_WAITOK|M_ZERO);
527 if (pnode == NULL) {
528 error = ENOSPC;
529 goto bad2;
530 }
531 if (!incache) {
532 /*
533 * We allocate a new entry if we are less than the maximum
534 * allowed and the one at the front of the LRU list is in use.
535 * Otherwise we use the one at the front of the LRU list.
536 */
537 MALLOC(pcp, struct pshmcache *, sizeof(struct pshmcache), M_SHM, M_WAITOK|M_ZERO);
538 if (pcp == NULL) {
539 error = ENOSPC;
540 goto bad2;
541 }
542
543 }
544 PSHM_SUBSYS_LOCK();
545
546 if (!incache) {
547 if ( (error = pshm_cache_add(pinfo, &nd, pcp)) ) {
548 PSHM_SUBSYS_UNLOCK();
549 FREE(pcp, M_SHM);
550 goto bad3;
551 }
552 }
553 pinfo->pshm_flags &= ~PSHM_INCREATE;
554 pinfo->pshm_usecount++; /* extra reference for the new fd */
555 pnode->pinfo = pinfo;
556
557 PSHM_SUBSYS_UNLOCK();
558 proc_fdlock(p);
559 fp->f_flag = fmode & FMASK;
560 fp->f_type = DTYPE_PSXSHM;
561 fp->f_ops = &pshmops;
562 fp->f_data = (caddr_t)pnode;
563 *fdflags(p, indx) &= ~UF_RESERVED;
564 fp_drop(p, indx, fp, 1);
565 proc_fdunlock(p);
566
567 *retval = indx;
568 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
569 return (0);
570 bad3:
571 FREE(pnode, M_SHM);
572
573 bad2:
574 if (pinfo_alloc)
575 FREE(pinfo, M_SHM);
576 bad1:
577 fp_free(p, indx, fp);
578 bad:
579 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
580 return (error);
581 }
582
583
584 int
585 pshm_truncate(__unused struct proc *p, struct fileproc *fp, __unused int fd,
586 off_t length, __unused register_t *retval)
587 {
588 struct pshminfo * pinfo;
589 struct pshmnode * pnode ;
590 kern_return_t kret;
591 vm_offset_t user_addr;
592 mem_entry_name_port_t mem_object;
593 vm_size_t size;
594
595 if (fp->f_type != DTYPE_PSXSHM) {
596 return(EINVAL);
597 }
598
599
600 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
601 return(EINVAL);
602
603 PSHM_SUBSYS_LOCK();
604 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) {
605 PSHM_SUBSYS_UNLOCK();
606 return(EINVAL);
607 }
608 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))
609 != PSHM_DEFINED) {
610 PSHM_SUBSYS_UNLOCK();
611 return(EINVAL);
612 }
613
614 PSHM_SUBSYS_UNLOCK();
615 size = round_page_64(length);
616 kret = vm_allocate(current_map(), &user_addr, size, VM_FLAGS_ANYWHERE);
617 if (kret != KERN_SUCCESS)
618 goto out;
619
620 kret = mach_make_memory_entry (current_map(), &size,
621 user_addr, VM_PROT_DEFAULT, &mem_object, 0);
622
623 if (kret != KERN_SUCCESS)
624 goto out;
625
626 vm_deallocate(current_map(), user_addr, size);
627
628 PSHM_SUBSYS_LOCK();
629 pinfo->pshm_flags &= ~PSHM_DEFINED;
630 pinfo->pshm_flags = PSHM_ALLOCATED;
631 pinfo->pshm_memobject = (void *)mem_object;
632 pinfo->pshm_length = size;
633 PSHM_SUBSYS_UNLOCK();
634 return(0);
635
636 out:
637 switch (kret) {
638 case KERN_INVALID_ADDRESS:
639 case KERN_NO_SPACE:
640 return (ENOMEM);
641 case KERN_PROTECTION_FAILURE:
642 return (EACCES);
643 default:
644 return (EINVAL);
645
646 }
647 }
648
649 int
650 pshm_stat(struct pshmnode *pnode, struct stat *sb)
651 {
652 struct pshminfo *pinfo;
653
654 PSHM_SUBSYS_LOCK();
655 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL){
656 PSHM_SUBSYS_UNLOCK();
657 return(EINVAL);
658 }
659
660 bzero(sb, sizeof(struct stat));
661 sb->st_mode = pinfo->pshm_mode;
662 sb->st_uid = pinfo->pshm_uid;
663 sb->st_gid = pinfo->pshm_gid;
664 sb->st_size = pinfo->pshm_length;
665 PSHM_SUBSYS_UNLOCK();
666
667 return(0);
668 }
669
670 /*
671 * This is called only from shm_open which holds pshm_lock();
672 * XXX This code is repeated many times
673 */
674 int
675 pshm_access(struct pshminfo *pinfo, int mode, kauth_cred_t cred, __unused struct proc *p)
676 {
677 mode_t mask;
678 int is_member;
679
680 /* Otherwise, user id 0 always gets access. */
681 if (!suser(cred, NULL))
682 return (0);
683
684 mask = 0;
685
686 /* Otherwise, check the owner. */
687 if (kauth_cred_getuid(cred) == pinfo->pshm_uid) {
688 if (mode & FREAD)
689 mask |= S_IRUSR;
690 if (mode & FWRITE)
691 mask |= S_IWUSR;
692 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
693 }
694
695 /* Otherwise, check the groups. */
696 if (kauth_cred_ismember_gid(cred, pinfo->pshm_gid, &is_member) == 0 && is_member) {
697 if (mode & FREAD)
698 mask |= S_IRGRP;
699 if (mode & FWRITE)
700 mask |= S_IWGRP;
701 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
702 }
703
704 /* Otherwise, check everyone else. */
705 if (mode & FREAD)
706 mask |= S_IROTH;
707 if (mode & FWRITE)
708 mask |= S_IWOTH;
709 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
710 }
711
712 int
713 pshm_mmap(struct proc *p, struct mmap_args *uap, user_addr_t *retval, struct fileproc *fp, off_t pageoff)
714 {
715 mach_vm_offset_t user_addr = (mach_vm_offset_t)uap->addr;
716 mach_vm_size_t user_size = (mach_vm_size_t)uap->len ;
717 int prot = uap->prot;
718 int flags = uap->flags;
719 vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
720 int fd = uap->fd;
721 vm_map_t user_map;
722 int alloc_flags;
723 boolean_t docow;
724 kern_return_t kret;
725 struct pshminfo * pinfo;
726 struct pshmnode * pnode;
727 void * mem_object;
728
729 if (user_size == 0)
730 return(0);
731
732 if ((flags & MAP_SHARED) == 0)
733 return(EINVAL);
734
735
736 if ((prot & PROT_WRITE) && ((fp->f_flag & FWRITE) == 0)) {
737 return(EPERM);
738 }
739
740 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
741 return(EINVAL);
742
743 PSHM_SUBSYS_LOCK();
744 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL) {
745 PSHM_SUBSYS_UNLOCK();
746 return(EINVAL);
747 }
748
749 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
750 PSHM_SUBSYS_UNLOCK();
751 return(EINVAL);
752 }
753 if ((off_t)user_size > pinfo->pshm_length) {
754 PSHM_SUBSYS_UNLOCK();
755 return(EINVAL);
756 }
757 if ((off_t)(user_size + file_pos) > pinfo->pshm_length) {
758 PSHM_SUBSYS_UNLOCK();
759 return(EINVAL);
760 }
761 if ((mem_object = pinfo->pshm_memobject) == NULL) {
762 PSHM_SUBSYS_UNLOCK();
763 return(EINVAL);
764 }
765
766
767 PSHM_SUBSYS_UNLOCK();
768 user_map = current_map();
769
770 if ((flags & MAP_FIXED) == 0) {
771 alloc_flags = VM_FLAGS_ANYWHERE;
772 user_addr = mach_vm_round_page(user_addr);
773 } else {
774 if (user_addr != mach_vm_trunc_page(user_addr))
775 return (EINVAL);
776 /*
777 * We do not get rid of the existing mappings here because
778 * it wouldn't be atomic (see comment in mmap()). We let
779 * Mach VM know that we want it to replace any existing
780 * mapping with the new one.
781 */
782 alloc_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
783 }
784 docow = FALSE;
785
786 kret = mach_vm_map(user_map, &user_addr, user_size,
787 0, alloc_flags, pinfo->pshm_memobject, file_pos, docow,
788 prot, VM_PROT_DEFAULT,
789 VM_INHERIT_SHARE);
790 if (kret != KERN_SUCCESS)
791 goto out;
792 /* LP64todo - this should be superfluous at this point */
793 kret = mach_vm_inherit(user_map, user_addr, user_size,
794 VM_INHERIT_SHARE);
795 if (kret != KERN_SUCCESS) {
796 (void) mach_vm_deallocate(user_map, user_addr, user_size);
797 goto out;
798 }
799 PSHM_SUBSYS_LOCK();
800 pnode->mapp_addr = user_addr;
801 pnode->map_size = user_size;
802 pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
803 PSHM_SUBSYS_UNLOCK();
804 out:
805 switch (kret) {
806 case KERN_SUCCESS:
807 *retval = (user_addr + pageoff);
808 return (0);
809 case KERN_INVALID_ADDRESS:
810 case KERN_NO_SPACE:
811 return (ENOMEM);
812 case KERN_PROTECTION_FAILURE:
813 return (EACCES);
814 default:
815 return (EINVAL);
816 }
817
818 }
819
820 int
821 shm_unlink(__unused struct proc *p, struct shm_unlink_args *uap,
822 __unused register_t *retval)
823 {
824 size_t i;
825 int error=0;
826 struct pshmname nd;
827 struct pshminfo *pinfo;
828 char * pnbuf;
829 char * nameptr;
830 char * cp;
831 size_t pathlen, plen;
832 int incache = 0;
833 struct pshmcache *pcache = PSHMCACHE_NULL;
834
835 pinfo = PSHMINFO_NULL;
836
837 MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
838 if (pnbuf == NULL) {
839 return(ENOSPC); /* XXX non-standard */
840 }
841 pathlen = MAXPATHLEN;
842 error = copyinstr(uap->name, (void *)pnbuf, MAXPATHLEN, &pathlen);
843 if (error) {
844 goto bad;
845 }
846 AUDIT_ARG(text, pnbuf);
847 if (pathlen > PSHMNAMLEN) {
848 error = ENAMETOOLONG;
849 goto bad;
850 }
851
852
853 #ifdef PSXSHM_NAME_RESTRICT
854 nameptr = pnbuf;
855 if (*nameptr == '/') {
856 while (*(nameptr++) == '/') {
857 plen--;
858 error = EINVAL;
859 goto bad;
860 }
861 } else {
862 error = EINVAL;
863 goto bad;
864 }
865 #endif /* PSXSHM_NAME_RESTRICT */
866
867 plen = pathlen;
868 nameptr = pnbuf;
869 nd.pshm_nameptr = nameptr;
870 nd.pshm_namelen = plen;
871 nd. pshm_hash =0;
872
873 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
874 nd.pshm_hash += (unsigned char)*cp * i;
875 }
876
877 PSHM_SUBSYS_LOCK();
878 error = pshm_cache_search(&pinfo, &nd, &pcache);
879
880 if (error == ENOENT) {
881 PSHM_SUBSYS_UNLOCK();
882 error = EINVAL;
883 goto bad;
884
885 }
886 if (!error) {
887 PSHM_SUBSYS_UNLOCK();
888 error = EINVAL;
889 goto bad;
890 } else
891 incache = 1;
892
893 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))==0) {
894 PSHM_SUBSYS_UNLOCK();
895 return (EINVAL);
896 }
897
898 if (pinfo->pshm_flags & PSHM_INDELETE) {
899 PSHM_SUBSYS_UNLOCK();
900 error = 0;
901 goto bad;
902 }
903
904 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid, pinfo->pshm_gid,
905 pinfo->pshm_mode);
906
907 /*
908 * JMM - How should permissions be checked?
909 */
910
911 pinfo->pshm_flags |= PSHM_INDELETE;
912 pshm_cache_delete(pcache);
913 pinfo->pshm_flags |= PSHM_REMOVED;
914 /* release the existence reference */
915 if (!--pinfo->pshm_usecount) {
916 PSHM_SUBSYS_UNLOCK();
917 /*
918 * If this is the last reference going away on the object,
919 * then we need to destroy the backing object. The name
920 * has an implied but uncounted reference on the object,
921 * once it's created, since it's used as a rendesvous, and
922 * therefore may be subsequently reopened.
923 */
924 if (pinfo->pshm_memobject != NULL)
925 mach_memory_entry_port_release(pinfo->pshm_memobject);
926 PSHM_SUBSYS_LOCK();
927 FREE(pinfo,M_SHM);
928 }
929 PSHM_SUBSYS_UNLOCK();
930 FREE(pcache, M_SHM);
931 error = 0;
932 bad:
933 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
934 return (error);
935 }
936
937 /* already called locked */
938 static int
939 pshm_close(struct pshmnode *pnode)
940 {
941 int error=0;
942 struct pshminfo *pinfo;
943
944 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
945 return(EINVAL);
946
947 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
948 return(EINVAL);
949 }
950 #if DIAGNOSTIC
951 if(!pinfo->pshm_usecount) {
952 kprintf("negative usecount in pshm_close\n");
953 }
954 #endif /* DIAGNOSTIC */
955 pinfo->pshm_usecount--; /* release this fd's reference */
956
957 if ((pinfo->pshm_flags & PSHM_REMOVED) && !pinfo->pshm_usecount) {
958 PSHM_SUBSYS_UNLOCK();
959 /*
960 * If this is the last reference going away on the object,
961 * then we need to destroy the backing object.
962 */
963 if (pinfo->pshm_memobject != NULL)
964 mach_memory_entry_port_release(pinfo->pshm_memobject);
965 PSHM_SUBSYS_LOCK();
966 FREE(pinfo,M_SHM);
967 }
968 FREE(pnode, M_SHM);
969 return (error);
970 }
971
972 /* struct proc passed to match prototype for struct fileops */
973 static int
974 pshm_closefile(struct fileglob *fg, __unused struct proc *p)
975 {
976 int error;
977
978 PSHM_SUBSYS_LOCK();
979 error = pshm_close(((struct pshmnode *)fg->fg_data));
980 PSHM_SUBSYS_UNLOCK();
981 return(error);
982 }
983
984 static int
985 pshm_read(__unused struct fileproc *fp, __unused struct uio *uio,
986 __unused kauth_cred_t cred, __unused int flags,
987 __unused struct proc *p)
988 {
989 return(ENOTSUP);
990 }
991
992 static int
993 pshm_write(__unused struct fileproc *fp, __unused struct uio *uio,
994 __unused kauth_cred_t cred, __unused int flags,
995 __unused struct proc *p)
996 {
997 return(ENOTSUP);
998 }
999
1000 static int
1001 pshm_ioctl(__unused struct fileproc *fp, __unused u_long com,
1002 __unused caddr_t data, __unused struct proc *p)
1003 {
1004 return(ENOTSUP);
1005 }
1006
1007 static int
1008 pshm_select(__unused struct fileproc *fp, __unused int which, __unused void *wql,
1009 __unused struct proc *p)
1010 {
1011 return(ENOTSUP);
1012 }
1013
1014 static int
1015 pshm_kqfilter(__unused struct fileproc *fp, __unused struct knote *kn,
1016 __unused struct proc *p)
1017 {
1018 return(ENOTSUP);
1019 }