]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/posix_shm.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / posix_shm.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
30 * All Rights Reserved.
31 */
32/*
9bccf70c 33 * posix_shm.c : Support for POSIX shared memory APIs
1c79356b
A
34 *
35 * File: posix_shm.c
36 * Author: Ananthakrishna Ramesh
37 *
38 * HISTORY
39 * 2-Sep-1999 A.Ramesh
40 * Created for MacOSX
41 *
42 */
2d21ac55
A
43/*
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,
47 * Version 2.0.
48 */
1c79356b
A
49
50#include <sys/cdefs.h>
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/kernel.h>
91447636 54#include <sys/file_internal.h>
1c79356b
A
55#include <sys/filedesc.h>
56#include <sys/stat.h>
91447636
A
57#include <sys/proc_internal.h>
58#include <sys/kauth.h>
1c79356b
A
59#include <sys/mount.h>
60#include <sys/namei.h>
61#include <sys/vnode.h>
2d21ac55 62#include <sys/vnode_internal.h>
1c79356b
A
63#include <sys/ioctl.h>
64#include <sys/tty.h>
65#include <sys/malloc.h>
66#include <sys/mman.h>
91447636
A
67#include <sys/stat.h>
68#include <sys/sysproto.h>
0c530ab8 69#include <sys/proc_info.h>
0a7de745 70#include <sys/posix_shm.h>
b0d623f7 71#include <security/audit/audit.h>
0a7de745 72#include <stdbool.h>
e5568f75 73
2d21ac55
A
74#if CONFIG_MACF
75#include <security/mac_framework.h>
76#endif
77
1c79356b 78#include <mach/mach_types.h>
91447636
A
79#include <mach/mach_vm.h>
80#include <mach/vm_map.h>
1c79356b
A
81#include <mach/vm_prot.h>
82#include <mach/vm_inherit.h>
83#include <mach/kern_return.h>
1c79356b 84
91447636
A
85#include <vm/vm_map.h>
86#include <vm/vm_protos.h>
1c79356b 87
f427ee49
A
88#define f_flag fp_glob->fg_flag
89#define f_ops fp_glob->fg_ops
90#define f_data fp_glob->fg_data
1c79356b 91
0a7de745
A
92/*
93 * Used to construct the list of memory objects
94 * assigned to a populated shared memory segment.
95 */
96typedef struct pshm_mobj {
97 void *pshmo_memobject;
98 memory_object_size_t pshmo_size;
99 SLIST_ENTRY(pshm_mobj) pshmo_next;
100} pshm_mobj_t;
b0d623f7 101
0a7de745
A
102/*
103 * This represents an existing Posix shared memory object.
104 *
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.
108 *
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.
114 */
115typedef 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 */
119} pshm_info_t;
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
127
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 */
1c79356b 134
0a7de745
A
135/*
136 * These handle reference counting pshm_info_t structs using pshm_usecount.
137 */
138static int pshm_ref(pshm_info_t *pinfo);
139static void pshm_deref(pshm_info_t *pinfo);
140#define PSHM_MAXCOUNT UINT_MAX
141
142/*
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
148 * one address.
149 */
150typedef struct pshmnode {
151 off_t mapp_addr;
152 pshm_info_t *pinfo;
153} pshmnode_t;
1c79356b 154
1c79356b 155
0a7de745
A
156/* compare function for the red black tree */
157static int
158pshm_compare(pshm_info_t *a, pshm_info_t *b)
159{
160 int cmp = strncmp(a->pshm_hdr.pshm_name, b->pshm_hdr.pshm_name, PSHMNAMLEN + 1);
1c79356b 161
0a7de745
A
162 if (cmp < 0) {
163 return -1;
164 }
165 if (cmp > 0) {
166 return 1;
167 }
168 return 0;
169}
91447636 170
1c79356b 171
0a7de745
A
172/*
173 * shared memory "paths" are stored in a red black tree for lookup
174 */
175u_long pshmnument; /* count of entries allocated in the red black tree */
176RB_HEAD(pshmhead, internal_pshminfo) pshm_head;
177RB_PROTOTYPE(pshmhead, internal_pshminfo, pshm_links, pshm_compare)
178RB_GENERATE(pshmhead, internal_pshminfo, pshm_links, pshm_compare)
179
180/* lookup, add, remove functions */
181static pshm_info_t *pshm_cache_search(pshm_info_t * look);
182static void pshm_cache_add(pshm_info_t *entry);
183static void pshm_cache_delete(pshm_info_t *entry);
184
0a7de745 185static int pshm_closefile(struct fileglob *fg, vfs_context_t ctx);
91447636 186
0a7de745 187static int pshm_access(pshm_info_t *pinfo, int mode, kauth_cred_t cred, proc_t p);
490019cf
A
188int pshm_cache_purge_all(proc_t p);
189
0a7de745 190static int pshm_unlink_internal(pshm_info_t *pinfo);
55e303ae 191
39236c6e 192static const struct fileops pshmops = {
cb323159
A
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,
39236c6e 201};
91447636 202
0a7de745
A
203/*
204 * Everything here is protected by a single mutex.
205 */
c3c9b80d
A
206static LCK_GRP_DECLARE(psx_shm_subsys_lck_grp, "posix shared memory");
207static LCK_MTX_DECLARE(psx_shm_subsys_mutex, &psx_shm_subsys_lck_grp);
91447636
A
208
209#define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex)
210#define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex)
39037602 211#define PSHM_SUBSYS_ASSERT_HELD() LCK_MTX_ASSERT(&psx_shm_subsys_mutex, LCK_MTX_ASSERT_OWNED)
91447636 212
1c79356b 213/*
0a7de745 214 * Lookup an entry in the cache. Only the name is used from "look".
1c79356b 215 */
0a7de745
A
216static pshm_info_t *
217pshm_cache_search(pshm_info_t *look)
1c79356b 218{
0a7de745
A
219 PSHM_SUBSYS_ASSERT_HELD();
220 return RB_FIND(pshmhead, &pshm_head, look);
1c79356b
A
221}
222
223/*
0a7de745 224 * Add a new entry to the cache.
1c79356b 225 */
0a7de745
A
226static void
227pshm_cache_add(pshm_info_t *entry)
1c79356b 228{
0a7de745 229 pshm_info_t *conflict;
1c79356b 230
0a7de745
A
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);
1c79356b
A
235 }
236 pshmnument++;
0a7de745 237}
1c79356b 238
0a7de745
A
239/*
240 * Remove the given entry from the red black tree.
241 */
242static void
243pshm_cache_delete(pshm_info_t *entry)
244{
245 PSHM_SUBSYS_ASSERT_HELD();
246 assert(!(entry->pshm_flags & PSHM_REMOVED));
247 RB_REMOVE(pshmhead, &pshm_head, entry);
248 pshmnument--;
1c79356b
A
249}
250
251/*
0a7de745 252 * Initialize the red black tree.
1c79356b
A
253 */
254void
91447636 255pshm_cache_init(void)
1c79356b 256{
0a7de745 257 RB_INIT(&pshm_head);
1c79356b
A
258}
259
260/*
0a7de745
A
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?
1c79356b 265 */
490019cf 266int
0a7de745 267pshm_cache_purge_all(__unused proc_t proc)
1c79356b 268{
0a7de745
A
269 pshm_info_t *p;
270 pshm_info_t *tmp;
490019cf
A
271 int error = 0;
272
0a7de745 273 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
490019cf 274 return EPERM;
0a7de745 275 }
1c79356b 276
490019cf 277 PSHM_SUBSYS_LOCK();
0a7de745
A
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 */
281 goto out;
490019cf 282 }
1c79356b 283 }
490019cf
A
284 assert(pshmnument == 0);
285
286out:
287 PSHM_SUBSYS_UNLOCK();
288
0a7de745
A
289 if (error) {
290 printf("%s: Error %d removing posix shm cache: %ld remain!\n",
291 __func__, error, pshmnument);
292 }
490019cf 293 return error;
1c79356b
A
294}
295
0a7de745
A
296/*
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.
300 */
301static int
302pshm_get_name(pshm_info_t *pinfo, const user_addr_t user_addr)
1c79356b 303{
0a7de745
A
304 size_t bytes_copied = 0;
305 int error;
1c79356b
A
306
307
0a7de745
A
308 error = copyinstr(user_addr, &pinfo->pshm_hdr.pshm_name[0], PSHMNAMLEN + 1, &bytes_copied);
309 if (error != 0) {
310 return error;
311 }
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 */
315 return EINVAL;
316 }
317 AUDIT_ARG(text, &pinfo->pshm_hdr.pshm_name[0]);
318 return 0;
319}
320
321/*
322 * Process a shm_open() system call.
323 */
1c79356b 324int
b0d623f7 325shm_open(proc_t p, struct shm_open_args *uap, int32_t *retval)
1c79356b 326{
0a7de745
A
327 int indx;
328 int error = 0;
329 pshm_info_t *pinfo = NULL;
330 pshm_info_t *new_pinfo = NULL;
331 pshmnode_t *new_pnode = NULL;
b0d623f7 332 struct fileproc *fp = NULL;
0a7de745 333 int fmode;
f427ee49 334 mode_t cmode = (mode_t)uap->mode;
0a7de745
A
335 bool incache = false;
336 bool have_label = false;
1c79356b 337
e5568f75 338 AUDIT_ARG(fflags, uap->oflag);
f427ee49 339 AUDIT_ARG(mode, cmode);
91447636 340
b0d623f7 341 /*
0a7de745
A
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.
b0d623f7 344 */
c3c9b80d 345 new_pinfo = kheap_alloc(KM_SHM, sizeof(pshm_info_t), Z_WAITOK | Z_ZERO);
0a7de745 346 if (new_pinfo == NULL) {
b0d623f7
A
347 error = ENOSPC;
348 goto bad;
91447636
A
349 }
350
0a7de745
A
351 /*
352 * Get and check the name.
353 */
354 error = pshm_get_name(new_pinfo, uap->name);
355 if (error != 0) {
1c79356b
A
356 goto bad;
357 }
1c79356b 358
b0d623f7 359 /*
0a7de745 360 * Attempt to allocate a new fp. If unsuccessful, the fp will be
b0d623f7
A
361 * left unmodified (NULL).
362 */
363 error = falloc(p, &fp, &indx, vfs_context_current());
0a7de745 364 if (error) {
b0d623f7 365 goto bad;
0a7de745 366 }
b0d623f7 367
0a7de745 368 cmode &= ALLPERMS;
6d2010ae
A
369
370 fmode = FFLAGS(uap->oflag);
371 if ((fmode & (FREAD | FWRITE)) == 0) {
372 error = EINVAL;
373 goto bad;
374 }
375
b0d623f7 376 /*
0a7de745 377 * Will need a new pnode for the file pointer
b0d623f7 378 */
c3c9b80d
A
379 new_pnode = kheap_alloc(KM_SHM, sizeof(pshmnode_t),
380 Z_WAITOK | Z_ZERO);
0a7de745 381 if (new_pnode == NULL) {
b0d623f7
A
382 error = ENOSPC;
383 goto bad;
384 }
385
0a7de745
A
386 /*
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.
389 */
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);
b0d623f7 397#if CONFIG_MACF
0a7de745
A
398 mac_posixshm_label_init(&new_pinfo->pshm_hdr);
399 have_label = true;
400 error = mac_posixshm_check_create(kauth_cred_get(), new_pinfo->pshm_hdr.pshm_name);
401 if (error) {
402 goto bad;
403 }
b0d623f7 404#endif
b0d623f7
A
405 }
406
6d2010ae 407 /*
0a7de745
A
408 * Look up the named shared memory segment in the cache, possibly adding
409 * it for O_CREAT.
6d2010ae 410 */
0a7de745 411 PSHM_SUBSYS_LOCK();
1c79356b 412
0a7de745
A
413 pinfo = pshm_cache_search(new_pinfo);
414 if (pinfo != NULL) {
415 incache = true;
6d2010ae 416
0a7de745
A
417 /* Get a new reference to go with the file pointer.*/
418 error = pshm_ref(pinfo);
419 if (error) {
420 pinfo = NULL; /* so cleanup code doesn't deref */
421 goto bad_locked;
2d21ac55 422 }
2d21ac55 423
0a7de745
A
424 /* can't have pre-existing if O_EXCL */
425 if ((fmode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
426 error = EEXIST;
427 goto bad_locked;
91447636 428 }
6d2010ae 429
0a7de745
A
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))) {
433 error = EINVAL;
434 goto bad_locked;
435 }
436 } else {
437 incache = false;
6d2010ae 438
0a7de745
A
439 /* if it wasn't found, must have O_CREAT */
440 if (!(fmode & O_CREAT)) {
441 error = ENOENT;
b0d623f7 442 goto bad_locked;
1c79356b 443 }
0a7de745
A
444
445 /* Add the new region to the cache. */
446 pinfo = new_pinfo;
447 pshm_cache_add(pinfo);
448 new_pinfo = NULL; /* so that it doesn't get free'd */
1c79356b 449 }
91447636
A
450
451 PSHM_SUBSYS_UNLOCK();
b0d623f7
A
452
453 /*
0a7de745 454 * Check we have permission to access any pre-existing segment
b0d623f7
A
455 */
456 if (incache) {
0a7de745
A
457 if (fmode & O_CREAT) {
458 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
459 pinfo->pshm_gid, pinfo->pshm_mode);
460 }
b0d623f7 461#if CONFIG_MACF
0a7de745
A
462 if ((error = mac_posixshm_check_open(kauth_cred_get(), &pinfo->pshm_hdr, fmode))) {
463 goto bad;
464 }
b0d623f7 465#endif
0a7de745
A
466 if ((error = pshm_access(pinfo, fmode, kauth_cred_get(), p))) {
467 goto bad;
b0d623f7 468 }
0a7de745
A
469 } else {
470#if CONFIG_MACF
471 mac_posixshm_label_associate(kauth_cred_get(), &pinfo->pshm_hdr, pinfo->pshm_hdr.pshm_name);
472#endif
b0d623f7
A
473 }
474
91447636 475 proc_fdlock(p);
1c79356b 476 fp->f_flag = fmode & FMASK;
1c79356b 477 fp->f_ops = &pshmops;
0a7de745 478 new_pnode->pinfo = pinfo;
b0d623f7 479 fp->f_data = (caddr_t)new_pnode;
2d21ac55 480 *fdflags(p, indx) |= UF_EXCLOSE;
6601e61a 481 procfdtbl_releasefd(p, indx, NULL);
91447636
A
482 fp_drop(p, indx, fp, 1);
483 proc_fdunlock(p);
484
1c79356b 485 *retval = indx;
0a7de745
A
486 error = 0;
487 goto done;
2d21ac55 488
b0d623f7
A
489bad_locked:
490 PSHM_SUBSYS_UNLOCK();
491bad:
6d2010ae 492 /*
0a7de745 493 * Drop any new reference to a pre-existing shared memory region.
6d2010ae 494 */
0a7de745 495 if (incache && pinfo != NULL) {
6d2010ae 496 PSHM_SUBSYS_LOCK();
0a7de745 497 pshm_deref(pinfo);
6d2010ae
A
498 PSHM_SUBSYS_UNLOCK();
499 }
500
0a7de745
A
501 /*
502 * Delete any allocated unused data structures.
503 */
c3c9b80d 504 kheap_free(KM_SHM, new_pnode, sizeof(pshmnode_t));
b0d623f7 505
0a7de745 506 if (fp != NULL) {
b0d623f7 507 fp_free(p, indx, fp);
0a7de745 508 }
b0d623f7 509
0a7de745
A
510done:
511 if (new_pinfo != NULL) {
2d21ac55 512#if CONFIG_MACF
0a7de745
A
513 if (have_label) {
514 mac_posixshm_label_destroy(&new_pinfo->pshm_hdr);
515 }
2d21ac55 516#endif
c3c9b80d 517 kheap_free(KM_SHM, new_pinfo, sizeof(pshm_info_t));
2d21ac55 518 }
0a7de745 519 return error;
1c79356b
A
520}
521
522
0a7de745
A
523/*
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.
526 */
1c79356b 527int
0a7de745
A
528pshm_truncate(
529 __unused proc_t p,
530 struct fileproc *fp,
531 __unused int fd,
532 off_t length,
533 __unused int32_t *retval)
1c79356b 534{
0a7de745
A
535 pshm_info_t *pinfo;
536 pshmnode_t *pnode;
537 kern_return_t kret;
91447636 538 mem_entry_name_port_t mem_object;
0a7de745
A
539 mach_vm_size_t total_size, alloc_size;
540 memory_object_size_t mosize;
541 pshm_mobj_t *pshmobj, *pshmobj_last;
542 vm_map_t user_map;
543 int error;
1c79356b 544
39236c6e
A
545 user_map = current_map();
546
f427ee49 547 if (FILEGLOB_DTYPE(fp->fp_glob) != DTYPE_PSXSHM) {
0a7de745 548 return EINVAL;
1c79356b 549 }
1c79356b 550
0a7de745
A
551#if 0
552 /*
553 * Can't enforce this yet, some third party tools don't
554 * specify O_RDWR like they ought to. See radar 48692182
555 */
556 /* ftruncate() requires write permission */
557 if (!(fp->f_flag & FWRITE)) {
558 return EINVAL;
559 }
560#endif
1c79356b 561
91447636 562 PSHM_SUBSYS_LOCK();
0a7de745 563 if (((pnode = (pshmnode_t *)fp->f_data)) == NULL) {
91447636 564 PSHM_SUBSYS_UNLOCK();
0a7de745 565 return EINVAL;
91447636 566 }
0a7de745
A
567
568 if ((pinfo = pnode->pinfo) == NULL) {
569 PSHM_SUBSYS_UNLOCK();
570 return EINVAL;
571 }
572
573 /* We only allow one ftruncate() per lifetime of the shm object. */
574 if (pinfo->pshm_flags & (PSHM_ALLOCATING | PSHM_ALLOCATED)) {
91447636 575 PSHM_SUBSYS_UNLOCK();
0a7de745 576 return EINVAL;
1c79356b 577 }
0a7de745 578
2d21ac55 579#if CONFIG_MACF
0a7de745 580 error = mac_posixshm_check_truncate(kauth_cred_get(), &pinfo->pshm_hdr, length);
2d21ac55
A
581 if (error) {
582 PSHM_SUBSYS_UNLOCK();
0a7de745 583 return error;
2d21ac55
A
584 }
585#endif
0a7de745
A
586 /*
587 * Grab an extra reference, so we can drop the lock while allocating and
588 * ensure the objects don't disappear.
589 */
590 error = pshm_ref(pinfo);
591 if (error) {
592 PSHM_SUBSYS_UNLOCK();
593 return error;
594 }
1c79356b 595
0a7de745 596 /* set ALLOCATING, so another truncate can't start */
b0d623f7 597 pinfo->pshm_flags |= PSHM_ALLOCATING;
0a7de745 598 total_size = vm_map_round_page(length, vm_map_page_mask(user_map));
1c79356b 599
0a7de745
A
600 pshmobj_last = NULL;
601 for (alloc_size = 0; alloc_size < total_size; alloc_size += mosize) {
b0d623f7
A
602 PSHM_SUBSYS_UNLOCK();
603
0a7de745 604 /* get a memory object back some of the shared memory */
6d2010ae 605 mosize = MIN(total_size - alloc_size, ANON_MAX_SIZE);
0a7de745
A
606 kret = mach_make_memory_entry_64(VM_MAP_NULL, &mosize, 0,
607 MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT, &mem_object, 0);
b0d623f7 608
0a7de745 609 if (kret != KERN_SUCCESS) {
b0d623f7 610 goto out;
0a7de745 611 }
b0d623f7 612
0a7de745 613 /* get a list entry to track the memory object */
c3c9b80d 614 pshmobj = kheap_alloc(KM_SHM, sizeof(pshm_mobj_t), Z_WAITOK);
b0d623f7
A
615 if (pshmobj == NULL) {
616 kret = KERN_NO_SPACE;
617 mach_memory_entry_port_release(mem_object);
618 mem_object = NULL;
619 goto out;
620 }
621
622 PSHM_SUBSYS_LOCK();
623
0a7de745
A
624 /* link in the new entry */
625 pshmobj->pshmo_memobject = (void *)mem_object;
6d2010ae 626 pshmobj->pshmo_size = mosize;
0a7de745
A
627 SLIST_NEXT(pshmobj, pshmo_next) = NULL;
628
629 if (pshmobj_last == NULL) {
630 SLIST_FIRST(&pinfo->pshm_mobjs) = pshmobj;
631 } else {
632 SLIST_INSERT_AFTER(pshmobj_last, pshmobj, pshmo_next);
633 }
634 pshmobj_last = pshmobj;
b0d623f7 635 }
0a7de745
A
636
637 /* all done, change flags to ALLOCATED and return success */
3e170ce0
A
638 pinfo->pshm_flags |= PSHM_ALLOCATED;
639 pinfo->pshm_flags &= ~(PSHM_ALLOCATING);
b0d623f7 640 pinfo->pshm_length = total_size;
0a7de745 641 pshm_deref(pinfo); /* drop the "allocating" reference */
91447636 642 PSHM_SUBSYS_UNLOCK();
0a7de745 643 return 0;
1c79356b
A
644
645out:
0a7de745 646 /* clean up any partially allocated objects */
b0d623f7 647 PSHM_SUBSYS_LOCK();
0a7de745
A
648 while ((pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs)) != NULL) {
649 SLIST_REMOVE_HEAD(&pinfo->pshm_mobjs, pshmo_next);
650 PSHM_SUBSYS_UNLOCK();
b0d623f7 651 mach_memory_entry_port_release(pshmobj->pshmo_memobject);
c3c9b80d 652 kheap_free(KM_SHM, pshmobj, sizeof(pshm_mobj_t));
0a7de745 653 PSHM_SUBSYS_LOCK();
b0d623f7 654 }
b0d623f7 655 pinfo->pshm_flags &= ~PSHM_ALLOCATING;
0a7de745 656 pshm_deref(pinfo); /* drop the "allocating" reference */
b0d623f7
A
657 PSHM_SUBSYS_UNLOCK();
658
1c79356b
A
659 switch (kret) {
660 case KERN_INVALID_ADDRESS:
661 case KERN_NO_SPACE:
0a7de745 662 return ENOMEM;
1c79356b 663 case KERN_PROTECTION_FAILURE:
0a7de745 664 return EACCES;
1c79356b 665 default:
0a7de745 666 return EINVAL;
1c79356b
A
667 }
668}
669
670int
0a7de745 671pshm_stat(pshmnode_t *pnode, void *ub, int isstat64)
1c79356b 672{
0a7de745 673 struct stat *sb = (struct stat *)0; /* warning avoidance ; protected by isstat64 */
2d21ac55 674 struct stat64 * sb64 = (struct stat64 *)0; /* warning avoidance ; protected by isstat64 */
0a7de745 675 pshm_info_t *pinfo;
2d21ac55
A
676#if CONFIG_MACF
677 int error;
678#endif
0a7de745 679
91447636 680 PSHM_SUBSYS_LOCK();
0a7de745 681 if ((pinfo = pnode->pinfo) == NULL) {
91447636 682 PSHM_SUBSYS_UNLOCK();
0a7de745 683 return EINVAL;
91447636 684 }
1c79356b 685
2d21ac55 686#if CONFIG_MACF
0a7de745 687 error = mac_posixshm_check_stat(kauth_cred_get(), &pinfo->pshm_hdr);
2d21ac55
A
688 if (error) {
689 PSHM_SUBSYS_UNLOCK();
0a7de745 690 return error;
2d21ac55
A
691 }
692#endif
693
694 if (isstat64 != 0) {
695 sb64 = (struct stat64 *)ub;
0a7de745 696 bzero(sb64, sizeof(struct stat64));
2d21ac55
A
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;
701 } else {
702 sb = (struct stat *)ub;
0a7de745 703 bzero(sb, sizeof(struct stat));
2d21ac55
A
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;
708 }
91447636 709 PSHM_SUBSYS_UNLOCK();
1c79356b 710
0a7de745 711 return 0;
1c79356b
A
712}
713
91447636 714/*
0a7de745 715 * Verify access to a shared memory region.
91447636 716 */
0a7de745
A
717static int
718pshm_access(pshm_info_t *pinfo, int mode, kauth_cred_t cred, __unused proc_t p)
1c79356b 719{
f427ee49 720 mode_t mode_req = ((mode & FREAD) ? S_IRUSR : 0) |
0a7de745 721 ((mode & FWRITE) ? S_IWUSR : 0);
1c79356b
A
722
723 /* Otherwise, user id 0 always gets access. */
0a7de745
A
724 if (!suser(cred, NULL)) {
725 return 0;
726 }
1c79356b 727
0a7de745 728 return posix_cred_access(cred, pinfo->pshm_uid, pinfo->pshm_gid, pinfo->pshm_mode, mode_req);
1c79356b 729}
9bccf70c 730
1c79356b 731int
0a7de745
A
732pshm_mmap(
733 __unused proc_t p,
734 struct mmap_args *uap,
735 user_addr_t *retval,
736 struct fileproc *fp,
737 off_t pageoff)
1c79356b 738{
0a7de745
A
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;
1c79356b 746 vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
b0d623f7 747 vm_object_offset_t map_pos;
0a7de745
A
748 vm_map_t user_map;
749 int alloc_flags;
5ba3f43e 750 vm_map_kernel_flags_t vmk_flags;
0a7de745
A
751 bool docow;
752 kern_return_t kret = KERN_SUCCESS;
753 pshm_info_t *pinfo;
754 pshmnode_t *pnode;
755 pshm_mobj_t *pshmobj;
756 int error;
757
758 if (user_size == 0) {
759 return 0;
760 }
1c79356b 761
0a7de745
A
762 if (!(flags & MAP_SHARED)) {
763 return EINVAL;
764 }
1c79356b 765
0a7de745 766 /* Can't allow write permission if the shm_open() didn't allow them. */
e8c3f781
A
767 if (!(fp->f_flag & FWRITE)) {
768 if (prot & VM_PROT_WRITE) {
769 return EPERM;
770 }
771 max_prot &= ~VM_PROT_WRITE;
1c79356b
A
772 }
773
91447636 774 PSHM_SUBSYS_LOCK();
0a7de745
A
775 pnode = (pshmnode_t *)fp->f_data;
776 if (pnode == NULL) {
91447636 777 PSHM_SUBSYS_UNLOCK();
0a7de745 778 return EINVAL;
91447636 779 }
1c79356b 780
0a7de745
A
781 pinfo = pnode->pinfo;
782 if (pinfo == NULL) {
91447636 783 PSHM_SUBSYS_UNLOCK();
0a7de745 784 return EINVAL;
1c79356b 785 }
0a7de745
A
786
787 if (!(pinfo->pshm_flags & PSHM_ALLOCATED)) {
788 PSHM_SUBSYS_UNLOCK();
789 return EINVAL;
790 }
791
5c9f4661 792 if (user_size > (vm_map_size_t)pinfo->pshm_length) {
91447636 793 PSHM_SUBSYS_UNLOCK();
0a7de745 794 return EINVAL;
1c79356b 795 }
0a7de745 796
5c9f4661
A
797 vm_map_size_t end_pos = 0;
798 if (os_add_overflow(user_size, file_pos, &end_pos)) {
799 PSHM_SUBSYS_UNLOCK();
0a7de745 800 return EINVAL;
5c9f4661
A
801 }
802 if (end_pos > (vm_map_size_t)pinfo->pshm_length) {
91447636 803 PSHM_SUBSYS_UNLOCK();
0a7de745 804 return EINVAL;
1c79356b 805 }
0a7de745
A
806
807 pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs);
808 if (pshmobj == NULL) {
91447636 809 PSHM_SUBSYS_UNLOCK();
0a7de745 810 return EINVAL;
1c79356b
A
811 }
812
2d21ac55 813#if CONFIG_MACF
0a7de745 814 error = mac_posixshm_check_mmap(kauth_cred_get(), &pinfo->pshm_hdr, prot, flags);
2d21ac55
A
815 if (error) {
816 PSHM_SUBSYS_UNLOCK();
0a7de745 817 return error;
2d21ac55
A
818 }
819#endif
0a7de745
A
820 /* Grab an extra reference, so we can drop the lock while mapping. */
821 error = pshm_ref(pinfo);
822 if (error) {
823 PSHM_SUBSYS_UNLOCK();
824 return error;
825 }
91447636
A
826
827 PSHM_SUBSYS_UNLOCK();
1c79356b
A
828 user_map = current_map();
829
0a7de745 830 if (!(flags & MAP_FIXED)) {
91447636 831 alloc_flags = VM_FLAGS_ANYWHERE;
39236c6e 832 user_addr = vm_map_round_page(user_addr,
0a7de745 833 vm_map_page_mask(user_map));
1c79356b 834 } else {
39236c6e 835 if (user_addr != vm_map_round_page(user_addr,
0a7de745
A
836 vm_map_page_mask(user_map))) {
837 error = EINVAL;
838 goto out_deref;
839 }
840
91447636
A
841 /*
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.
846 */
847 alloc_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
1c79356b 848 }
0a7de745 849 docow = false;
1c79356b 850
b0d623f7 851 mapped_size = 0;
5ba3f43e
A
852 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
853 /* reserve the entire space first... */
b0d623f7 854 kret = vm_map_enter_mem_object(user_map,
0a7de745
A
855 &user_addr,
856 user_size,
857 0,
858 alloc_flags,
859 vmk_flags,
860 VM_KERN_MEMORY_NONE,
861 IPC_PORT_NULL,
862 0,
863 false,
864 VM_PROT_NONE,
865 VM_PROT_NONE,
866 VM_INHERIT_NONE);
b0d623f7 867 user_start_addr = user_addr;
1c79356b 868 if (kret != KERN_SUCCESS) {
0a7de745 869 goto out_deref;
1c79356b 870 }
b0d623f7 871
0a7de745
A
872 /* Now overwrite with the real mappings. */
873 for (map_pos = 0, pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs);
874 user_size != 0;
875 map_pos += pshmobj->pshmo_size, pshmobj = SLIST_NEXT(pshmobj, pshmo_next)) {
b0d623f7
A
876 if (pshmobj == NULL) {
877 /* nothing there to map !? */
0a7de745 878 goto out_deref;
b0d623f7
A
879 }
880 if (file_pos >= map_pos + pshmobj->pshmo_size) {
881 continue;
882 }
f427ee49 883 map_size = (vm_map_size_t)(pshmobj->pshmo_size - (file_pos - map_pos));
b0d623f7
A
884 if (map_size > user_size) {
885 map_size = user_size;
886 }
5ba3f43e 887 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
b0d623f7
A
888 kret = vm_map_enter_mem_object(
889 user_map,
890 &user_addr,
891 map_size,
892 0,
893 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
5ba3f43e
A
894 vmk_flags,
895 VM_KERN_MEMORY_NONE,
b0d623f7
A
896 pshmobj->pshmo_memobject,
897 file_pos - map_pos,
898 docow,
899 prot,
e8c3f781 900 max_prot,
b0d623f7 901 VM_INHERIT_SHARE);
0a7de745
A
902 if (kret != KERN_SUCCESS) {
903 goto out_deref;
904 }
b0d623f7
A
905
906 user_addr += map_size;
907 user_size -= map_size;
908 mapped_size += map_size;
909 file_pos += map_size;
910 }
911
91447636 912 PSHM_SUBSYS_LOCK();
b0d623f7 913 pnode->mapp_addr = user_start_addr;
1c79356b 914 pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
91447636 915 PSHM_SUBSYS_UNLOCK();
0a7de745
A
916out_deref:
917 PSHM_SUBSYS_LOCK();
918 pshm_deref(pinfo); /* drop the extra reference we had while mapping. */
919 PSHM_SUBSYS_UNLOCK();
b0d623f7
A
920 if (kret != KERN_SUCCESS) {
921 if (mapped_size != 0) {
922 (void) mach_vm_deallocate(current_map(),
0a7de745
A
923 user_start_addr,
924 mapped_size);
b0d623f7
A
925 }
926 }
927
1c79356b
A
928 switch (kret) {
929 case KERN_SUCCESS:
f427ee49 930 *retval = (user_addr_t)(user_start_addr + pageoff);
0a7de745 931 return 0;
1c79356b
A
932 case KERN_INVALID_ADDRESS:
933 case KERN_NO_SPACE:
0a7de745 934 return ENOMEM;
1c79356b 935 case KERN_PROTECTION_FAILURE:
0a7de745 936 return EACCES;
1c79356b 937 default:
0a7de745 938 return EINVAL;
1c79356b 939 }
1c79356b
A
940}
941
0a7de745
A
942/*
943 * Remove a shared memory region name from the name lookup cache.
944 */
490019cf 945static int
0a7de745 946pshm_unlink_internal(pshm_info_t *pinfo)
490019cf 947{
490019cf
A
948 PSHM_SUBSYS_ASSERT_HELD();
949
0a7de745 950 if (pinfo == NULL) {
490019cf 951 return EINVAL;
0a7de745 952 }
490019cf 953
0a7de745 954 pshm_cache_delete(pinfo);
490019cf
A
955 pinfo->pshm_flags |= PSHM_REMOVED;
956
0a7de745
A
957 /* release the "unlink" reference */
958 pshm_deref(pinfo);
490019cf
A
959
960 return 0;
961}
962
1c79356b 963int
490019cf 964shm_unlink(proc_t p, struct shm_unlink_args *uap, __unused int32_t *retval)
1c79356b 965{
0a7de745
A
966 int error = 0;
967 pshm_info_t *pinfo = NULL;
968 pshm_info_t *name_pinfo = NULL;
1c79356b 969
0a7de745
A
970 /*
971 * Get the name from user args.
972 */
c3c9b80d
A
973 name_pinfo = kheap_alloc(KHEAP_TEMP, sizeof(pshm_info_t),
974 Z_WAITOK | Z_ZERO);
0a7de745
A
975 if (name_pinfo == NULL) {
976 error = ENOSPC;
1c79356b
A
977 goto bad;
978 }
0a7de745
A
979 error = pshm_get_name(name_pinfo, uap->name);
980 if (error != 0) {
1c79356b
A
981 error = EINVAL;
982 goto bad;
983 }
1c79356b 984
91447636 985 PSHM_SUBSYS_LOCK();
0a7de745 986 pinfo = pshm_cache_search(name_pinfo);
1c79356b 987
0a7de745 988 if (pinfo == NULL) {
39236c6e 989 error = ENOENT;
0a7de745 990 goto bad_unlock;
1c79356b 991 }
490019cf 992
2d21ac55 993#if CONFIG_MACF
0a7de745 994 error = mac_posixshm_check_unlink(kauth_cred_get(), &pinfo->pshm_hdr, name_pinfo->pshm_hdr.pshm_name);
2d21ac55 995 if (error) {
0a7de745 996 goto bad_unlock;
2d21ac55
A
997 }
998#endif
1c79356b 999
0a7de745 1000 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid, pinfo->pshm_gid, pinfo->pshm_mode);
91447636 1001
0a7de745
A
1002 /*
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.
91447636 1008 */
0a7de745
A
1009 error = pshm_access(pinfo, FWRITE, kauth_cred_get(), p);
1010 if (error != 0 && pinfo->pshm_uid != kauth_getuid()) {
1011 goto bad_unlock;
316670eb 1012 }
91447636 1013
0a7de745
A
1014 error = pshm_unlink_internal(pinfo);
1015bad_unlock:
490019cf 1016 PSHM_SUBSYS_UNLOCK();
1c79356b 1017bad:
c3c9b80d 1018 kheap_free(KHEAP_TEMP, name_pinfo, sizeof(pshm_info_t));
490019cf 1019 return error;
1c79356b 1020}
1c79356b 1021
0a7de745
A
1022/*
1023 * Add a new reference to a shared memory region.
1024 * Fails if we will overflow the reference counter.
1025 */
91447636 1026static int
0a7de745 1027pshm_ref(pshm_info_t *pinfo)
1c79356b 1028{
0a7de745 1029 PSHM_SUBSYS_ASSERT_HELD();
1c79356b 1030
0a7de745
A
1031 if (pinfo->pshm_usecount == PSHM_MAXCOUNT) {
1032 return EMFILE;
1c79356b 1033 }
0a7de745
A
1034 pinfo->pshm_usecount++;
1035 return 0;
1036}
1037
1038/*
1039 * Dereference a pshm_info_t. Delete the region if
1040 * this was the final reference count.
1041 */
1042static void
1043pshm_deref(pshm_info_t *pinfo)
1044{
1045 pshm_mobj_t *pshmobj;
1046
1047 PSHM_SUBSYS_ASSERT_HELD();
1048 if (pinfo->pshm_usecount == 0) {
1049 panic("negative usecount in pshm_close\n");
1c79356b 1050 }
91447636 1051 pinfo->pshm_usecount--; /* release this fd's reference */
1c79356b 1052
0a7de745 1053 if (pinfo->pshm_usecount == 0) {
b0d623f7 1054#if CONFIG_MACF
0a7de745 1055 mac_posixshm_label_destroy(&pinfo->pshm_hdr);
b0d623f7 1056#endif
91447636 1057 PSHM_SUBSYS_UNLOCK();
0a7de745 1058
91447636 1059 /*
0a7de745 1060 * Release references to any backing objects.
91447636 1061 */
0a7de745
A
1062 while ((pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs)) != NULL) {
1063 SLIST_REMOVE_HEAD(&pinfo->pshm_mobjs, pshmo_next);
b0d623f7 1064 mach_memory_entry_port_release(pshmobj->pshmo_memobject);
c3c9b80d 1065 kheap_free(KM_SHM, pshmobj, sizeof(pshm_mobj_t));
b0d623f7 1066 }
0a7de745
A
1067
1068 /* free the pinfo itself */
c3c9b80d 1069 kheap_free(KM_SHM, pinfo, sizeof(pshm_info_t));
0a7de745 1070
91447636 1071 PSHM_SUBSYS_LOCK();
91447636 1072 }
1c79356b 1073}
9bccf70c 1074
2d21ac55 1075/* vfs_context_t passed to match prototype for struct fileops */
9bccf70c 1076static int
2d21ac55 1077pshm_closefile(struct fileglob *fg, __unused vfs_context_t ctx)
9bccf70c 1078{
0a7de745
A
1079 int error = EINVAL;
1080 pshmnode_t *pnode;
91447636
A
1081
1082 PSHM_SUBSYS_LOCK();
6d2010ae 1083
0a7de745
A
1084 pnode = (pshmnode_t *)fg->fg_data;
1085 if (pnode != NULL) {
1086 error = 0;
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;
6d2010ae 1091 }
6d2010ae
A
1092 }
1093
91447636 1094 PSHM_SUBSYS_UNLOCK();
c3c9b80d 1095 kheap_free(KM_SHM, pnode, sizeof(pshmnode_t));
6d2010ae 1096
0a7de745 1097 return error;
9bccf70c
A
1098}
1099
0c530ab8 1100int
0a7de745 1101fill_pshminfo(pshmnode_t * pshm, struct pshm_info * info)
0c530ab8 1102{
0a7de745 1103 pshm_info_t *pinfo;
2d21ac55 1104 struct vinfo_stat *sb;
0a7de745 1105
0c530ab8 1106 PSHM_SUBSYS_LOCK();
0a7de745 1107 if ((pinfo = pshm->pinfo) == NULL) {
0c530ab8 1108 PSHM_SUBSYS_UNLOCK();
0a7de745 1109 return EINVAL;
0c530ab8
A
1110 }
1111
1112 sb = &info->pshm_stat;
1113
0a7de745 1114 bzero(sb, sizeof(struct vinfo_stat));
2d21ac55
A
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;
0c530ab8
A
1119
1120 info->pshm_mappaddr = pshm->mapp_addr;
0a7de745 1121 bcopy(&pinfo->pshm_hdr.pshm_name[0], &info->pshm_name[0], PSHMNAMLEN + 1);
0c530ab8
A
1122
1123 PSHM_SUBSYS_UNLOCK();
0a7de745 1124 return 0;
0c530ab8
A
1125}
1126
2d21ac55
A
1127#if CONFIG_MACF
1128void
1129pshm_label_associate(struct fileproc *fp, struct vnode *vp, vfs_context_t ctx)
1130{
0a7de745
A
1131 pshmnode_t *pnode;
1132 pshm_info_t *pshm;
0c530ab8 1133
2d21ac55 1134 PSHM_SUBSYS_LOCK();
0a7de745 1135 pnode = (pshmnode_t *)fp->f_data;
2d21ac55
A
1136 if (pnode != NULL) {
1137 pshm = pnode->pinfo;
0a7de745 1138 if (pshm != NULL) {
2d21ac55 1139 mac_posixshm_vnode_label_associate(
0a7de745 1140 vfs_context_ucred(ctx), &pshm->pshm_hdr, pshm->pshm_label,
2d21ac55 1141 vp, vp->v_label);
0a7de745 1142 }
2d21ac55
A
1143 }
1144 PSHM_SUBSYS_UNLOCK();
1145}
1146#endif