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>
85 #include <vm/vm_map.h>
86 #include <vm/vm_protos.h>
88 #define f_flag fp_glob->fg_flag
89 #define f_ops fp_glob->fg_ops
90 #define f_data fp_glob->fg_data
93 * Used to construct the list of memory objects
94 * assigned to a populated shared memory segment.
96 typedef struct pshm_mobj
{
97 void *pshmo_memobject
;
98 memory_object_size_t pshmo_size
;
99 SLIST_ENTRY(pshm_mobj
) pshmo_next
;
103 * This represents an existing Posix shared memory object.
105 * It comes into existence with a shm_open(...O_CREAT...)
106 * call and goes away only after it has been shm_unlink()ed
107 * and the last remaining shm_open() file reference is closed.
109 * To keep track of that lifetime, pshm_usecount is used as a reference
110 * counter. It's incremented for every successful shm_open() and
111 * one extra time for the shm_unlink() to release. Internally
112 * you can temporarily use an additional reference whenever the
113 * subsystem lock has to be dropped for other reasons.
115 typedef struct internal_pshminfo
{
116 struct pshminfo pshm_hdr
;
117 SLIST_HEAD(pshm_mobjhead
, pshm_mobj
) pshm_mobjs
;
118 RB_ENTRY(internal_pshminfo
) pshm_links
; /* links for red/black tree */
120 #define pshm_flags pshm_hdr.pshm_flags
121 #define pshm_usecount pshm_hdr.pshm_usecount
122 #define pshm_length pshm_hdr.pshm_length
123 #define pshm_mode pshm_hdr.pshm_mode
124 #define pshm_uid pshm_hdr.pshm_uid
125 #define pshm_gid pshm_hdr.pshm_gid
126 #define pshm_label pshm_hdr.pshm_label
128 /* Values for pshm_flags that are still used */
129 #define PSHM_ALLOCATED 0x004 /* backing storage is allocated */
130 #define PSHM_MAPPED 0x008 /* mapped at least once */
131 #define PSHM_INUSE 0x010 /* mapped at least once */
132 #define PSHM_REMOVED 0x020 /* no longer in the name cache due to shm_unlink() */
133 #define PSHM_ALLOCATING 0x100 /* storage is being allocated */
136 * These handle reference counting pshm_info_t structs using pshm_usecount.
138 static int pshm_ref(pshm_info_t
*pinfo
);
139 static void pshm_deref(pshm_info_t
*pinfo
);
140 #define PSHM_MAXCOUNT UINT_MAX
143 * For every shm_open, we get a new one of these.
144 * The only reason we don't just use pshm_info directly is that
145 * you can query the mapped memory objects via proc_pidinfo to
146 * query the mapped address. Note that even this is a hack. If
147 * you mmap() the same fd multiple times, we only save/report
150 typedef struct pshmnode
{
156 /* compare function for the red black tree */
158 pshm_compare(pshm_info_t
*a
, pshm_info_t
*b
)
160 int cmp
= strncmp(a
->pshm_hdr
.pshm_name
, b
->pshm_hdr
.pshm_name
, PSHMNAMLEN
+ 1);
173 * shared memory "paths" are stored in a red black tree for lookup
175 u_long pshmnument
; /* count of entries allocated in the red black tree */
176 RB_HEAD(pshmhead
, internal_pshminfo
) pshm_head
;
177 RB_PROTOTYPE(pshmhead
, internal_pshminfo
, pshm_links
, pshm_compare
)
178 RB_GENERATE(pshmhead
, internal_pshminfo
, pshm_links
, pshm_compare
)
180 /* lookup, add, remove functions */
181 static pshm_info_t
*pshm_cache_search(pshm_info_t
* look
);
182 static void pshm_cache_add(pshm_info_t
*entry
);
183 static void pshm_cache_delete(pshm_info_t
*entry
);
185 static int pshm_closefile(struct fileglob
*fg
, vfs_context_t ctx
);
187 static int pshm_access(pshm_info_t
*pinfo
, int mode
, kauth_cred_t cred
, proc_t p
);
188 int pshm_cache_purge_all(proc_t p
);
190 static int pshm_unlink_internal(pshm_info_t
*pinfo
);
192 static const struct fileops pshmops
= {
193 .fo_type
= DTYPE_PSXSHM
,
194 .fo_read
= fo_no_read
,
195 .fo_write
= fo_no_write
,
196 .fo_ioctl
= fo_no_ioctl
,
197 .fo_select
= fo_no_select
,
198 .fo_close
= pshm_closefile
,
199 .fo_drain
= fo_no_drain
,
200 .fo_kqfilter
= fo_no_kqfilter
,
204 * Everything here is protected by a single mutex.
206 static LCK_GRP_DECLARE(psx_shm_subsys_lck_grp
, "posix shared memory");
207 static LCK_MTX_DECLARE(psx_shm_subsys_mutex
, &psx_shm_subsys_lck_grp
);
209 #define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex)
210 #define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex)
211 #define PSHM_SUBSYS_ASSERT_HELD() LCK_MTX_ASSERT(&psx_shm_subsys_mutex, LCK_MTX_ASSERT_OWNED)
214 * Lookup an entry in the cache. Only the name is used from "look".
217 pshm_cache_search(pshm_info_t
*look
)
219 PSHM_SUBSYS_ASSERT_HELD();
220 return RB_FIND(pshmhead
, &pshm_head
, look
);
224 * Add a new entry to the cache.
227 pshm_cache_add(pshm_info_t
*entry
)
229 pshm_info_t
*conflict
;
231 PSHM_SUBSYS_ASSERT_HELD();
232 conflict
= RB_INSERT(pshmhead
, &pshm_head
, entry
);
233 if (conflict
!= NULL
) {
234 panic("pshm_cache_add() found %p", conflict
);
240 * Remove the given entry from the red black tree.
243 pshm_cache_delete(pshm_info_t
*entry
)
245 PSHM_SUBSYS_ASSERT_HELD();
246 assert(!(entry
->pshm_flags
& PSHM_REMOVED
));
247 RB_REMOVE(pshmhead
, &pshm_head
, entry
);
252 * Initialize the red black tree.
255 pshm_cache_init(void)
261 * Invalidate all entries and delete all objects associated with them
262 * XXX - due to the reference counting, this only works if all userland
263 * references to it via file descriptors are also closed already. Is this
264 * known to be called after all user processes are killed?
267 pshm_cache_purge_all(__unused proc_t proc
)
273 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
278 RB_FOREACH_SAFE(p
, pshmhead
, &pshm_head
, tmp
) {
279 error
= pshm_unlink_internal(p
);
280 if (error
) { /* XXX: why give up on failure, should keep going */
284 assert(pshmnument
== 0);
287 PSHM_SUBSYS_UNLOCK();
290 printf("%s: Error %d removing posix shm cache: %ld remain!\n",
291 __func__
, error
, pshmnument
);
297 * Utility to get the shared memory name from userspace and
298 * populate a pshm_info_t with it. If there's a problem
299 * reading the name or it's malformed, will return an error code.
302 pshm_get_name(pshm_info_t
*pinfo
, const user_addr_t user_addr
)
304 size_t bytes_copied
= 0;
308 error
= copyinstr(user_addr
, &pinfo
->pshm_hdr
.pshm_name
[0], PSHMNAMLEN
+ 1, &bytes_copied
);
312 assert(bytes_copied
<= PSHMNAMLEN
+ 1);
313 assert(pinfo
->pshm_hdr
.pshm_name
[bytes_copied
- 1] == 0);
314 if (bytes_copied
< 2) { /* 2: expect at least one character and terminating zero */
317 AUDIT_ARG(text
, &pinfo
->pshm_hdr
.pshm_name
[0]);
322 * Process a shm_open() system call.
325 shm_open(proc_t p
, struct shm_open_args
*uap
, int32_t *retval
)
329 pshm_info_t
*pinfo
= NULL
;
330 pshm_info_t
*new_pinfo
= NULL
;
331 pshmnode_t
*new_pnode
= NULL
;
332 struct fileproc
*fp
= NULL
;
334 mode_t cmode
= (mode_t
)uap
->mode
;
335 bool incache
= false;
336 bool have_label
= false;
338 AUDIT_ARG(fflags
, uap
->oflag
);
339 AUDIT_ARG(mode
, cmode
);
342 * Allocate data structures we need. We parse the userspace name into
343 * a pshm_info_t, even when we don't need to O_CREAT.
345 new_pinfo
= kheap_alloc(KM_SHM
, sizeof(pshm_info_t
), Z_WAITOK
| Z_ZERO
);
346 if (new_pinfo
== NULL
) {
352 * Get and check the name.
354 error
= pshm_get_name(new_pinfo
, uap
->name
);
360 * Attempt to allocate a new fp. If unsuccessful, the fp will be
361 * left unmodified (NULL).
363 error
= falloc(p
, &fp
, &indx
, vfs_context_current());
370 fmode
= FFLAGS(uap
->oflag
);
371 if ((fmode
& (FREAD
| FWRITE
)) == 0) {
377 * Will need a new pnode for the file pointer
379 new_pnode
= kheap_alloc(KM_SHM
, sizeof(pshmnode_t
),
381 if (new_pnode
== NULL
) {
387 * If creating a new segment, fill in its information.
388 * If we find a pre-exisitng one in cache lookup we'll just toss this one later.
390 if (fmode
& O_CREAT
) {
391 new_pinfo
->pshm_usecount
= 2; /* one each for: file pointer, shm_unlink */
392 new_pinfo
->pshm_length
= 0;
393 new_pinfo
->pshm_mode
= cmode
;
394 new_pinfo
->pshm_uid
= kauth_getuid();
395 new_pinfo
->pshm_gid
= kauth_getgid();
396 SLIST_INIT(&new_pinfo
->pshm_mobjs
);
398 mac_posixshm_label_init(&new_pinfo
->pshm_hdr
);
400 error
= mac_posixshm_check_create(kauth_cred_get(), new_pinfo
->pshm_hdr
.pshm_name
);
408 * Look up the named shared memory segment in the cache, possibly adding
413 pinfo
= pshm_cache_search(new_pinfo
);
417 /* Get a new reference to go with the file pointer.*/
418 error
= pshm_ref(pinfo
);
420 pinfo
= NULL
; /* so cleanup code doesn't deref */
424 /* can't have pre-existing if O_EXCL */
425 if ((fmode
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)) {
430 /* O_TRUNC is only valid while length is not yet set */
431 if ((fmode
& O_TRUNC
) &&
432 (pinfo
->pshm_flags
& (PSHM_ALLOCATING
| PSHM_ALLOCATED
))) {
439 /* if it wasn't found, must have O_CREAT */
440 if (!(fmode
& O_CREAT
)) {
445 /* Add the new region to the cache. */
447 pshm_cache_add(pinfo
);
448 new_pinfo
= NULL
; /* so that it doesn't get free'd */
451 PSHM_SUBSYS_UNLOCK();
454 * Check we have permission to access any pre-existing segment
457 if (fmode
& O_CREAT
) {
458 AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
,
459 pinfo
->pshm_gid
, pinfo
->pshm_mode
);
462 if ((error
= mac_posixshm_check_open(kauth_cred_get(), &pinfo
->pshm_hdr
, fmode
))) {
466 if ((error
= pshm_access(pinfo
, fmode
, kauth_cred_get(), p
))) {
471 mac_posixshm_label_associate(kauth_cred_get(), &pinfo
->pshm_hdr
, pinfo
->pshm_hdr
.pshm_name
);
476 fp
->f_flag
= fmode
& FMASK
;
477 fp
->f_ops
= &pshmops
;
478 new_pnode
->pinfo
= pinfo
;
479 fp
->f_data
= (caddr_t
)new_pnode
;
480 *fdflags(p
, indx
) |= UF_EXCLOSE
;
481 procfdtbl_releasefd(p
, indx
, NULL
);
482 fp_drop(p
, indx
, fp
, 1);
490 PSHM_SUBSYS_UNLOCK();
493 * Drop any new reference to a pre-existing shared memory region.
495 if (incache
&& pinfo
!= NULL
) {
498 PSHM_SUBSYS_UNLOCK();
502 * Delete any allocated unused data structures.
504 kheap_free(KM_SHM
, new_pnode
, sizeof(pshmnode_t
));
507 fp_free(p
, indx
, fp
);
511 if (new_pinfo
!= NULL
) {
514 mac_posixshm_label_destroy(&new_pinfo
->pshm_hdr
);
517 kheap_free(KM_SHM
, new_pinfo
, sizeof(pshm_info_t
));
524 * The truncate call associates memory with shared memory region. It can
525 * only be succesfully done with a non-zero length once per shared memory region.
533 __unused
int32_t *retval
)
538 mem_entry_name_port_t mem_object
;
539 mach_vm_size_t total_size
, alloc_size
;
540 memory_object_size_t mosize
;
541 pshm_mobj_t
*pshmobj
, *pshmobj_last
;
545 user_map
= current_map();
547 if (FILEGLOB_DTYPE(fp
->fp_glob
) != DTYPE_PSXSHM
) {
553 * Can't enforce this yet, some third party tools don't
554 * specify O_RDWR like they ought to. See radar 48692182
556 /* ftruncate() requires write permission */
557 if (!(fp
->f_flag
& FWRITE
)) {
563 if (((pnode
= (pshmnode_t
*)fp
->f_data
)) == NULL
) {
564 PSHM_SUBSYS_UNLOCK();
568 if ((pinfo
= pnode
->pinfo
) == NULL
) {
569 PSHM_SUBSYS_UNLOCK();
573 /* We only allow one ftruncate() per lifetime of the shm object. */
574 if (pinfo
->pshm_flags
& (PSHM_ALLOCATING
| PSHM_ALLOCATED
)) {
575 PSHM_SUBSYS_UNLOCK();
580 error
= mac_posixshm_check_truncate(kauth_cred_get(), &pinfo
->pshm_hdr
, length
);
582 PSHM_SUBSYS_UNLOCK();
587 * Grab an extra reference, so we can drop the lock while allocating and
588 * ensure the objects don't disappear.
590 error
= pshm_ref(pinfo
);
592 PSHM_SUBSYS_UNLOCK();
596 /* set ALLOCATING, so another truncate can't start */
597 pinfo
->pshm_flags
|= PSHM_ALLOCATING
;
598 total_size
= vm_map_round_page(length
, vm_map_page_mask(user_map
));
601 for (alloc_size
= 0; alloc_size
< total_size
; alloc_size
+= mosize
) {
602 PSHM_SUBSYS_UNLOCK();
604 /* get a memory object back some of the shared memory */
605 mosize
= MIN(total_size
- alloc_size
, ANON_MAX_SIZE
);
606 kret
= mach_make_memory_entry_64(VM_MAP_NULL
, &mosize
, 0,
607 MAP_MEM_NAMED_CREATE
| VM_PROT_DEFAULT
, &mem_object
, 0);
609 if (kret
!= KERN_SUCCESS
) {
613 /* get a list entry to track the memory object */
614 pshmobj
= kheap_alloc(KM_SHM
, sizeof(pshm_mobj_t
), Z_WAITOK
);
615 if (pshmobj
== NULL
) {
616 kret
= KERN_NO_SPACE
;
617 mach_memory_entry_port_release(mem_object
);
624 /* link in the new entry */
625 pshmobj
->pshmo_memobject
= (void *)mem_object
;
626 pshmobj
->pshmo_size
= mosize
;
627 SLIST_NEXT(pshmobj
, pshmo_next
) = NULL
;
629 if (pshmobj_last
== NULL
) {
630 SLIST_FIRST(&pinfo
->pshm_mobjs
) = pshmobj
;
632 SLIST_INSERT_AFTER(pshmobj_last
, pshmobj
, pshmo_next
);
634 pshmobj_last
= pshmobj
;
637 /* all done, change flags to ALLOCATED and return success */
638 pinfo
->pshm_flags
|= PSHM_ALLOCATED
;
639 pinfo
->pshm_flags
&= ~(PSHM_ALLOCATING
);
640 pinfo
->pshm_length
= total_size
;
641 pshm_deref(pinfo
); /* drop the "allocating" reference */
642 PSHM_SUBSYS_UNLOCK();
646 /* clean up any partially allocated objects */
648 while ((pshmobj
= SLIST_FIRST(&pinfo
->pshm_mobjs
)) != NULL
) {
649 SLIST_REMOVE_HEAD(&pinfo
->pshm_mobjs
, pshmo_next
);
650 PSHM_SUBSYS_UNLOCK();
651 mach_memory_entry_port_release(pshmobj
->pshmo_memobject
);
652 kheap_free(KM_SHM
, pshmobj
, sizeof(pshm_mobj_t
));
655 pinfo
->pshm_flags
&= ~PSHM_ALLOCATING
;
656 pshm_deref(pinfo
); /* drop the "allocating" reference */
657 PSHM_SUBSYS_UNLOCK();
660 case KERN_INVALID_ADDRESS
:
663 case KERN_PROTECTION_FAILURE
:
671 pshm_stat(pshmnode_t
*pnode
, void *ub
, int isstat64
)
673 struct stat
*sb
= (struct stat
*)0; /* warning avoidance ; protected by isstat64 */
674 struct stat64
* sb64
= (struct stat64
*)0; /* warning avoidance ; protected by isstat64 */
681 if ((pinfo
= pnode
->pinfo
) == NULL
) {
682 PSHM_SUBSYS_UNLOCK();
687 error
= mac_posixshm_check_stat(kauth_cred_get(), &pinfo
->pshm_hdr
);
689 PSHM_SUBSYS_UNLOCK();
695 sb64
= (struct stat64
*)ub
;
696 bzero(sb64
, sizeof(struct stat64
));
697 sb64
->st_mode
= pinfo
->pshm_mode
;
698 sb64
->st_uid
= pinfo
->pshm_uid
;
699 sb64
->st_gid
= pinfo
->pshm_gid
;
700 sb64
->st_size
= pinfo
->pshm_length
;
702 sb
= (struct stat
*)ub
;
703 bzero(sb
, sizeof(struct stat
));
704 sb
->st_mode
= pinfo
->pshm_mode
;
705 sb
->st_uid
= pinfo
->pshm_uid
;
706 sb
->st_gid
= pinfo
->pshm_gid
;
707 sb
->st_size
= pinfo
->pshm_length
;
709 PSHM_SUBSYS_UNLOCK();
715 * Verify access to a shared memory region.
718 pshm_access(pshm_info_t
*pinfo
, int mode
, kauth_cred_t cred
, __unused proc_t p
)
720 mode_t mode_req
= ((mode
& FREAD
) ? S_IRUSR
: 0) |
721 ((mode
& FWRITE
) ? S_IWUSR
: 0);
723 /* Otherwise, user id 0 always gets access. */
724 if (!suser(cred
, NULL
)) {
728 return posix_cred_access(cred
, pinfo
->pshm_uid
, pinfo
->pshm_gid
, pinfo
->pshm_mode
, mode_req
);
734 struct mmap_args
*uap
,
739 vm_map_offset_t user_addr
= (vm_map_offset_t
)uap
->addr
;
740 vm_map_size_t user_size
= (vm_map_size_t
)uap
->len
;
741 vm_map_offset_t user_start_addr
;
742 vm_map_size_t map_size
, mapped_size
;
743 int prot
= uap
->prot
;
744 int max_prot
= VM_PROT_DEFAULT
;
745 int flags
= uap
->flags
;
746 vm_object_offset_t file_pos
= (vm_object_offset_t
)uap
->pos
;
747 vm_object_offset_t map_pos
;
750 vm_map_kernel_flags_t vmk_flags
;
752 kern_return_t kret
= KERN_SUCCESS
;
755 pshm_mobj_t
*pshmobj
;
758 if (user_size
== 0) {
762 if (!(flags
& MAP_SHARED
)) {
766 /* Can't allow write permission if the shm_open() didn't allow them. */
767 if (!(fp
->f_flag
& FWRITE
)) {
768 if (prot
& VM_PROT_WRITE
) {
771 max_prot
&= ~VM_PROT_WRITE
;
775 pnode
= (pshmnode_t
*)fp
->f_data
;
777 PSHM_SUBSYS_UNLOCK();
781 pinfo
= pnode
->pinfo
;
783 PSHM_SUBSYS_UNLOCK();
787 if (!(pinfo
->pshm_flags
& PSHM_ALLOCATED
)) {
788 PSHM_SUBSYS_UNLOCK();
792 if (user_size
> (vm_map_size_t
)pinfo
->pshm_length
) {
793 PSHM_SUBSYS_UNLOCK();
797 vm_map_size_t end_pos
= 0;
798 if (os_add_overflow(user_size
, file_pos
, &end_pos
)) {
799 PSHM_SUBSYS_UNLOCK();
802 if (end_pos
> (vm_map_size_t
)pinfo
->pshm_length
) {
803 PSHM_SUBSYS_UNLOCK();
807 pshmobj
= SLIST_FIRST(&pinfo
->pshm_mobjs
);
808 if (pshmobj
== NULL
) {
809 PSHM_SUBSYS_UNLOCK();
814 error
= mac_posixshm_check_mmap(kauth_cred_get(), &pinfo
->pshm_hdr
, prot
, flags
);
816 PSHM_SUBSYS_UNLOCK();
820 /* Grab an extra reference, so we can drop the lock while mapping. */
821 error
= pshm_ref(pinfo
);
823 PSHM_SUBSYS_UNLOCK();
827 PSHM_SUBSYS_UNLOCK();
828 user_map
= current_map();
830 if (!(flags
& MAP_FIXED
)) {
831 alloc_flags
= VM_FLAGS_ANYWHERE
;
832 user_addr
= vm_map_round_page(user_addr
,
833 vm_map_page_mask(user_map
));
835 if (user_addr
!= vm_map_round_page(user_addr
,
836 vm_map_page_mask(user_map
))) {
842 * We do not get rid of the existing mappings here because
843 * it wouldn't be atomic (see comment in mmap()). We let
844 * Mach VM know that we want it to replace any existing
845 * mapping with the new one.
847 alloc_flags
= VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
;
852 vmk_flags
= VM_MAP_KERNEL_FLAGS_NONE
;
853 /* reserve the entire space first... */
854 kret
= vm_map_enter_mem_object(user_map
,
867 user_start_addr
= user_addr
;
868 if (kret
!= KERN_SUCCESS
) {
872 /* Now overwrite with the real mappings. */
873 for (map_pos
= 0, pshmobj
= SLIST_FIRST(&pinfo
->pshm_mobjs
);
875 map_pos
+= pshmobj
->pshmo_size
, pshmobj
= SLIST_NEXT(pshmobj
, pshmo_next
)) {
876 if (pshmobj
== NULL
) {
877 /* nothing there to map !? */
880 if (file_pos
>= map_pos
+ pshmobj
->pshmo_size
) {
883 map_size
= (vm_map_size_t
)(pshmobj
->pshmo_size
- (file_pos
- map_pos
));
884 if (map_size
> user_size
) {
885 map_size
= user_size
;
887 vmk_flags
= VM_MAP_KERNEL_FLAGS_NONE
;
888 kret
= vm_map_enter_mem_object(
893 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
896 pshmobj
->pshmo_memobject
,
902 if (kret
!= KERN_SUCCESS
) {
906 user_addr
+= map_size
;
907 user_size
-= map_size
;
908 mapped_size
+= map_size
;
909 file_pos
+= map_size
;
913 pnode
->mapp_addr
= user_start_addr
;
914 pinfo
->pshm_flags
|= (PSHM_MAPPED
| PSHM_INUSE
);
915 PSHM_SUBSYS_UNLOCK();
918 pshm_deref(pinfo
); /* drop the extra reference we had while mapping. */
919 PSHM_SUBSYS_UNLOCK();
920 if (kret
!= KERN_SUCCESS
) {
921 if (mapped_size
!= 0) {
922 (void) mach_vm_deallocate(current_map(),
930 *retval
= (user_addr_t
)(user_start_addr
+ pageoff
);
932 case KERN_INVALID_ADDRESS
:
935 case KERN_PROTECTION_FAILURE
:
943 * Remove a shared memory region name from the name lookup cache.
946 pshm_unlink_internal(pshm_info_t
*pinfo
)
948 PSHM_SUBSYS_ASSERT_HELD();
954 pshm_cache_delete(pinfo
);
955 pinfo
->pshm_flags
|= PSHM_REMOVED
;
957 /* release the "unlink" reference */
964 shm_unlink(proc_t p
, struct shm_unlink_args
*uap
, __unused
int32_t *retval
)
967 pshm_info_t
*pinfo
= NULL
;
968 pshm_info_t
*name_pinfo
= NULL
;
971 * Get the name from user args.
973 name_pinfo
= kheap_alloc(KHEAP_TEMP
, sizeof(pshm_info_t
),
975 if (name_pinfo
== NULL
) {
979 error
= pshm_get_name(name_pinfo
, uap
->name
);
986 pinfo
= pshm_cache_search(name_pinfo
);
994 error
= mac_posixshm_check_unlink(kauth_cred_get(), &pinfo
->pshm_hdr
, name_pinfo
->pshm_hdr
.pshm_name
);
1000 AUDIT_ARG(posix_ipc_perm
, pinfo
->pshm_uid
, pinfo
->pshm_gid
, pinfo
->pshm_mode
);
1003 * Following file semantics, unlink should normally be allowed
1004 * for users with write permission only. We also allow the creator
1005 * of a segment to be able to delete, even w/o write permission.
1006 * That's because there's no equivalent of write permission for the
1007 * directory containing a file.
1009 error
= pshm_access(pinfo
, FWRITE
, kauth_cred_get(), p
);
1010 if (error
!= 0 && pinfo
->pshm_uid
!= kauth_getuid()) {
1014 error
= pshm_unlink_internal(pinfo
);
1016 PSHM_SUBSYS_UNLOCK();
1018 kheap_free(KHEAP_TEMP
, name_pinfo
, sizeof(pshm_info_t
));
1023 * Add a new reference to a shared memory region.
1024 * Fails if we will overflow the reference counter.
1027 pshm_ref(pshm_info_t
*pinfo
)
1029 PSHM_SUBSYS_ASSERT_HELD();
1031 if (pinfo
->pshm_usecount
== PSHM_MAXCOUNT
) {
1034 pinfo
->pshm_usecount
++;
1039 * Dereference a pshm_info_t. Delete the region if
1040 * this was the final reference count.
1043 pshm_deref(pshm_info_t
*pinfo
)
1045 pshm_mobj_t
*pshmobj
;
1047 PSHM_SUBSYS_ASSERT_HELD();
1048 if (pinfo
->pshm_usecount
== 0) {
1049 panic("negative usecount in pshm_close\n");
1051 pinfo
->pshm_usecount
--; /* release this fd's reference */
1053 if (pinfo
->pshm_usecount
== 0) {
1055 mac_posixshm_label_destroy(&pinfo
->pshm_hdr
);
1057 PSHM_SUBSYS_UNLOCK();
1060 * Release references to any backing objects.
1062 while ((pshmobj
= SLIST_FIRST(&pinfo
->pshm_mobjs
)) != NULL
) {
1063 SLIST_REMOVE_HEAD(&pinfo
->pshm_mobjs
, pshmo_next
);
1064 mach_memory_entry_port_release(pshmobj
->pshmo_memobject
);
1065 kheap_free(KM_SHM
, pshmobj
, sizeof(pshm_mobj_t
));
1068 /* free the pinfo itself */
1069 kheap_free(KM_SHM
, pinfo
, sizeof(pshm_info_t
));
1075 /* vfs_context_t passed to match prototype for struct fileops */
1077 pshm_closefile(struct fileglob
*fg
, __unused vfs_context_t ctx
)
1084 pnode
= (pshmnode_t
*)fg
->fg_data
;
1085 if (pnode
!= NULL
) {
1087 fg
->fg_data
= NULL
; /* set fg_data to NULL to avoid racing close()es */
1088 if (pnode
->pinfo
!= NULL
) {
1089 pshm_deref(pnode
->pinfo
);
1090 pnode
->pinfo
= NULL
;
1094 PSHM_SUBSYS_UNLOCK();
1095 kheap_free(KM_SHM
, pnode
, sizeof(pshmnode_t
));
1101 fill_pshminfo(pshmnode_t
* pshm
, struct pshm_info
* info
)
1104 struct vinfo_stat
*sb
;
1107 if ((pinfo
= pshm
->pinfo
) == NULL
) {
1108 PSHM_SUBSYS_UNLOCK();
1112 sb
= &info
->pshm_stat
;
1114 bzero(sb
, sizeof(struct vinfo_stat
));
1115 sb
->vst_mode
= pinfo
->pshm_mode
;
1116 sb
->vst_uid
= pinfo
->pshm_uid
;
1117 sb
->vst_gid
= pinfo
->pshm_gid
;
1118 sb
->vst_size
= pinfo
->pshm_length
;
1120 info
->pshm_mappaddr
= pshm
->mapp_addr
;
1121 bcopy(&pinfo
->pshm_hdr
.pshm_name
[0], &info
->pshm_name
[0], PSHMNAMLEN
+ 1);
1123 PSHM_SUBSYS_UNLOCK();
1129 pshm_label_associate(struct fileproc
*fp
, struct vnode
*vp
, vfs_context_t ctx
)
1135 pnode
= (pshmnode_t
*)fp
->f_data
;
1136 if (pnode
!= NULL
) {
1137 pshm
= pnode
->pinfo
;
1139 mac_posixshm_vnode_label_associate(
1140 vfs_context_ucred(ctx
), &pshm
->pshm_hdr
, pshm
->pshm_label
,
1144 PSHM_SUBSYS_UNLOCK();