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 <sys/posix_shm.h> 
  71 #include <security/audit/audit.h> 
  75 #include <security/mac_framework.h> 
  78 #include <mach/mach_types.h> 
  79 #include <mach/mach_vm.h> 
  80 #include <mach/vm_map.h> 
  81 #include <mach/vm_prot.h> 
  82 #include <mach/vm_inherit.h> 
  83 #include <mach/kern_return.h> 
  84 #include <mach/memory_object_control.h> 
  86 #include <vm/vm_map.h> 
  87 #include <vm/vm_protos.h> 
  89 #define f_flag f_fglob->fg_flag 
  90 #define f_type f_fglob->fg_ops->fo_type 
  91 #define f_msgcount f_fglob->fg_msgcount 
  92 #define f_cred f_fglob->fg_cred 
  93 #define f_ops f_fglob->fg_ops 
  94 #define f_offset f_fglob->fg_offset 
  95 #define f_data f_fglob->fg_data 
  98  * Used to construct the list of memory objects 
  99  * assigned to a populated shared memory segment. 
 101 typedef struct pshm_mobj 
{ 
 102         void                  *pshmo_memobject
; 
 103         memory_object_size_t  pshmo_size
; 
 104         SLIST_ENTRY(pshm_mobj
) pshmo_next
; 
 108  * This represents an existing Posix shared memory object. 
 110  * It comes into existence with a shm_open(...O_CREAT...) 
 111  * call and goes away only after it has been shm_unlink()ed 
 112  * and the last remaining shm_open() file reference is closed. 
 114  * To keep track of that lifetime, pshm_usecount is used as a reference 
 115  * counter. It's incremented for every successful shm_open() and 
 116  * one extra time for the shm_unlink() to release. Internally 
 117  * you can temporarily use an additional reference whenever the 
 118  * subsystem lock has to be dropped for other reasons. 
 120 typedef struct internal_pshminfo 
{ 
 121         struct pshminfo pshm_hdr
; 
 122         SLIST_HEAD(pshm_mobjhead
, pshm_mobj
) pshm_mobjs
; 
 123         RB_ENTRY(internal_pshminfo
) pshm_links
;        /* links for red/black tree */ 
 125 #define pshm_flags    pshm_hdr.pshm_flags 
 126 #define pshm_usecount pshm_hdr.pshm_usecount 
 127 #define pshm_length   pshm_hdr.pshm_length 
 128 #define pshm_mode     pshm_hdr.pshm_mode 
 129 #define pshm_uid      pshm_hdr.pshm_uid 
 130 #define pshm_gid      pshm_hdr.pshm_gid 
 131 #define pshm_label    pshm_hdr.pshm_label 
 133 /* Values for pshm_flags that are still used */ 
 134 #define PSHM_ALLOCATED  0x004   /* backing storage is allocated */ 
 135 #define PSHM_MAPPED     0x008   /* mapped at least once */ 
 136 #define PSHM_INUSE      0x010   /* mapped at least once */ 
 137 #define PSHM_REMOVED    0x020   /* no longer in the name cache due to shm_unlink() */ 
 138 #define PSHM_ALLOCATING 0x100   /* storage is being allocated */ 
 141  * These handle reference counting pshm_info_t structs using pshm_usecount. 
 143 static int pshm_ref(pshm_info_t 
*pinfo
); 
 144 static void pshm_deref(pshm_info_t 
*pinfo
); 
 145 #define PSHM_MAXCOUNT UINT_MAX 
 148  * For every shm_open, we get a new one of these. 
 149  * The only reason we don't just use pshm_info directly is that 
 150  * you can query the mapped memory objects via proc_pidinfo to 
 151  * query the mapped address. Note that even this is a hack. If 
 152  * you mmap() the same fd multiple times, we only save/report 
 155 typedef struct pshmnode 
{ 
 161 /* compare function for the red black tree */ 
 163 pshm_compare(pshm_info_t 
*a
, pshm_info_t 
*b
) 
 165         int cmp 
= strncmp(a
->pshm_hdr
.pshm_name
, b
->pshm_hdr
.pshm_name
, PSHMNAMLEN 
+ 1); 
 178  * shared memory "paths" are stored in a red black tree for lookup 
 180 u_long pshmnument
;    /* count of entries allocated in the red black tree */ 
 181 RB_HEAD(pshmhead
, internal_pshminfo
) pshm_head
; 
 182 RB_PROTOTYPE(pshmhead
, internal_pshminfo
, pshm_links
, pshm_compare
) 
 183 RB_GENERATE(pshmhead
, internal_pshminfo
, pshm_links
, pshm_compare
) 
 185 /* lookup, add, remove functions */ 
 186 static pshm_info_t 
*pshm_cache_search(pshm_info_t 
* look
); 
 187 static void pshm_cache_add(pshm_info_t 
*entry
); 
 188 static void pshm_cache_delete(pshm_info_t 
*entry
); 
 190 static int pshm_closefile(struct fileglob 
*fg
, vfs_context_t ctx
); 
 192 static int pshm_access(pshm_info_t 
*pinfo
, int mode
, kauth_cred_t cred
, proc_t p
); 
 193 int pshm_cache_purge_all(proc_t p
); 
 195 static int pshm_unlink_internal(pshm_info_t 
*pinfo
); 
 197 static const struct fileops pshmops 
= { 
 198         .fo_type     
= DTYPE_PSXSHM
, 
 199         .fo_read     
= fo_no_read
, 
 200         .fo_write    
= fo_no_write
, 
 201         .fo_ioctl    
= fo_no_ioctl
, 
 202         .fo_select   
= fo_no_select
, 
 203         .fo_close    
= pshm_closefile
, 
 204         .fo_drain    
= fo_no_drain
, 
 205         .fo_kqfilter 
= fo_no_kqfilter
, 
 209  * Everything here is protected by a single mutex. 
 211 static lck_grp_t       
*psx_shm_subsys_lck_grp
; 
 212 static lck_grp_attr_t  
*psx_shm_subsys_lck_grp_attr
; 
 213 static lck_attr_t      
*psx_shm_subsys_lck_attr
; 
 214 static lck_mtx_t        psx_shm_subsys_mutex
; 
 216 #define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex) 
 217 #define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex) 
 218 #define PSHM_SUBSYS_ASSERT_HELD()  LCK_MTX_ASSERT(&psx_shm_subsys_mutex, LCK_MTX_ASSERT_OWNED) 
 221 __private_extern__ 
void 
 222 pshm_lock_init( void ) 
 224         psx_shm_subsys_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 226         psx_shm_subsys_lck_grp 
= 
 227             lck_grp_alloc_init("posix shared memory", psx_shm_subsys_lck_grp_attr
); 
 229         psx_shm_subsys_lck_attr 
= lck_attr_alloc_init(); 
 230         lck_mtx_init(&psx_shm_subsys_mutex
, psx_shm_subsys_lck_grp
, psx_shm_subsys_lck_attr
); 
 234  * Lookup an entry in the cache. Only the name is used from "look". 
 237 pshm_cache_search(pshm_info_t 
*look
) 
 239         PSHM_SUBSYS_ASSERT_HELD(); 
 240         return RB_FIND(pshmhead
, &pshm_head
, look
); 
 244  * Add a new entry to the cache. 
 247 pshm_cache_add(pshm_info_t 
*entry
) 
 249         pshm_info_t 
*conflict
; 
 251         PSHM_SUBSYS_ASSERT_HELD(); 
 252         conflict 
= RB_INSERT(pshmhead
, &pshm_head
, entry
); 
 253         if (conflict 
!= NULL
) { 
 254                 panic("pshm_cache_add() found %p", conflict
); 
 260  * Remove the given entry from the red black tree. 
 263 pshm_cache_delete(pshm_info_t 
*entry
) 
 265         PSHM_SUBSYS_ASSERT_HELD(); 
 266         assert(!(entry
->pshm_flags 
& PSHM_REMOVED
)); 
 267         RB_REMOVE(pshmhead
, &pshm_head
, entry
); 
 272  * Initialize the red black tree. 
 275 pshm_cache_init(void) 
 281  * Invalidate all entries and delete all objects associated with them 
 282  * XXX - due to the reference counting, this only works if all userland 
 283  * references to it via file descriptors are also closed already. Is this 
 284  * known to be called after all user processes are killed? 
 287 pshm_cache_purge_all(__unused proc_t proc
) 
 293         if (kauth_cred_issuser(kauth_cred_get()) == 0) { 
 298         RB_FOREACH_SAFE(p
, pshmhead
, &pshm_head
, tmp
) { 
 299                 error 
= pshm_unlink_internal(p
); 
 300                 if (error
) {  /* XXX: why give up on failure, should keep going */ 
 304         assert(pshmnument 
== 0); 
 307         PSHM_SUBSYS_UNLOCK(); 
 310                 printf("%s: Error %d removing posix shm cache: %ld remain!\n", 
 311                     __func__
, error
, pshmnument
); 
 317  * Utility to get the shared memory name from userspace and 
 318  * populate a pshm_info_t with it. If there's a problem 
 319  * reading the name or it's malformed, will return an error code. 
 322 pshm_get_name(pshm_info_t 
*pinfo
, const user_addr_t user_addr
) 
 324         size_t bytes_copied 
= 0; 
 328         error 
= copyinstr(user_addr
, &pinfo
->pshm_hdr
.pshm_name
[0], PSHMNAMLEN 
+ 1, &bytes_copied
); 
 332         assert(bytes_copied 
<= PSHMNAMLEN 
+ 1); 
 333         assert(pinfo
->pshm_hdr
.pshm_name
[bytes_copied 
- 1] == 0); 
 334         if (bytes_copied 
< 2) { /* 2: expect at least one character and terminating zero */ 
 337         AUDIT_ARG(text
, &pinfo
->pshm_hdr
.pshm_name
[0]); 
 342  * Process a shm_open() system call. 
 345 shm_open(proc_t p
, struct shm_open_args 
*uap
, int32_t *retval
) 
 349         pshm_info_t     
*pinfo 
= NULL
; 
 350         pshm_info_t     
*new_pinfo 
= NULL
; 
 351         pshmnode_t      
*new_pnode 
= NULL
; 
 352         struct fileproc 
*fp 
= NULL
; 
 354         int             cmode 
= uap
->mode
; 
 355         bool            incache 
= false; 
 356         bool            have_label 
= false; 
 358         AUDIT_ARG(fflags
, uap
->oflag
); 
 359         AUDIT_ARG(mode
, uap
->mode
); 
 362          * Allocate data structures we need. We parse the userspace name into 
 363          * a pshm_info_t, even when we don't need to O_CREAT. 
 365         MALLOC(new_pinfo
, pshm_info_t 
*, sizeof(pshm_info_t
), M_SHM
, M_WAITOK 
| M_ZERO
); 
 366         if (new_pinfo 
== NULL
) { 
 372          * Get and check the name. 
 374         error 
= pshm_get_name(new_pinfo
, uap
->name
); 
 380          * Attempt to allocate a new fp. If unsuccessful, the fp will be 
 381          * left unmodified (NULL). 
 383         error 
= falloc(p
, &fp
, &indx
, vfs_context_current()); 
 390         fmode 
= FFLAGS(uap
->oflag
); 
 391         if ((fmode 
& (FREAD 
| FWRITE
)) == 0) { 
 397          * Will need a new pnode for the file pointer 
 399         MALLOC(new_pnode
, pshmnode_t 
*, sizeof(pshmnode_t
), M_SHM
, M_WAITOK 
| M_ZERO
); 
 400         if (new_pnode 
== NULL
) { 
 406          * If creating a new segment, fill in its information. 
 407          * If we find a pre-exisitng one in cache lookup we'll just toss this one later. 
 409         if (fmode 
& O_CREAT
) { 
 410                 new_pinfo
->pshm_usecount 
= 2; /* one each for: file pointer, shm_unlink */ 
 411                 new_pinfo
->pshm_length 
= 0; 
 412                 new_pinfo
->pshm_mode 
= cmode
; 
 413                 new_pinfo
->pshm_uid 
= kauth_getuid(); 
 414                 new_pinfo
->pshm_gid 
= kauth_getgid(); 
 415                 SLIST_INIT(&new_pinfo
->pshm_mobjs
); 
 417                 mac_posixshm_label_init(&new_pinfo
->pshm_hdr
); 
 419                 error 
= mac_posixshm_check_create(kauth_cred_get(), new_pinfo
->pshm_hdr
.pshm_name
); 
 427          * Look up the named shared memory segment in the cache, possibly adding 
 432         pinfo 
= pshm_cache_search(new_pinfo
); 
 436                 /* Get a new reference to go with the file pointer.*/ 
 437                 error 
= pshm_ref(pinfo
); 
 439                         pinfo 
= NULL
;      /* so cleanup code doesn't deref */ 
 443                 /* can't have pre-existing if O_EXCL */ 
 444                 if ((fmode 
& (O_CREAT 
| O_EXCL
)) == (O_CREAT 
| O_EXCL
)) { 
 449                 /* O_TRUNC is only valid while length is not yet set */ 
 450                 if ((fmode 
& O_TRUNC
) && 
 451                     (pinfo
->pshm_flags 
& (PSHM_ALLOCATING 
| PSHM_ALLOCATED
))) { 
 458                 /* if it wasn't found, must have O_CREAT */ 
 459                 if (!(fmode 
& O_CREAT
)) { 
 464                 /* Add the new region to the cache. */ 
 466                 pshm_cache_add(pinfo
); 
 467                 new_pinfo 
= NULL
;       /* so that it doesn't get free'd */ 
 470         PSHM_SUBSYS_UNLOCK(); 
 473          * Check we have permission to access any pre-existing segment 
 476                 if (fmode 
& O_CREAT
) { 
 477                         AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, 
 478                             pinfo
->pshm_gid
, pinfo
->pshm_mode
); 
 481                 if ((error 
= mac_posixshm_check_open(kauth_cred_get(), &pinfo
->pshm_hdr
, fmode
))) { 
 485                 if ((error 
= pshm_access(pinfo
, fmode
, kauth_cred_get(), p
))) { 
 490                 mac_posixshm_label_associate(kauth_cred_get(), &pinfo
->pshm_hdr
, pinfo
->pshm_hdr
.pshm_name
); 
 495         fp
->f_flag 
= fmode 
& FMASK
; 
 496         fp
->f_ops 
= &pshmops
; 
 497         new_pnode
->pinfo 
= pinfo
; 
 498         fp
->f_data 
= (caddr_t
)new_pnode
; 
 499         *fdflags(p
, indx
) |= UF_EXCLOSE
; 
 500         procfdtbl_releasefd(p
, indx
, NULL
); 
 501         fp_drop(p
, indx
, fp
, 1); 
 509         PSHM_SUBSYS_UNLOCK(); 
 512          * Drop any new reference to a pre-existing shared memory region. 
 514         if (incache 
&& pinfo 
!= NULL
) { 
 517                 PSHM_SUBSYS_UNLOCK(); 
 521          * Delete any allocated unused data structures. 
 523         if (new_pnode 
!= NULL
) { 
 524                 FREE(new_pnode
, M_SHM
); 
 528                 fp_free(p
, indx
, fp
); 
 532         if (new_pinfo 
!= NULL
) { 
 535                         mac_posixshm_label_destroy(&new_pinfo
->pshm_hdr
); 
 538                 FREE(new_pinfo
, M_SHM
); 
 545  * The truncate call associates memory with shared memory region. It can 
 546  * only be succesfully done with a non-zero length once per shared memory region. 
 554         __unused 
int32_t      *retval
) 
 559         mem_entry_name_port_t mem_object
; 
 560         mach_vm_size_t        total_size
, alloc_size
; 
 561         memory_object_size_t  mosize
; 
 562         pshm_mobj_t           
*pshmobj
, *pshmobj_last
; 
 566         user_map 
= current_map(); 
 568         if (fp
->f_type 
!= DTYPE_PSXSHM
) { 
 574          * Can't enforce this yet, some third party tools don't 
 575          * specify O_RDWR like they ought to. See radar 48692182 
 577         /* ftruncate() requires write permission */ 
 578         if (!(fp
->f_flag 
& FWRITE
)) { 
 584         if (((pnode 
= (pshmnode_t 
*)fp
->f_data
)) == NULL
) { 
 585                 PSHM_SUBSYS_UNLOCK(); 
 589         if ((pinfo 
= pnode
->pinfo
) == NULL
) { 
 590                 PSHM_SUBSYS_UNLOCK(); 
 594         /* We only allow one ftruncate() per lifetime of the shm object. */ 
 595         if (pinfo
->pshm_flags 
& (PSHM_ALLOCATING 
| PSHM_ALLOCATED
)) { 
 596                 PSHM_SUBSYS_UNLOCK(); 
 601         error 
= mac_posixshm_check_truncate(kauth_cred_get(), &pinfo
->pshm_hdr
, length
); 
 603                 PSHM_SUBSYS_UNLOCK(); 
 608          * Grab an extra reference, so we can drop the lock while allocating and 
 609          * ensure the objects don't disappear. 
 611         error 
= pshm_ref(pinfo
); 
 613                 PSHM_SUBSYS_UNLOCK(); 
 617         /* set ALLOCATING, so another truncate can't start */ 
 618         pinfo
->pshm_flags 
|= PSHM_ALLOCATING
; 
 619         total_size 
= vm_map_round_page(length
, vm_map_page_mask(user_map
)); 
 622         for (alloc_size 
= 0; alloc_size 
< total_size
; alloc_size 
+= mosize
) { 
 623                 PSHM_SUBSYS_UNLOCK(); 
 625                 /* get a memory object back some of the shared memory */ 
 626                 mosize 
= MIN(total_size 
- alloc_size
, ANON_MAX_SIZE
); 
 627                 kret 
= mach_make_memory_entry_64(VM_MAP_NULL
, &mosize
, 0, 
 628                     MAP_MEM_NAMED_CREATE 
| VM_PROT_DEFAULT
, &mem_object
, 0); 
 630                 if (kret 
!= KERN_SUCCESS
) { 
 634                 /* get a list entry to track the memory object */ 
 635                 MALLOC(pshmobj
, pshm_mobj_t 
*, sizeof(pshm_mobj_t
), M_SHM
, M_WAITOK
); 
 636                 if (pshmobj 
== NULL
) { 
 637                         kret 
= KERN_NO_SPACE
; 
 638                         mach_memory_entry_port_release(mem_object
); 
 645                 /* link in the new entry */ 
 646                 pshmobj
->pshmo_memobject 
= (void *)mem_object
; 
 647                 pshmobj
->pshmo_size 
= mosize
; 
 648                 SLIST_NEXT(pshmobj
, pshmo_next
) = NULL
; 
 650                 if (pshmobj_last 
== NULL
) { 
 651                         SLIST_FIRST(&pinfo
->pshm_mobjs
) = pshmobj
; 
 653                         SLIST_INSERT_AFTER(pshmobj_last
, pshmobj
, pshmo_next
); 
 655                 pshmobj_last 
= pshmobj
; 
 658         /* all done, change flags to ALLOCATED and return success */ 
 659         pinfo
->pshm_flags 
|= PSHM_ALLOCATED
; 
 660         pinfo
->pshm_flags 
&= ~(PSHM_ALLOCATING
); 
 661         pinfo
->pshm_length 
= total_size
; 
 662         pshm_deref(pinfo
);              /* drop the "allocating" reference */ 
 663         PSHM_SUBSYS_UNLOCK(); 
 667         /* clean up any partially allocated objects */ 
 669         while ((pshmobj 
= SLIST_FIRST(&pinfo
->pshm_mobjs
)) != NULL
) { 
 670                 SLIST_REMOVE_HEAD(&pinfo
->pshm_mobjs
, pshmo_next
); 
 671                 PSHM_SUBSYS_UNLOCK(); 
 672                 mach_memory_entry_port_release(pshmobj
->pshmo_memobject
); 
 673                 FREE(pshmobj
, M_SHM
); 
 676         pinfo
->pshm_flags 
&= ~PSHM_ALLOCATING
; 
 677         pshm_deref(pinfo
);              /* drop the "allocating" reference */ 
 678         PSHM_SUBSYS_UNLOCK(); 
 681         case KERN_INVALID_ADDRESS
: 
 684         case KERN_PROTECTION_FAILURE
: 
 692 pshm_stat(pshmnode_t 
*pnode
, void *ub
, int isstat64
) 
 694         struct stat 
*sb 
= (struct stat 
*)0;     /* warning avoidance ; protected by isstat64 */ 
 695         struct stat64 
* sb64 
= (struct stat64 
*)0;  /* warning avoidance ; protected by isstat64 */ 
 702         if ((pinfo 
= pnode
->pinfo
) == NULL
) { 
 703                 PSHM_SUBSYS_UNLOCK(); 
 708         error 
= mac_posixshm_check_stat(kauth_cred_get(), &pinfo
->pshm_hdr
); 
 710                 PSHM_SUBSYS_UNLOCK(); 
 716                 sb64 
= (struct stat64 
*)ub
; 
 717                 bzero(sb64
, sizeof(struct stat64
)); 
 718                 sb64
->st_mode 
= pinfo
->pshm_mode
; 
 719                 sb64
->st_uid 
= pinfo
->pshm_uid
; 
 720                 sb64
->st_gid 
= pinfo
->pshm_gid
; 
 721                 sb64
->st_size 
= pinfo
->pshm_length
; 
 723                 sb 
= (struct stat 
*)ub
; 
 724                 bzero(sb
, sizeof(struct stat
)); 
 725                 sb
->st_mode 
= pinfo
->pshm_mode
; 
 726                 sb
->st_uid 
= pinfo
->pshm_uid
; 
 727                 sb
->st_gid 
= pinfo
->pshm_gid
; 
 728                 sb
->st_size 
= pinfo
->pshm_length
; 
 730         PSHM_SUBSYS_UNLOCK(); 
 736  * Verify access to a shared memory region. 
 739 pshm_access(pshm_info_t 
*pinfo
, int mode
, kauth_cred_t cred
, __unused proc_t p
) 
 741         int mode_req 
= ((mode 
& FREAD
) ? S_IRUSR 
: 0) | 
 742             ((mode 
& FWRITE
) ? S_IWUSR 
: 0); 
 744         /* Otherwise, user id 0 always gets access. */ 
 745         if (!suser(cred
, NULL
)) { 
 749         return posix_cred_access(cred
, pinfo
->pshm_uid
, pinfo
->pshm_gid
, pinfo
->pshm_mode
, mode_req
); 
 755         struct mmap_args   
*uap
, 
 760         vm_map_offset_t    user_addr 
= (vm_map_offset_t
)uap
->addr
; 
 761         vm_map_size_t      user_size 
= (vm_map_size_t
)uap
->len
; 
 762         vm_map_offset_t    user_start_addr
; 
 763         vm_map_size_t      map_size
, mapped_size
; 
 764         int                prot 
= uap
->prot
; 
 765         int                max_prot 
= VM_PROT_DEFAULT
; 
 766         int                flags 
= uap
->flags
; 
 767         vm_object_offset_t file_pos 
= (vm_object_offset_t
)uap
->pos
; 
 768         vm_object_offset_t map_pos
; 
 771         vm_map_kernel_flags_t vmk_flags
; 
 773         kern_return_t      kret 
= KERN_SUCCESS
; 
 776         pshm_mobj_t        
*pshmobj
; 
 779         if (user_size 
== 0) { 
 783         if (!(flags 
& MAP_SHARED
)) { 
 787         /* Can't allow write permission if the shm_open() didn't allow them. */ 
 788         if (!(fp
->f_flag 
& FWRITE
)) { 
 789                 if (prot 
& VM_PROT_WRITE
) { 
 792                 max_prot 
&= ~VM_PROT_WRITE
; 
 796         pnode 
= (pshmnode_t 
*)fp
->f_data
; 
 798                 PSHM_SUBSYS_UNLOCK(); 
 802         pinfo 
= pnode
->pinfo
; 
 804                 PSHM_SUBSYS_UNLOCK(); 
 808         if (!(pinfo
->pshm_flags 
& PSHM_ALLOCATED
)) { 
 809                 PSHM_SUBSYS_UNLOCK(); 
 813         if (user_size 
> (vm_map_size_t
)pinfo
->pshm_length
) { 
 814                 PSHM_SUBSYS_UNLOCK(); 
 818         vm_map_size_t end_pos 
= 0; 
 819         if (os_add_overflow(user_size
, file_pos
, &end_pos
)) { 
 820                 PSHM_SUBSYS_UNLOCK(); 
 823         if (end_pos 
> (vm_map_size_t
)pinfo
->pshm_length
) { 
 824                 PSHM_SUBSYS_UNLOCK(); 
 828         pshmobj 
= SLIST_FIRST(&pinfo
->pshm_mobjs
); 
 829         if (pshmobj 
== NULL
) { 
 830                 PSHM_SUBSYS_UNLOCK(); 
 835         error 
= mac_posixshm_check_mmap(kauth_cred_get(), &pinfo
->pshm_hdr
, prot
, flags
); 
 837                 PSHM_SUBSYS_UNLOCK(); 
 841         /* Grab an extra reference, so we can drop the lock while mapping. */ 
 842         error 
= pshm_ref(pinfo
); 
 844                 PSHM_SUBSYS_UNLOCK(); 
 848         PSHM_SUBSYS_UNLOCK(); 
 849         user_map 
= current_map(); 
 851         if (!(flags 
& MAP_FIXED
)) { 
 852                 alloc_flags 
= VM_FLAGS_ANYWHERE
; 
 853                 user_addr 
= vm_map_round_page(user_addr
, 
 854                     vm_map_page_mask(user_map
)); 
 856                 if (user_addr 
!= vm_map_round_page(user_addr
, 
 857                     vm_map_page_mask(user_map
))) { 
 863                  * We do not get rid of the existing mappings here because 
 864                  * it wouldn't be atomic (see comment in mmap()).  We let 
 865                  * Mach VM know that we want it to replace any existing 
 866                  * mapping with the new one. 
 868                 alloc_flags 
= VM_FLAGS_FIXED 
| VM_FLAGS_OVERWRITE
; 
 873         vmk_flags 
= VM_MAP_KERNEL_FLAGS_NONE
; 
 874         /* reserve the entire space first... */ 
 875         kret 
= vm_map_enter_mem_object(user_map
, 
 888         user_start_addr 
= user_addr
; 
 889         if (kret 
!= KERN_SUCCESS
) { 
 893         /* Now overwrite with the real mappings. */ 
 894         for (map_pos 
= 0, pshmobj 
= SLIST_FIRST(&pinfo
->pshm_mobjs
); 
 896             map_pos 
+= pshmobj
->pshmo_size
, pshmobj 
= SLIST_NEXT(pshmobj
, pshmo_next
)) { 
 897                 if (pshmobj 
== NULL
) { 
 898                         /* nothing there to map !? */ 
 901                 if (file_pos 
>= map_pos 
+ pshmobj
->pshmo_size
) { 
 904                 map_size 
= pshmobj
->pshmo_size 
- (file_pos 
- map_pos
); 
 905                 if (map_size 
> user_size
) { 
 906                         map_size 
= user_size
; 
 908                 vmk_flags 
= VM_MAP_KERNEL_FLAGS_NONE
; 
 909                 kret 
= vm_map_enter_mem_object( 
 914                         VM_FLAGS_FIXED 
| VM_FLAGS_OVERWRITE
, 
 917                         pshmobj
->pshmo_memobject
, 
 923                 if (kret 
!= KERN_SUCCESS
) { 
 927                 user_addr 
+= map_size
; 
 928                 user_size 
-= map_size
; 
 929                 mapped_size 
+= map_size
; 
 930                 file_pos 
+= map_size
; 
 934         pnode
->mapp_addr 
= user_start_addr
; 
 935         pinfo
->pshm_flags 
|= (PSHM_MAPPED 
| PSHM_INUSE
); 
 936         PSHM_SUBSYS_UNLOCK(); 
 939         pshm_deref(pinfo
);      /* drop the extra reference we had while mapping. */ 
 940         PSHM_SUBSYS_UNLOCK(); 
 941         if (kret 
!= KERN_SUCCESS
) { 
 942                 if (mapped_size 
!= 0) { 
 943                         (void) mach_vm_deallocate(current_map(), 
 951                 *retval 
= (user_start_addr 
+ pageoff
); 
 953         case KERN_INVALID_ADDRESS
: 
 956         case KERN_PROTECTION_FAILURE
: 
 964  * Remove a shared memory region name from the name lookup cache. 
 967 pshm_unlink_internal(pshm_info_t 
*pinfo
) 
 969         PSHM_SUBSYS_ASSERT_HELD(); 
 975         pshm_cache_delete(pinfo
); 
 976         pinfo
->pshm_flags 
|= PSHM_REMOVED
; 
 978         /* release the "unlink" reference */ 
 985 shm_unlink(proc_t p
, struct shm_unlink_args 
*uap
, __unused 
int32_t *retval
) 
 988         pshm_info_t 
*pinfo 
= NULL
; 
 989         pshm_info_t 
*name_pinfo 
= NULL
; 
 992          * Get the name from user args. 
 994         MALLOC(name_pinfo
, pshm_info_t 
*, sizeof(pshm_info_t
), M_SHM
, M_WAITOK 
| M_ZERO
); 
 995         if (name_pinfo 
== NULL
) { 
 999         error 
= pshm_get_name(name_pinfo
, uap
->name
); 
1006         pinfo 
= pshm_cache_search(name_pinfo
); 
1008         if (pinfo 
== NULL
) { 
1014         error 
= mac_posixshm_check_unlink(kauth_cred_get(), &pinfo
->pshm_hdr
, name_pinfo
->pshm_hdr
.pshm_name
); 
1020         AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, pinfo
->pshm_gid
, pinfo
->pshm_mode
); 
1023          * Following file semantics, unlink should normally be allowed 
1024          * for users with write permission only. We also allow the creator 
1025          * of a segment to be able to delete, even w/o write permission. 
1026          * That's because there's no equivalent of write permission for the 
1027          * directory containing a file. 
1029         error 
= pshm_access(pinfo
, FWRITE
, kauth_cred_get(), p
); 
1030         if (error 
!= 0 && pinfo
->pshm_uid 
!= kauth_getuid()) { 
1034         error 
= pshm_unlink_internal(pinfo
); 
1036         PSHM_SUBSYS_UNLOCK(); 
1038         if (name_pinfo 
!= NULL
) { 
1039                 FREE(name_pinfo
, M_SHM
); 
1045  * Add a new reference to a shared memory region. 
1046  * Fails if we will overflow the reference counter. 
1049 pshm_ref(pshm_info_t 
*pinfo
) 
1051         PSHM_SUBSYS_ASSERT_HELD(); 
1053         if (pinfo
->pshm_usecount 
== PSHM_MAXCOUNT
) { 
1056         pinfo
->pshm_usecount
++; 
1061  * Dereference a pshm_info_t. Delete the region if 
1062  * this was the final reference count. 
1065 pshm_deref(pshm_info_t 
*pinfo
) 
1067         pshm_mobj_t 
*pshmobj
; 
1069         PSHM_SUBSYS_ASSERT_HELD(); 
1070         if (pinfo
->pshm_usecount 
== 0) { 
1071                 panic("negative usecount in pshm_close\n"); 
1073         pinfo
->pshm_usecount
--; /* release this fd's reference */ 
1075         if (pinfo
->pshm_usecount 
== 0) { 
1077                 mac_posixshm_label_destroy(&pinfo
->pshm_hdr
); 
1079                 PSHM_SUBSYS_UNLOCK(); 
1082                  * Release references to any backing objects. 
1084                 while ((pshmobj 
= SLIST_FIRST(&pinfo
->pshm_mobjs
)) != NULL
) { 
1085                         SLIST_REMOVE_HEAD(&pinfo
->pshm_mobjs
, pshmo_next
); 
1086                         mach_memory_entry_port_release(pshmobj
->pshmo_memobject
); 
1087                         FREE(pshmobj
, M_SHM
); 
1090                 /* free the pinfo itself */ 
1097 /* vfs_context_t passed to match prototype for struct fileops */ 
1099 pshm_closefile(struct fileglob 
*fg
, __unused vfs_context_t ctx
) 
1106         pnode 
= (pshmnode_t 
*)fg
->fg_data
; 
1107         if (pnode 
!= NULL
) { 
1109                 fg
->fg_data 
= NULL
; /* set fg_data to NULL to avoid racing close()es */ 
1110                 if (pnode
->pinfo 
!= NULL
) { 
1111                         pshm_deref(pnode
->pinfo
); 
1112                         pnode
->pinfo 
= NULL
; 
1116         PSHM_SUBSYS_UNLOCK(); 
1117         if (pnode 
!= NULL
) { 
1125 fill_pshminfo(pshmnode_t 
* pshm
, struct pshm_info 
* info
) 
1128         struct vinfo_stat 
*sb
; 
1131         if ((pinfo 
= pshm
->pinfo
) == NULL
) { 
1132                 PSHM_SUBSYS_UNLOCK(); 
1136         sb 
= &info
->pshm_stat
; 
1138         bzero(sb
, sizeof(struct vinfo_stat
)); 
1139         sb
->vst_mode 
= pinfo
->pshm_mode
; 
1140         sb
->vst_uid 
= pinfo
->pshm_uid
; 
1141         sb
->vst_gid 
= pinfo
->pshm_gid
; 
1142         sb
->vst_size 
= pinfo
->pshm_length
; 
1144         info
->pshm_mappaddr 
= pshm
->mapp_addr
; 
1145         bcopy(&pinfo
->pshm_hdr
.pshm_name
[0], &info
->pshm_name
[0], PSHMNAMLEN 
+ 1); 
1147         PSHM_SUBSYS_UNLOCK(); 
1153 pshm_label_associate(struct fileproc 
*fp
, struct vnode 
*vp
, vfs_context_t ctx
) 
1159         pnode 
= (pshmnode_t 
*)fp
->f_data
; 
1160         if (pnode 
!= NULL
) { 
1161                 pshm 
= pnode
->pinfo
; 
1163                         mac_posixshm_vnode_label_associate( 
1164                                 vfs_context_ucred(ctx
), &pshm
->pshm_hdr
, pshm
->pshm_label
, 
1168         PSHM_SUBSYS_UNLOCK();