2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  *      Copyright (c) 1990, 1996-1998 Apple Computer, Inc. 
  30  *      All Rights Reserved. 
  33  * posix_shm.c : Support for POSIX shared memory APIs 
  36  *      Author: Ananthakrishna Ramesh 
  44  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 
  45  * support for mandatory and extensible security protections.  This notice 
  46  * is included in support of clause 2.2 (b) of the Apple Public License, 
  50 #include <sys/cdefs.h> 
  51 #include <sys/param.h> 
  52 #include <sys/systm.h> 
  53 #include <sys/kernel.h> 
  54 #include <sys/file_internal.h> 
  55 #include <sys/filedesc.h> 
  57 #include <sys/proc_internal.h> 
  58 #include <sys/kauth.h> 
  59 #include <sys/mount.h> 
  60 #include <sys/namei.h> 
  61 #include <sys/vnode.h> 
  62 #include <sys/vnode_internal.h> 
  63 #include <sys/ioctl.h> 
  65 #include <sys/malloc.h> 
  68 #include <sys/sysproto.h> 
  69 #include <sys/proc_info.h> 
  70 #include <bsm/audit_kernel.h> 
  73 #include <security/mac_framework.h> 
  76 #include <mach/mach_types.h> 
  77 #include <mach/mach_vm.h> 
  78 #include <mach/vm_map.h> 
  79 #include <mach/vm_prot.h> 
  80 #include <mach/vm_inherit.h> 
  81 #include <mach/kern_return.h> 
  82 #include <mach/memory_object_control.h> 
  84 #include <vm/vm_map.h> 
  85 #include <vm/vm_protos.h> 
  87 #define f_flag f_fglob->fg_flag 
  88 #define f_type f_fglob->fg_type 
  89 #define f_msgcount f_fglob->fg_msgcount 
  90 #define f_cred f_fglob->fg_cred 
  91 #define f_ops f_fglob->fg_ops 
  92 #define f_offset f_fglob->fg_offset 
  93 #define f_data f_fglob->fg_data 
  94 #define PSHMNAMLEN      31      /* maximum name segment length we bother with */ 
  97         unsigned int    pshm_flags
; 
  98         unsigned int    pshm_usecount
; 
 103         char            pshm_name
[PSHMNAMLEN 
+ 1];      /* segment name */ 
 104         void *          pshm_memobject
; 
 106         unsigned int    pshm_readcount
; 
 107         unsigned int    pshm_writecount
; 
 109 #endif /* DIAGNOSTIC */ 
 110         struct label
*   pshm_label
; 
 112 #define PSHMINFO_NULL (struct pshminfo *)0 
 115 #define PSHM_DEFINED    2 
 116 #define PSHM_ALLOCATED  4 
 117 #define PSHM_MAPPED     8 
 118 #define PSHM_INUSE      0x10 
 119 #define PSHM_REMOVED    0x20 
 120 #define PSHM_INCREATE   0x40 
 121 #define PSHM_INDELETE   0x80 
 124         LIST_ENTRY(pshmcache
) pshm_hash
;        /* hash chain */ 
 125         struct  pshminfo 
*pshminfo
;             /* vnode the name refers to */ 
 126         int     pshm_nlen
;              /* length of name */ 
 127         char    pshm_name
[PSHMNAMLEN 
+ 1];      /* segment name */ 
 129 #define PSHMCACHE_NULL (struct pshmcache *)0 
 132         long    goodhits
;               /* hits that we can really use */ 
 133         long    neghits
;                /* negative hits that we can use */ 
 134         long    badhits
;                /* hits we must drop */ 
 135         long    falsehits
;              /* hits with id mismatch */ 
 136         long    miss
;           /* misses */ 
 137         long    longnames
;              /* long names that ignore cache */ 
 141         char    *pshm_nameptr
;  /* pointer to looked up name */ 
 142         long    pshm_namelen
;   /* length of looked up component */ 
 143         u_long  pshm_hash
;      /* hash value of looked up name */ 
 148         user_size_t     map_size
; 
 149         struct pshminfo 
*pinfo
; 
 150         unsigned int    pshm_usecount
; 
 152         unsigned int readcnt
; 
 153         unsigned int writecnt
; 
 156 #define PSHMNODE_NULL (struct pshmnode *)0 
 159 #define PSHMHASH(pnp) \ 
 160         (&pshmhashtbl[(pnp)->pshm_hash & pshmhash]) 
 162 LIST_HEAD(pshmhashhead
, pshmcache
) *pshmhashtbl
;        /* Hash Table */ 
 163 u_long  pshmhash
;                               /* size of hash table - 1 */ 
 164 long    pshmnument
;                     /* number of cache entries allocated */ 
 165 struct pshmstats pshmstats
;             /* cache effectiveness statistics */ 
 167 static int pshm_read (struct fileproc 
*fp
, struct uio 
*uio
, 
 168                     int flags
, vfs_context_t ctx
); 
 169 static int pshm_write (struct fileproc 
*fp
, struct uio 
*uio
, 
 170                     int flags
, vfs_context_t ctx
); 
 171 static int pshm_ioctl (struct fileproc 
*fp
, u_long com
, 
 172                     caddr_t data
, vfs_context_t ctx
); 
 173 static int pshm_select (struct fileproc 
*fp
, int which
, void *wql
, vfs_context_t ctx
); 
 174 static int pshm_close(struct pshmnode 
*pnode
); 
 175 static int pshm_closefile (struct fileglob 
*fg
, vfs_context_t ctx
); 
 177 static int pshm_kqfilter(struct fileproc 
*fp
, struct knote 
*kn
, vfs_context_t ctx
); 
 179 int pshm_access(struct pshminfo 
*pinfo
, int mode
, kauth_cred_t cred
, proc_t p
); 
 180 static int pshm_cache_add(struct pshminfo 
*pshmp
, struct pshmname 
*pnp
, struct pshmcache 
*pcp
); 
 181 static void pshm_cache_delete(struct pshmcache 
*pcp
); 
 183 static void pshm_cache_purge(void); 
 184 #endif  /* NOT_USED */ 
 185 static int pshm_cache_search(struct pshminfo 
**pshmp
, struct pshmname 
*pnp
, 
 186         struct pshmcache 
**pcache
); 
 188 struct  fileops pshmops 
= 
 189         { pshm_read
, pshm_write
, pshm_ioctl
, pshm_select
, pshm_closefile
, pshm_kqfilter
, 0 }; 
 191 static lck_grp_t       
*psx_shm_subsys_lck_grp
; 
 192 static lck_grp_attr_t  
*psx_shm_subsys_lck_grp_attr
; 
 193 static lck_attr_t      
*psx_shm_subsys_lck_attr
; 
 194 static lck_mtx_t        psx_shm_subsys_mutex
; 
 196 #define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex) 
 197 #define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex) 
 200 /* Initialize the mutex governing access to the posix shm subsystem */ 
 201 __private_extern__ 
void 
 202 pshm_lock_init( void ) 
 205     psx_shm_subsys_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 207     psx_shm_subsys_lck_grp 
= lck_grp_alloc_init("posix shared memory", psx_shm_subsys_lck_grp_attr
); 
 209     psx_shm_subsys_lck_attr 
= lck_attr_alloc_init(); 
 210     lck_mtx_init(& psx_shm_subsys_mutex
, psx_shm_subsys_lck_grp
, psx_shm_subsys_lck_attr
); 
 214  * Lookup an entry in the cache  
 217  * status of -1 is returned if matches 
 218  * If the lookup determines that the name does not exist 
 219  * (negative cacheing), a status of ENOENT is returned. If the lookup 
 220  * fails, a status of zero is returned. 
 224 pshm_cache_search(struct pshminfo 
**pshmp
, struct pshmname 
*pnp
, 
 225         struct pshmcache 
**pcache
) 
 227         struct pshmcache 
*pcp
, *nnp
; 
 228         struct pshmhashhead 
*pcpp
; 
 230         if (pnp
->pshm_namelen 
> PSHMNAMLEN
) { 
 231                 pshmstats
.longnames
++; 
 235         pcpp 
= PSHMHASH(pnp
); 
 236         for (pcp 
= pcpp
->lh_first
; pcp 
!= 0; pcp 
= nnp
) { 
 237                 nnp 
= pcp
->pshm_hash
.le_next
; 
 238                 if (pcp
->pshm_nlen 
== pnp
->pshm_namelen 
&& 
 239                     !bcmp(pcp
->pshm_name
, pnp
->pshm_nameptr
,                                            (u_int
)pcp
-> pshm_nlen
)) 
 248         /* We found a "positive" match, return the vnode */ 
 250                 pshmstats
.goodhits
++; 
 252                 *pshmp 
= pcp
->pshminfo
; 
 258          * We found a "negative" match, ENOENT notifies client of this match. 
 259          * The nc_vpid field records whether this is a whiteout. 
 266  * Add an entry to the cache. 
 267  * XXX should be static? 
 270 pshm_cache_add(struct pshminfo 
*pshmp
, struct pshmname 
*pnp
, struct pshmcache 
*pcp
) 
 272         struct pshmhashhead 
*pcpp
; 
 273         struct pshminfo 
*dpinfo
; 
 274         struct pshmcache 
*dpcp
; 
 277         if (pnp
->pshm_namelen 
> PSHMNAMLEN
) 
 278                 panic("cache_enter: name too long"); 
 282         /*  if the entry has already been added by some one else return */ 
 283         if (pshm_cache_search(&dpinfo
, pnp
, &dpcp
) == -1) { 
 289          * Fill in cache info, if vp is NULL this is a "negative" cache entry. 
 290          * For negative entries, we have to record whether it is a whiteout. 
 291          * the whiteout flag is stored in the nc_vpid field which is 
 294         pcp
->pshminfo 
= pshmp
; 
 295         pcp
->pshm_nlen 
= pnp
->pshm_namelen
; 
 296         bcopy(pnp
->pshm_nameptr
, pcp
->pshm_name
, (unsigned)pcp
->pshm_nlen
); 
 297         pcpp 
= PSHMHASH(pnp
); 
 302                 for (p 
= pcpp
->lh_first
; p 
!= 0; p 
= p
->pshm_hash
.le_next
) 
 304                                 panic("cache_enter: duplicate"); 
 307         LIST_INSERT_HEAD(pcpp
, pcp
, pshm_hash
); 
 312  * Name cache initialization, from vfs_init() when we are booting 
 315 pshm_cache_init(void) 
 317         pshmhashtbl 
= hashinit(desiredvnodes 
/ 8, M_SHM
, &pshmhash
); 
 322  * Invalidate a all entries to particular vnode. 
 324  * We actually just increment the v_id, that will do it. The entries will 
 325  * be purged by lookup as they get found. If the v_id wraps around, we 
 326  * need to ditch the entire cache, to avoid confusion. No valid vnode will 
 327  * ever have (v_id == 0). 
 330 pshm_cache_purge(void) 
 332         struct pshmcache 
*pcp
; 
 333         struct pshmhashhead 
*pcpp
; 
 335         for (pcpp 
= &pshmhashtbl
[pshmhash
]; pcpp 
>= pshmhashtbl
; pcpp
--) { 
 336                 while ( (pcp 
= pcpp
->lh_first
) ) 
 337                         pshm_cache_delete(pcp
); 
 340 #endif  /* NOT_USED */ 
 343 pshm_cache_delete(struct pshmcache 
*pcp
) 
 346         if (pcp
->pshm_hash
.le_prev 
== 0) 
 347                 panic("namecache purge le_prev"); 
 348         if (pcp
->pshm_hash
.le_next 
== pcp
) 
 349                 panic("namecache purge le_next"); 
 350 #endif /* DIAGNOSTIC */ 
 351         LIST_REMOVE(pcp
, pshm_hash
); 
 352         pcp
->pshm_hash
.le_prev 
= 0;      
 358 shm_open(proc_t p
, struct shm_open_args 
*uap
, register_t 
*retval
) 
 362         struct fileproc 
*nfp
; 
 365         struct pshminfo 
*pinfo
; 
 369         size_t pathlen
, plen
; 
 371         int cmode 
= uap
->mode
; 
 373         struct pshmnode 
* pnode 
= PSHMNODE_NULL
; 
 374         struct pshmcache 
* pcache 
= PSHMCACHE_NULL
; 
 375         struct pshmcache 
*pcp 
= NULL
;   /* protected by !incache */ 
 378         AUDIT_ARG(fflags
, uap
->oflag
); 
 379         AUDIT_ARG(mode
, uap
->mode
); 
 381         pinfo 
= PSHMINFO_NULL
; 
 383         MALLOC_ZONE(pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 388         pathlen 
= MAXPATHLEN
; 
 389         error 
= copyinstr(uap
->name
, (void *)pnbuf
, MAXPATHLEN
, &pathlen
); 
 393         AUDIT_ARG(text
, pnbuf
); 
 394         if (pathlen 
> PSHMNAMLEN
) { 
 395                 error 
= ENAMETOOLONG
; 
 400 #ifdef PSXSHM_NAME_RESTRICT 
 402         if (*nameptr 
== '/') { 
 403                 while (*(nameptr
++) == '/') { 
 412 #endif /* PSXSHM_NAME_RESTRICT */ 
 416         nd
.pshm_nameptr 
= nameptr
; 
 417         nd
.pshm_namelen 
= plen
; 
 420         for (cp 
= nameptr
, i
=1; *cp 
!= 0 && i 
<= plen
; i
++, cp
++) { 
 421                 nd
.pshm_hash 
+= (unsigned char)*cp 
* i
; 
 425         error 
= pshm_cache_search(&pinfo
, &nd
, &pcache
); 
 427         if (error 
== ENOENT
) { 
 428                 PSHM_SUBSYS_UNLOCK(); 
 437         fmode 
= FFLAGS(uap
->oflag
); 
 438         if ((fmode 
& (FREAD 
| FWRITE
))==0) { 
 439                 PSHM_SUBSYS_UNLOCK(); 
 445          * XXXXXXXXXX TBD XXXXXXXXXX 
 446          * There is a race that existed with the funnels as well. 
 447          * Need to be fixed later 
 449         PSHM_SUBSYS_UNLOCK(); 
 450         error 
= falloc(p
, &nfp
, &indx
, vfs_context_current()); 
 459         if (fmode 
& O_CREAT
) { 
 460                 if ((fmode 
& O_EXCL
) && incache
) { 
 461                         AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, 
 462                                         pinfo
->pshm_gid
, pinfo
->pshm_mode
); 
 464                         /* shm obj exists and opened O_EXCL */ 
 466                         if (pinfo
->pshm_flags 
& PSHM_INDELETE
) { 
 470                         PSHM_SUBSYS_UNLOCK(); 
 474                         PSHM_SUBSYS_UNLOCK(); 
 475                         /*  create a new one */ 
 476                         MALLOC(pinfo
, struct pshminfo 
*, sizeof(struct pshminfo
), M_SHM
, M_WAITOK
|M_ZERO
); 
 483                         pinfo
->pshm_flags 
= PSHM_DEFINED 
| PSHM_INCREATE
; 
 484                         pinfo
->pshm_usecount 
= 1; /* existence reference */ 
 485                         pinfo
->pshm_mode 
= cmode
; 
 486                         pinfo
->pshm_uid 
= kauth_cred_getuid(kauth_cred_get()); 
 487                         pinfo
->pshm_gid 
= kauth_cred_get()->cr_gid
; 
 488                         bcopy(pnbuf
, &pinfo
->pshm_name
[0], PSHMNAMLEN
); 
 489                         pinfo
->pshm_name
[PSHMNAMLEN
]=0; 
 491                         PSHM_SUBSYS_UNLOCK(); 
 492                         mac_posixshm_label_init(pinfo
); 
 494                         error 
= mac_posixshm_check_create(kauth_cred_get(), nameptr
); 
 496                                 PSHM_SUBSYS_UNLOCK(); 
 499                         mac_posixshm_label_associate(kauth_cred_get(), pinfo
, nameptr
); 
 503                         if( pinfo
->pshm_flags 
& PSHM_INDELETE
) { 
 504                                 PSHM_SUBSYS_UNLOCK(); 
 508                         AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, 
 509                                         pinfo
->pshm_gid
, pinfo
->pshm_mode
); 
 511                         if ((error 
= mac_posixshm_check_open( 
 512                                                         kauth_cred_get(), pinfo
))) { 
 513                                 PSHM_SUBSYS_UNLOCK(); 
 517                         if ( (error 
= pshm_access(pinfo
, fmode
, kauth_cred_get(), p
)) ) { 
 518                                 PSHM_SUBSYS_UNLOCK(); 
 524                         /* O_CREAT  is not set and the shm obecj does not exist */ 
 525                         PSHM_SUBSYS_UNLOCK(); 
 529                 if( pinfo
->pshm_flags 
& PSHM_INDELETE
) { 
 530                         PSHM_SUBSYS_UNLOCK(); 
 535                 if ((error 
= mac_posixshm_check_open( 
 536                                                 kauth_cred_get(), pinfo
))) { 
 537                         PSHM_SUBSYS_UNLOCK(); 
 542                 if ( (error 
= pshm_access(pinfo
, fmode
, kauth_cred_get(), p
)) ) { 
 543                         PSHM_SUBSYS_UNLOCK(); 
 547         if (fmode 
& O_TRUNC
) { 
 548                 PSHM_SUBSYS_UNLOCK(); 
 554                 pinfo
->pshm_writecount
++; 
 556                 pinfo
->pshm_readcount
++; 
 558         PSHM_SUBSYS_UNLOCK(); 
 559         MALLOC(pnode
, struct pshmnode 
*, sizeof(struct pshmnode
), M_SHM
, M_WAITOK
|M_ZERO
); 
 566                  * We allocate a new entry if we are less than the maximum 
 567                  * allowed and the one at the front of the LRU list is in use. 
 568                  * Otherwise we use the one at the front of the LRU list. 
 570                 MALLOC(pcp
, struct pshmcache 
*, sizeof(struct pshmcache
), M_SHM
, M_WAITOK
|M_ZERO
); 
 580                 if ( (error 
= pshm_cache_add(pinfo
, &nd
, pcp
)) ) { 
 581                         PSHM_SUBSYS_UNLOCK(); 
 586         pinfo
->pshm_flags 
&= ~PSHM_INCREATE
; 
 587         pinfo
->pshm_usecount
++; /* extra reference for the new fd */ 
 588         pnode
->pinfo 
= pinfo
; 
 590         PSHM_SUBSYS_UNLOCK(); 
 592         fp
->f_flag 
= fmode 
& FMASK
; 
 593         fp
->f_type 
= DTYPE_PSXSHM
; 
 594         fp
->f_ops 
= &pshmops
; 
 595         fp
->f_data 
= (caddr_t
)pnode
; 
 596         *fdflags(p
, indx
) |= UF_EXCLOSE
; 
 597         procfdtbl_releasefd(p
, indx
, NULL
); 
 598         fp_drop(p
, indx
, fp
, 1); 
 602         FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
 610                 mac_posixshm_label_destroy(pinfo
); 
 615         fp_free(p
, indx
, fp
); 
 617         FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
 623 pshm_truncate(__unused proc_t p
, struct fileproc 
*fp
, __unused 
int fd
,  
 624                                 off_t length
, __unused register_t 
*retval
) 
 626         struct pshminfo 
* pinfo
; 
 627         struct pshmnode 
* pnode 
; 
 629         mach_vm_offset_t user_addr
; 
 630         mem_entry_name_port_t mem_object
; 
 636         if (fp
->f_type 
!= DTYPE_PSXSHM
) { 
 641         if (((pnode 
= (struct pshmnode 
*)fp
->f_data
)) == PSHMNODE_NULL 
) 
 645         if ((pinfo 
= pnode
->pinfo
) == PSHMINFO_NULL
) { 
 646                 PSHM_SUBSYS_UNLOCK(); 
 649         if ((pinfo
->pshm_flags 
& (PSHM_DEFINED 
| PSHM_ALLOCATED
))  
 651                 PSHM_SUBSYS_UNLOCK(); 
 655         error 
= mac_posixshm_check_truncate(kauth_cred_get(), pinfo
, size
); 
 657                 PSHM_SUBSYS_UNLOCK(); 
 661         PSHM_SUBSYS_UNLOCK(); 
 662         size 
= round_page_64(length
); 
 663         kret 
= mach_vm_allocate(current_map(), &user_addr
, size
, VM_FLAGS_ANYWHERE
); 
 664         if (kret 
!= KERN_SUCCESS
)  
 667         kret 
= mach_make_memory_entry_64 (current_map(), &size
, 
 668                         user_addr
, VM_PROT_DEFAULT
, &mem_object
, 0); 
 670         if (kret 
!= KERN_SUCCESS
)  
 673         mach_vm_deallocate(current_map(), user_addr
, size
); 
 676         pinfo
->pshm_flags 
&= ~PSHM_DEFINED
; 
 677         pinfo
->pshm_flags 
= PSHM_ALLOCATED
; 
 678         pinfo
->pshm_memobject 
= (void *)mem_object
; 
 679         pinfo
->pshm_length 
= size
; 
 680         PSHM_SUBSYS_UNLOCK(); 
 685         case KERN_INVALID_ADDRESS
: 
 688         case KERN_PROTECTION_FAILURE
: 
 697 pshm_stat(struct pshmnode 
*pnode
, void *ub
, int isstat64
) 
 699         struct stat 
*sb 
= (struct stat 
*)0;     /* warning avoidance ; protected by isstat64 */ 
 700         struct stat64 
* sb64 
= (struct stat64 
*)0;  /* warning avoidance ; protected by isstat64 */ 
 701         struct pshminfo 
*pinfo
; 
 707         if ((pinfo 
= pnode
->pinfo
) == PSHMINFO_NULL
){ 
 708                 PSHM_SUBSYS_UNLOCK(); 
 713         error 
= mac_posixshm_check_stat(kauth_cred_get(), pinfo
); 
 715                 PSHM_SUBSYS_UNLOCK(); 
 721                 sb64 
= (struct stat64 
*)ub
; 
 722                 bzero(sb64
, sizeof(struct stat64
));  
 723                 sb64
->st_mode 
= pinfo
->pshm_mode
; 
 724                 sb64
->st_uid 
= pinfo
->pshm_uid
; 
 725                 sb64
->st_gid 
= pinfo
->pshm_gid
; 
 726                 sb64
->st_size 
= pinfo
->pshm_length
; 
 728                 sb 
= (struct stat 
*)ub
; 
 729                 bzero(sb
, sizeof(struct stat
));  
 730                 sb
->st_mode 
= pinfo
->pshm_mode
; 
 731                 sb
->st_uid 
= pinfo
->pshm_uid
; 
 732                 sb
->st_gid 
= pinfo
->pshm_gid
; 
 733                 sb
->st_size 
= pinfo
->pshm_length
; 
 735         PSHM_SUBSYS_UNLOCK(); 
 741  * This is called only from shm_open which holds pshm_lock(); 
 742  * XXX This code is repeated many times 
 745 pshm_access(struct pshminfo 
*pinfo
, int mode
, kauth_cred_t cred
, __unused proc_t p
) 
 750         /* Otherwise, user id 0 always gets access. */ 
 751         if (!suser(cred
, NULL
)) 
 756         /* Otherwise, check the owner. */ 
 757         if (kauth_cred_getuid(cred
) == pinfo
->pshm_uid
) { 
 762                 return ((pinfo
->pshm_mode 
& mask
) == mask 
? 0 : EACCES
); 
 765         /* Otherwise, check the groups. */ 
 766         if (kauth_cred_ismember_gid(cred
, pinfo
->pshm_gid
, &is_member
) == 0 && is_member
) { 
 771                 return ((pinfo
->pshm_mode 
& mask
) == mask 
? 0 : EACCES
); 
 774         /* Otherwise, check everyone else. */ 
 779         return ((pinfo
->pshm_mode 
& mask
) == mask 
? 0 : EACCES
); 
 783 pshm_mmap(__unused proc_t p
, struct mmap_args 
*uap
, user_addr_t 
*retval
, struct fileproc 
*fp
, off_t pageoff
)  
 785         mach_vm_offset_t        user_addr 
= (mach_vm_offset_t
)uap
->addr
; 
 786         mach_vm_size_t          user_size 
= (mach_vm_size_t
)uap
->len 
; 
 787         int prot 
= uap
->prot
; 
 788         int flags 
= uap
->flags
; 
 789         vm_object_offset_t file_pos 
= (vm_object_offset_t
)uap
->pos
; 
 794         struct pshminfo 
* pinfo
; 
 795         struct pshmnode 
* pnode
; 
 804         if ((flags 
& MAP_SHARED
) == 0) 
 808         if ((prot 
& PROT_WRITE
) && ((fp
->f_flag 
& FWRITE
) == 0)) { 
 812         if (((pnode 
= (struct pshmnode 
*)fp
->f_data
)) == PSHMNODE_NULL 
) 
 816         if ((pinfo 
= pnode
->pinfo
) == PSHMINFO_NULL
) { 
 817                 PSHM_SUBSYS_UNLOCK(); 
 821         if ((pinfo
->pshm_flags 
& PSHM_ALLOCATED
) != PSHM_ALLOCATED
) { 
 822                 PSHM_SUBSYS_UNLOCK(); 
 825         if ((off_t
)user_size 
> pinfo
->pshm_length
) { 
 826                 PSHM_SUBSYS_UNLOCK(); 
 829         if ((off_t
)(user_size 
+ file_pos
) > pinfo
->pshm_length
) { 
 830                 PSHM_SUBSYS_UNLOCK(); 
 833         if ((mem_object 
=  pinfo
->pshm_memobject
) == NULL
) { 
 834                 PSHM_SUBSYS_UNLOCK(); 
 839         error 
= mac_posixshm_check_mmap(kauth_cred_get(), pinfo
, prot
, flags
); 
 841                 PSHM_SUBSYS_UNLOCK(); 
 846         PSHM_SUBSYS_UNLOCK(); 
 847         user_map 
= current_map(); 
 849         if ((flags 
& MAP_FIXED
) == 0) { 
 850                 alloc_flags 
= VM_FLAGS_ANYWHERE
; 
 851                 user_addr 
= mach_vm_round_page(user_addr
);  
 853                 if (user_addr 
!= mach_vm_trunc_page(user_addr
)) 
 856                  * We do not get rid of the existing mappings here because 
 857                  * it wouldn't be atomic (see comment in mmap()).  We let 
 858                  * Mach VM know that we want it to replace any existing 
 859                  * mapping with the new one. 
 861                 alloc_flags 
= VM_FLAGS_FIXED 
| VM_FLAGS_OVERWRITE
; 
 865         kret 
= vm_map_enter_mem_object(user_map
, &user_addr
, user_size
, 
 867                                        pinfo
->pshm_memobject
, file_pos
, docow
, 
 868                                        prot
, VM_PROT_DEFAULT
,  
 870         if (kret 
!= KERN_SUCCESS
)  
 872         /* LP64todo - this should be superfluous at this point */ 
 873         kret 
= mach_vm_inherit(user_map
, user_addr
, user_size
, 
 875         if (kret 
!= KERN_SUCCESS
) { 
 876                 (void) mach_vm_deallocate(user_map
, user_addr
, user_size
); 
 880         pnode
->mapp_addr 
= user_addr
; 
 881         pnode
->map_size 
= user_size
; 
 882         pinfo
->pshm_flags 
|= (PSHM_MAPPED 
| PSHM_INUSE
); 
 883         PSHM_SUBSYS_UNLOCK(); 
 887                 *retval 
= (user_addr 
+ pageoff
); 
 889         case KERN_INVALID_ADDRESS
: 
 892         case KERN_PROTECTION_FAILURE
: 
 901 shm_unlink(__unused proc_t p
, struct shm_unlink_args 
*uap
,  
 902                         __unused register_t 
*retval
) 
 907         struct pshminfo 
*pinfo
; 
 911         size_t pathlen
, plen
; 
 913         struct pshmcache 
*pcache 
= PSHMCACHE_NULL
; 
 915         pinfo 
= PSHMINFO_NULL
; 
 917         MALLOC_ZONE(pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
); 
 919                 return(ENOSPC
);         /* XXX non-standard */ 
 921         pathlen 
= MAXPATHLEN
; 
 922         error 
= copyinstr(uap
->name
, (void *)pnbuf
, MAXPATHLEN
, &pathlen
); 
 926         AUDIT_ARG(text
, pnbuf
); 
 927         if (pathlen 
> PSHMNAMLEN
) { 
 928                 error 
= ENAMETOOLONG
; 
 933 #ifdef PSXSHM_NAME_RESTRICT 
 935         if (*nameptr 
== '/') { 
 936                 while (*(nameptr
++) == '/') { 
 945 #endif /* PSXSHM_NAME_RESTRICT */ 
 949         nd
.pshm_nameptr 
= nameptr
; 
 950         nd
.pshm_namelen 
= plen
; 
 953         for (cp 
= nameptr
, i
=1; *cp 
!= 0 && i 
<= plen
; i
++, cp
++) { 
 954                nd
.pshm_hash 
+= (unsigned char)*cp 
* i
; 
 958         error 
= pshm_cache_search(&pinfo
, &nd
, &pcache
); 
 960         if (error 
== ENOENT
) { 
 961                 PSHM_SUBSYS_UNLOCK(); 
 967                 PSHM_SUBSYS_UNLOCK(); 
 973         if ((pinfo
->pshm_flags 
& (PSHM_DEFINED 
| PSHM_ALLOCATED
))==0) { 
 974                 PSHM_SUBSYS_UNLOCK(); 
 979         if (pinfo
->pshm_flags 
& PSHM_INDELETE
) { 
 980                 PSHM_SUBSYS_UNLOCK(); 
 985         error 
= mac_posixshm_check_unlink(kauth_cred_get(), pinfo
, nameptr
); 
 987                 PSHM_SUBSYS_UNLOCK(); 
 992         AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, pinfo
->pshm_gid
, 
 996          * JMM - How should permissions be checked? 
 999         pinfo
->pshm_flags 
|= PSHM_INDELETE
; 
1000         pshm_cache_delete(pcache
); 
1001         pinfo
->pshm_flags 
|= PSHM_REMOVED
; 
1002         /* release the existence reference */ 
1003         if (!--pinfo
->pshm_usecount
) { 
1004                 PSHM_SUBSYS_UNLOCK(); 
1006                  * If this is the last reference going away on the object, 
1007                  * then we need to destroy the backing object.  The name 
1008                  * has an implied but uncounted reference on the object, 
1009                  * once it's created, since it's used as a rendesvous, and 
1010                  * therefore may be subsequently reopened. 
1012                 if (pinfo
->pshm_memobject 
!= NULL
) 
1013                         mach_memory_entry_port_release(pinfo
->pshm_memobject
); 
1017         PSHM_SUBSYS_UNLOCK(); 
1018         FREE(pcache
, M_SHM
); 
1021         FREE_ZONE(pnbuf
, MAXPATHLEN
, M_NAMEI
); 
1025 /* already called locked */ 
1027 pshm_close(struct pshmnode 
*pnode
) 
1030         struct pshminfo 
*pinfo
; 
1032         if ((pinfo 
= pnode
->pinfo
) == PSHMINFO_NULL
) 
1035         if ((pinfo
->pshm_flags 
& PSHM_ALLOCATED
) != PSHM_ALLOCATED
) { 
1039         if(!pinfo
->pshm_usecount
) { 
1040                 kprintf("negative usecount in pshm_close\n"); 
1042 #endif /* DIAGNOSTIC */ 
1043         pinfo
->pshm_usecount
--; /* release this fd's reference */ 
1045         if ((pinfo
->pshm_flags 
& PSHM_REMOVED
) && !pinfo
->pshm_usecount
) { 
1046                 PSHM_SUBSYS_UNLOCK(); 
1048                  * If this is the last reference going away on the object, 
1049                  * then we need to destroy the backing object. 
1051                 if (pinfo
->pshm_memobject 
!= NULL
) 
1052                         mach_memory_entry_port_release(pinfo
->pshm_memobject
); 
1055                 mac_posixshm_label_destroy(pinfo
); 
1063 /* vfs_context_t passed to match prototype for struct fileops */ 
1065 pshm_closefile(struct fileglob 
*fg
, __unused vfs_context_t ctx
) 
1070         error 
=  pshm_close(((struct pshmnode 
*)fg
->fg_data
)); 
1071         PSHM_SUBSYS_UNLOCK(); 
1076 pshm_read(__unused 
struct fileproc 
*fp
, __unused 
struct uio 
*uio
,  
1077                         __unused 
int flags
, __unused vfs_context_t ctx
) 
1083 pshm_write(__unused 
struct fileproc 
*fp
, __unused 
struct uio 
*uio
,  
1084                         __unused 
int flags
, __unused vfs_context_t ctx
) 
1090 pshm_ioctl(__unused 
struct fileproc 
*fp
, __unused u_long com
,  
1091                         __unused caddr_t data
, __unused vfs_context_t ctx
) 
1097 pshm_select(__unused 
struct fileproc 
*fp
, __unused 
int which
, __unused 
void *wql
,  
1098                         __unused vfs_context_t ctx
) 
1104 pshm_kqfilter(__unused 
struct fileproc 
*fp
, __unused 
struct knote 
*kn
,  
1105                                 __unused vfs_context_t ctx
) 
1111 fill_pshminfo(struct pshmnode 
* pshm
, struct pshm_info 
* info
) 
1113         struct pshminfo 
*pinfo
; 
1114         struct vinfo_stat 
*sb
; 
1117         if ((pinfo 
= pshm
->pinfo
) == PSHMINFO_NULL
){ 
1118                 PSHM_SUBSYS_UNLOCK(); 
1122         sb 
= &info
->pshm_stat
; 
1124         bzero(sb
, sizeof(struct vinfo_stat
));  
1125         sb
->vst_mode 
= pinfo
->pshm_mode
; 
1126         sb
->vst_uid 
= pinfo
->pshm_uid
; 
1127         sb
->vst_gid 
= pinfo
->pshm_gid
; 
1128         sb
->vst_size 
= pinfo
->pshm_length
; 
1130         info
->pshm_mappaddr 
= pshm
->mapp_addr
; 
1131         bcopy(&pinfo
->pshm_name
[0], &info
->pshm_name
[0], PSHMNAMLEN
+1);  
1133         PSHM_SUBSYS_UNLOCK(); 
1139 pshm_label_associate(struct fileproc 
*fp
, struct vnode 
*vp
, vfs_context_t ctx
) 
1141         struct pshmnode 
*pnode
; 
1142         struct pshminfo 
*pshm
; 
1145         pnode 
= (struct pshmnode 
*)fp
->f_fglob
->fg_data
; 
1146         if (pnode 
!= NULL
) { 
1147                 pshm 
= pnode
->pinfo
; 
1149                         mac_posixshm_vnode_label_associate( 
1150                                 vfs_context_ucred(ctx
), pshm
, pshm
->pshm_label
, 
1153         PSHM_SUBSYS_UNLOCK();