]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/posix_shm.c
xnu-6153.81.5.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>
84#include <mach/memory_object_control.h>
85
91447636
A
86#include <vm/vm_map.h>
87#include <vm/vm_protos.h>
1c79356b 88
91447636 89#define f_flag f_fglob->fg_flag
39236c6e 90#define f_type f_fglob->fg_ops->fo_type
91447636
A
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
1c79356b 96
0a7de745
A
97/*
98 * Used to construct the list of memory objects
99 * assigned to a populated shared memory segment.
100 */
101typedef struct pshm_mobj {
102 void *pshmo_memobject;
103 memory_object_size_t pshmo_size;
104 SLIST_ENTRY(pshm_mobj) pshmo_next;
105} pshm_mobj_t;
b0d623f7 106
0a7de745
A
107/*
108 * This represents an existing Posix shared memory object.
109 *
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.
113 *
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.
119 */
120typedef 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 */
124} pshm_info_t;
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
132
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 */
1c79356b 139
0a7de745
A
140/*
141 * These handle reference counting pshm_info_t structs using pshm_usecount.
142 */
143static int pshm_ref(pshm_info_t *pinfo);
144static void pshm_deref(pshm_info_t *pinfo);
145#define PSHM_MAXCOUNT UINT_MAX
146
147/*
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
153 * one address.
154 */
155typedef struct pshmnode {
156 off_t mapp_addr;
157 pshm_info_t *pinfo;
158} pshmnode_t;
1c79356b 159
1c79356b 160
0a7de745
A
161/* compare function for the red black tree */
162static int
163pshm_compare(pshm_info_t *a, pshm_info_t *b)
164{
165 int cmp = strncmp(a->pshm_hdr.pshm_name, b->pshm_hdr.pshm_name, PSHMNAMLEN + 1);
1c79356b 166
0a7de745
A
167 if (cmp < 0) {
168 return -1;
169 }
170 if (cmp > 0) {
171 return 1;
172 }
173 return 0;
174}
91447636 175
1c79356b 176
0a7de745
A
177/*
178 * shared memory "paths" are stored in a red black tree for lookup
179 */
180u_long pshmnument; /* count of entries allocated in the red black tree */
181RB_HEAD(pshmhead, internal_pshminfo) pshm_head;
182RB_PROTOTYPE(pshmhead, internal_pshminfo, pshm_links, pshm_compare)
183RB_GENERATE(pshmhead, internal_pshminfo, pshm_links, pshm_compare)
184
185/* lookup, add, remove functions */
186static pshm_info_t *pshm_cache_search(pshm_info_t * look);
187static void pshm_cache_add(pshm_info_t *entry);
188static void pshm_cache_delete(pshm_info_t *entry);
189
0a7de745 190static int pshm_closefile(struct fileglob *fg, vfs_context_t ctx);
91447636 191
0a7de745 192static int pshm_access(pshm_info_t *pinfo, int mode, kauth_cred_t cred, proc_t p);
490019cf
A
193int pshm_cache_purge_all(proc_t p);
194
0a7de745 195static int pshm_unlink_internal(pshm_info_t *pinfo);
55e303ae 196
39236c6e 197static const struct fileops pshmops = {
cb323159
A
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,
39236c6e 206};
91447636 207
0a7de745
A
208/*
209 * Everything here is protected by a single mutex.
210 */
91447636
A
211static lck_grp_t *psx_shm_subsys_lck_grp;
212static lck_grp_attr_t *psx_shm_subsys_lck_grp_attr;
213static lck_attr_t *psx_shm_subsys_lck_attr;
214static lck_mtx_t psx_shm_subsys_mutex;
215
216#define PSHM_SUBSYS_LOCK() lck_mtx_lock(& psx_shm_subsys_mutex)
217#define PSHM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_shm_subsys_mutex)
39037602 218#define PSHM_SUBSYS_ASSERT_HELD() LCK_MTX_ASSERT(&psx_shm_subsys_mutex, LCK_MTX_ASSERT_OWNED)
91447636
A
219
220
91447636
A
221__private_extern__ void
222pshm_lock_init( void )
223{
0a7de745 224 psx_shm_subsys_lck_grp_attr = lck_grp_attr_alloc_init();
91447636 225
0a7de745
A
226 psx_shm_subsys_lck_grp =
227 lck_grp_alloc_init("posix shared memory", psx_shm_subsys_lck_grp_attr);
91447636 228
0a7de745
A
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);
91447636 231}
1c79356b 232
1c79356b 233/*
0a7de745 234 * Lookup an entry in the cache. Only the name is used from "look".
1c79356b 235 */
0a7de745
A
236static pshm_info_t *
237pshm_cache_search(pshm_info_t *look)
1c79356b 238{
0a7de745
A
239 PSHM_SUBSYS_ASSERT_HELD();
240 return RB_FIND(pshmhead, &pshm_head, look);
1c79356b
A
241}
242
243/*
0a7de745 244 * Add a new entry to the cache.
1c79356b 245 */
0a7de745
A
246static void
247pshm_cache_add(pshm_info_t *entry)
1c79356b 248{
0a7de745 249 pshm_info_t *conflict;
1c79356b 250
0a7de745
A
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);
1c79356b
A
255 }
256 pshmnument++;
0a7de745 257}
1c79356b 258
0a7de745
A
259/*
260 * Remove the given entry from the red black tree.
261 */
262static void
263pshm_cache_delete(pshm_info_t *entry)
264{
265 PSHM_SUBSYS_ASSERT_HELD();
266 assert(!(entry->pshm_flags & PSHM_REMOVED));
267 RB_REMOVE(pshmhead, &pshm_head, entry);
268 pshmnument--;
1c79356b
A
269}
270
271/*
0a7de745 272 * Initialize the red black tree.
1c79356b
A
273 */
274void
91447636 275pshm_cache_init(void)
1c79356b 276{
0a7de745 277 RB_INIT(&pshm_head);
1c79356b
A
278}
279
280/*
0a7de745
A
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?
1c79356b 285 */
490019cf 286int
0a7de745 287pshm_cache_purge_all(__unused proc_t proc)
1c79356b 288{
0a7de745
A
289 pshm_info_t *p;
290 pshm_info_t *tmp;
490019cf
A
291 int error = 0;
292
0a7de745 293 if (kauth_cred_issuser(kauth_cred_get()) == 0) {
490019cf 294 return EPERM;
0a7de745 295 }
1c79356b 296
490019cf 297 PSHM_SUBSYS_LOCK();
0a7de745
A
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 */
301 goto out;
490019cf 302 }
1c79356b 303 }
490019cf
A
304 assert(pshmnument == 0);
305
306out:
307 PSHM_SUBSYS_UNLOCK();
308
0a7de745
A
309 if (error) {
310 printf("%s: Error %d removing posix shm cache: %ld remain!\n",
311 __func__, error, pshmnument);
312 }
490019cf 313 return error;
1c79356b
A
314}
315
0a7de745
A
316/*
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.
320 */
321static int
322pshm_get_name(pshm_info_t *pinfo, const user_addr_t user_addr)
1c79356b 323{
0a7de745
A
324 size_t bytes_copied = 0;
325 int error;
1c79356b
A
326
327
0a7de745
A
328 error = copyinstr(user_addr, &pinfo->pshm_hdr.pshm_name[0], PSHMNAMLEN + 1, &bytes_copied);
329 if (error != 0) {
330 return error;
331 }
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 */
335 return EINVAL;
336 }
337 AUDIT_ARG(text, &pinfo->pshm_hdr.pshm_name[0]);
338 return 0;
339}
340
341/*
342 * Process a shm_open() system call.
343 */
1c79356b 344int
b0d623f7 345shm_open(proc_t p, struct shm_open_args *uap, int32_t *retval)
1c79356b 346{
0a7de745
A
347 int indx;
348 int error = 0;
349 pshm_info_t *pinfo = NULL;
350 pshm_info_t *new_pinfo = NULL;
351 pshmnode_t *new_pnode = NULL;
b0d623f7 352 struct fileproc *fp = NULL;
0a7de745
A
353 int fmode;
354 int cmode = uap->mode;
355 bool incache = false;
356 bool have_label = false;
1c79356b 357
e5568f75
A
358 AUDIT_ARG(fflags, uap->oflag);
359 AUDIT_ARG(mode, uap->mode);
91447636 360
b0d623f7 361 /*
0a7de745
A
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.
b0d623f7 364 */
0a7de745
A
365 MALLOC(new_pinfo, pshm_info_t *, sizeof(pshm_info_t), M_SHM, M_WAITOK | M_ZERO);
366 if (new_pinfo == NULL) {
b0d623f7
A
367 error = ENOSPC;
368 goto bad;
91447636
A
369 }
370
0a7de745
A
371 /*
372 * Get and check the name.
373 */
374 error = pshm_get_name(new_pinfo, uap->name);
375 if (error != 0) {
1c79356b
A
376 goto bad;
377 }
1c79356b 378
b0d623f7 379 /*
0a7de745 380 * Attempt to allocate a new fp. If unsuccessful, the fp will be
b0d623f7
A
381 * left unmodified (NULL).
382 */
383 error = falloc(p, &fp, &indx, vfs_context_current());
0a7de745 384 if (error) {
b0d623f7 385 goto bad;
0a7de745 386 }
b0d623f7 387
0a7de745 388 cmode &= ALLPERMS;
6d2010ae
A
389
390 fmode = FFLAGS(uap->oflag);
391 if ((fmode & (FREAD | FWRITE)) == 0) {
392 error = EINVAL;
393 goto bad;
394 }
395
b0d623f7 396 /*
0a7de745 397 * Will need a new pnode for the file pointer
b0d623f7 398 */
0a7de745
A
399 MALLOC(new_pnode, pshmnode_t *, sizeof(pshmnode_t), M_SHM, M_WAITOK | M_ZERO);
400 if (new_pnode == NULL) {
b0d623f7
A
401 error = ENOSPC;
402 goto bad;
403 }
404
0a7de745
A
405 /*
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.
408 */
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);
b0d623f7 416#if CONFIG_MACF
0a7de745
A
417 mac_posixshm_label_init(&new_pinfo->pshm_hdr);
418 have_label = true;
419 error = mac_posixshm_check_create(kauth_cred_get(), new_pinfo->pshm_hdr.pshm_name);
420 if (error) {
421 goto bad;
422 }
b0d623f7 423#endif
b0d623f7
A
424 }
425
6d2010ae 426 /*
0a7de745
A
427 * Look up the named shared memory segment in the cache, possibly adding
428 * it for O_CREAT.
6d2010ae 429 */
0a7de745 430 PSHM_SUBSYS_LOCK();
1c79356b 431
0a7de745
A
432 pinfo = pshm_cache_search(new_pinfo);
433 if (pinfo != NULL) {
434 incache = true;
6d2010ae 435
0a7de745
A
436 /* Get a new reference to go with the file pointer.*/
437 error = pshm_ref(pinfo);
438 if (error) {
439 pinfo = NULL; /* so cleanup code doesn't deref */
440 goto bad_locked;
2d21ac55 441 }
2d21ac55 442
0a7de745
A
443 /* can't have pre-existing if O_EXCL */
444 if ((fmode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
445 error = EEXIST;
446 goto bad_locked;
91447636 447 }
6d2010ae 448
0a7de745
A
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))) {
452 error = EINVAL;
453 goto bad_locked;
454 }
455 } else {
456 incache = false;
6d2010ae 457
0a7de745
A
458 /* if it wasn't found, must have O_CREAT */
459 if (!(fmode & O_CREAT)) {
460 error = ENOENT;
b0d623f7 461 goto bad_locked;
1c79356b 462 }
0a7de745
A
463
464 /* Add the new region to the cache. */
465 pinfo = new_pinfo;
466 pshm_cache_add(pinfo);
467 new_pinfo = NULL; /* so that it doesn't get free'd */
1c79356b 468 }
91447636
A
469
470 PSHM_SUBSYS_UNLOCK();
b0d623f7
A
471
472 /*
0a7de745 473 * Check we have permission to access any pre-existing segment
b0d623f7
A
474 */
475 if (incache) {
0a7de745
A
476 if (fmode & O_CREAT) {
477 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
478 pinfo->pshm_gid, pinfo->pshm_mode);
479 }
b0d623f7 480#if CONFIG_MACF
0a7de745
A
481 if ((error = mac_posixshm_check_open(kauth_cred_get(), &pinfo->pshm_hdr, fmode))) {
482 goto bad;
483 }
b0d623f7 484#endif
0a7de745
A
485 if ((error = pshm_access(pinfo, fmode, kauth_cred_get(), p))) {
486 goto bad;
b0d623f7 487 }
0a7de745
A
488 } else {
489#if CONFIG_MACF
490 mac_posixshm_label_associate(kauth_cred_get(), &pinfo->pshm_hdr, pinfo->pshm_hdr.pshm_name);
491#endif
b0d623f7
A
492 }
493
91447636 494 proc_fdlock(p);
1c79356b 495 fp->f_flag = fmode & FMASK;
1c79356b 496 fp->f_ops = &pshmops;
0a7de745 497 new_pnode->pinfo = pinfo;
b0d623f7 498 fp->f_data = (caddr_t)new_pnode;
2d21ac55 499 *fdflags(p, indx) |= UF_EXCLOSE;
6601e61a 500 procfdtbl_releasefd(p, indx, NULL);
91447636
A
501 fp_drop(p, indx, fp, 1);
502 proc_fdunlock(p);
503
1c79356b 504 *retval = indx;
0a7de745
A
505 error = 0;
506 goto done;
2d21ac55 507
b0d623f7
A
508bad_locked:
509 PSHM_SUBSYS_UNLOCK();
510bad:
6d2010ae 511 /*
0a7de745 512 * Drop any new reference to a pre-existing shared memory region.
6d2010ae 513 */
0a7de745 514 if (incache && pinfo != NULL) {
6d2010ae 515 PSHM_SUBSYS_LOCK();
0a7de745 516 pshm_deref(pinfo);
6d2010ae
A
517 PSHM_SUBSYS_UNLOCK();
518 }
519
0a7de745
A
520 /*
521 * Delete any allocated unused data structures.
522 */
523 if (new_pnode != NULL) {
b0d623f7 524 FREE(new_pnode, M_SHM);
0a7de745 525 }
b0d623f7 526
0a7de745 527 if (fp != NULL) {
b0d623f7 528 fp_free(p, indx, fp);
0a7de745 529 }
b0d623f7 530
0a7de745
A
531done:
532 if (new_pinfo != NULL) {
2d21ac55 533#if CONFIG_MACF
0a7de745
A
534 if (have_label) {
535 mac_posixshm_label_destroy(&new_pinfo->pshm_hdr);
536 }
2d21ac55 537#endif
b0d623f7 538 FREE(new_pinfo, M_SHM);
2d21ac55 539 }
0a7de745 540 return error;
1c79356b
A
541}
542
543
0a7de745
A
544/*
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.
547 */
1c79356b 548int
0a7de745
A
549pshm_truncate(
550 __unused proc_t p,
551 struct fileproc *fp,
552 __unused int fd,
553 off_t length,
554 __unused int32_t *retval)
1c79356b 555{
0a7de745
A
556 pshm_info_t *pinfo;
557 pshmnode_t *pnode;
558 kern_return_t kret;
91447636 559 mem_entry_name_port_t mem_object;
0a7de745
A
560 mach_vm_size_t total_size, alloc_size;
561 memory_object_size_t mosize;
562 pshm_mobj_t *pshmobj, *pshmobj_last;
563 vm_map_t user_map;
564 int error;
1c79356b 565
39236c6e
A
566 user_map = current_map();
567
1c79356b 568 if (fp->f_type != DTYPE_PSXSHM) {
0a7de745 569 return EINVAL;
1c79356b 570 }
1c79356b 571
0a7de745
A
572#if 0
573 /*
574 * Can't enforce this yet, some third party tools don't
575 * specify O_RDWR like they ought to. See radar 48692182
576 */
577 /* ftruncate() requires write permission */
578 if (!(fp->f_flag & FWRITE)) {
579 return EINVAL;
580 }
581#endif
1c79356b 582
91447636 583 PSHM_SUBSYS_LOCK();
0a7de745 584 if (((pnode = (pshmnode_t *)fp->f_data)) == NULL) {
91447636 585 PSHM_SUBSYS_UNLOCK();
0a7de745 586 return EINVAL;
91447636 587 }
0a7de745
A
588
589 if ((pinfo = pnode->pinfo) == NULL) {
590 PSHM_SUBSYS_UNLOCK();
591 return EINVAL;
592 }
593
594 /* We only allow one ftruncate() per lifetime of the shm object. */
595 if (pinfo->pshm_flags & (PSHM_ALLOCATING | PSHM_ALLOCATED)) {
91447636 596 PSHM_SUBSYS_UNLOCK();
0a7de745 597 return EINVAL;
1c79356b 598 }
0a7de745 599
2d21ac55 600#if CONFIG_MACF
0a7de745 601 error = mac_posixshm_check_truncate(kauth_cred_get(), &pinfo->pshm_hdr, length);
2d21ac55
A
602 if (error) {
603 PSHM_SUBSYS_UNLOCK();
0a7de745 604 return error;
2d21ac55
A
605 }
606#endif
0a7de745
A
607 /*
608 * Grab an extra reference, so we can drop the lock while allocating and
609 * ensure the objects don't disappear.
610 */
611 error = pshm_ref(pinfo);
612 if (error) {
613 PSHM_SUBSYS_UNLOCK();
614 return error;
615 }
1c79356b 616
0a7de745 617 /* set ALLOCATING, so another truncate can't start */
b0d623f7 618 pinfo->pshm_flags |= PSHM_ALLOCATING;
0a7de745 619 total_size = vm_map_round_page(length, vm_map_page_mask(user_map));
1c79356b 620
0a7de745
A
621 pshmobj_last = NULL;
622 for (alloc_size = 0; alloc_size < total_size; alloc_size += mosize) {
b0d623f7
A
623 PSHM_SUBSYS_UNLOCK();
624
0a7de745 625 /* get a memory object back some of the shared memory */
6d2010ae 626 mosize = MIN(total_size - alloc_size, ANON_MAX_SIZE);
0a7de745
A
627 kret = mach_make_memory_entry_64(VM_MAP_NULL, &mosize, 0,
628 MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT, &mem_object, 0);
b0d623f7 629
0a7de745 630 if (kret != KERN_SUCCESS) {
b0d623f7 631 goto out;
0a7de745 632 }
b0d623f7 633
0a7de745
A
634 /* get a list entry to track the memory object */
635 MALLOC(pshmobj, pshm_mobj_t *, sizeof(pshm_mobj_t), M_SHM, M_WAITOK);
b0d623f7
A
636 if (pshmobj == NULL) {
637 kret = KERN_NO_SPACE;
638 mach_memory_entry_port_release(mem_object);
639 mem_object = NULL;
640 goto out;
641 }
642
643 PSHM_SUBSYS_LOCK();
644
0a7de745
A
645 /* link in the new entry */
646 pshmobj->pshmo_memobject = (void *)mem_object;
6d2010ae 647 pshmobj->pshmo_size = mosize;
0a7de745
A
648 SLIST_NEXT(pshmobj, pshmo_next) = NULL;
649
650 if (pshmobj_last == NULL) {
651 SLIST_FIRST(&pinfo->pshm_mobjs) = pshmobj;
652 } else {
653 SLIST_INSERT_AFTER(pshmobj_last, pshmobj, pshmo_next);
654 }
655 pshmobj_last = pshmobj;
b0d623f7 656 }
0a7de745
A
657
658 /* all done, change flags to ALLOCATED and return success */
3e170ce0
A
659 pinfo->pshm_flags |= PSHM_ALLOCATED;
660 pinfo->pshm_flags &= ~(PSHM_ALLOCATING);
b0d623f7 661 pinfo->pshm_length = total_size;
0a7de745 662 pshm_deref(pinfo); /* drop the "allocating" reference */
91447636 663 PSHM_SUBSYS_UNLOCK();
0a7de745 664 return 0;
1c79356b
A
665
666out:
0a7de745 667 /* clean up any partially allocated objects */
b0d623f7 668 PSHM_SUBSYS_LOCK();
0a7de745
A
669 while ((pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs)) != NULL) {
670 SLIST_REMOVE_HEAD(&pinfo->pshm_mobjs, pshmo_next);
671 PSHM_SUBSYS_UNLOCK();
b0d623f7
A
672 mach_memory_entry_port_release(pshmobj->pshmo_memobject);
673 FREE(pshmobj, M_SHM);
0a7de745 674 PSHM_SUBSYS_LOCK();
b0d623f7 675 }
b0d623f7 676 pinfo->pshm_flags &= ~PSHM_ALLOCATING;
0a7de745 677 pshm_deref(pinfo); /* drop the "allocating" reference */
b0d623f7
A
678 PSHM_SUBSYS_UNLOCK();
679
1c79356b
A
680 switch (kret) {
681 case KERN_INVALID_ADDRESS:
682 case KERN_NO_SPACE:
0a7de745 683 return ENOMEM;
1c79356b 684 case KERN_PROTECTION_FAILURE:
0a7de745 685 return EACCES;
1c79356b 686 default:
0a7de745 687 return EINVAL;
1c79356b
A
688 }
689}
690
691int
0a7de745 692pshm_stat(pshmnode_t *pnode, void *ub, int isstat64)
1c79356b 693{
0a7de745 694 struct stat *sb = (struct stat *)0; /* warning avoidance ; protected by isstat64 */
2d21ac55 695 struct stat64 * sb64 = (struct stat64 *)0; /* warning avoidance ; protected by isstat64 */
0a7de745 696 pshm_info_t *pinfo;
2d21ac55
A
697#if CONFIG_MACF
698 int error;
699#endif
0a7de745 700
91447636 701 PSHM_SUBSYS_LOCK();
0a7de745 702 if ((pinfo = pnode->pinfo) == NULL) {
91447636 703 PSHM_SUBSYS_UNLOCK();
0a7de745 704 return EINVAL;
91447636 705 }
1c79356b 706
2d21ac55 707#if CONFIG_MACF
0a7de745 708 error = mac_posixshm_check_stat(kauth_cred_get(), &pinfo->pshm_hdr);
2d21ac55
A
709 if (error) {
710 PSHM_SUBSYS_UNLOCK();
0a7de745 711 return error;
2d21ac55
A
712 }
713#endif
714
715 if (isstat64 != 0) {
716 sb64 = (struct stat64 *)ub;
0a7de745 717 bzero(sb64, sizeof(struct stat64));
2d21ac55
A
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;
722 } else {
723 sb = (struct stat *)ub;
0a7de745 724 bzero(sb, sizeof(struct stat));
2d21ac55
A
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;
729 }
91447636 730 PSHM_SUBSYS_UNLOCK();
1c79356b 731
0a7de745 732 return 0;
1c79356b
A
733}
734
91447636 735/*
0a7de745 736 * Verify access to a shared memory region.
91447636 737 */
0a7de745
A
738static int
739pshm_access(pshm_info_t *pinfo, int mode, kauth_cred_t cred, __unused proc_t p)
1c79356b 740{
6d2010ae 741 int mode_req = ((mode & FREAD) ? S_IRUSR : 0) |
0a7de745 742 ((mode & FWRITE) ? S_IWUSR : 0);
1c79356b
A
743
744 /* Otherwise, user id 0 always gets access. */
0a7de745
A
745 if (!suser(cred, NULL)) {
746 return 0;
747 }
1c79356b 748
0a7de745 749 return posix_cred_access(cred, pinfo->pshm_uid, pinfo->pshm_gid, pinfo->pshm_mode, mode_req);
1c79356b 750}
9bccf70c 751
1c79356b 752int
0a7de745
A
753pshm_mmap(
754 __unused proc_t p,
755 struct mmap_args *uap,
756 user_addr_t *retval,
757 struct fileproc *fp,
758 off_t pageoff)
1c79356b 759{
0a7de745
A
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;
1c79356b 767 vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
b0d623f7 768 vm_object_offset_t map_pos;
0a7de745
A
769 vm_map_t user_map;
770 int alloc_flags;
5ba3f43e 771 vm_map_kernel_flags_t vmk_flags;
0a7de745
A
772 bool docow;
773 kern_return_t kret = KERN_SUCCESS;
774 pshm_info_t *pinfo;
775 pshmnode_t *pnode;
776 pshm_mobj_t *pshmobj;
777 int error;
778
779 if (user_size == 0) {
780 return 0;
781 }
1c79356b 782
0a7de745
A
783 if (!(flags & MAP_SHARED)) {
784 return EINVAL;
785 }
1c79356b 786
0a7de745 787 /* Can't allow write permission if the shm_open() didn't allow them. */
e8c3f781
A
788 if (!(fp->f_flag & FWRITE)) {
789 if (prot & VM_PROT_WRITE) {
790 return EPERM;
791 }
792 max_prot &= ~VM_PROT_WRITE;
1c79356b
A
793 }
794
91447636 795 PSHM_SUBSYS_LOCK();
0a7de745
A
796 pnode = (pshmnode_t *)fp->f_data;
797 if (pnode == NULL) {
91447636 798 PSHM_SUBSYS_UNLOCK();
0a7de745 799 return EINVAL;
91447636 800 }
1c79356b 801
0a7de745
A
802 pinfo = pnode->pinfo;
803 if (pinfo == NULL) {
91447636 804 PSHM_SUBSYS_UNLOCK();
0a7de745 805 return EINVAL;
1c79356b 806 }
0a7de745
A
807
808 if (!(pinfo->pshm_flags & PSHM_ALLOCATED)) {
809 PSHM_SUBSYS_UNLOCK();
810 return EINVAL;
811 }
812
5c9f4661 813 if (user_size > (vm_map_size_t)pinfo->pshm_length) {
91447636 814 PSHM_SUBSYS_UNLOCK();
0a7de745 815 return EINVAL;
1c79356b 816 }
0a7de745 817
5c9f4661
A
818 vm_map_size_t end_pos = 0;
819 if (os_add_overflow(user_size, file_pos, &end_pos)) {
820 PSHM_SUBSYS_UNLOCK();
0a7de745 821 return EINVAL;
5c9f4661
A
822 }
823 if (end_pos > (vm_map_size_t)pinfo->pshm_length) {
91447636 824 PSHM_SUBSYS_UNLOCK();
0a7de745 825 return EINVAL;
1c79356b 826 }
0a7de745
A
827
828 pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs);
829 if (pshmobj == NULL) {
91447636 830 PSHM_SUBSYS_UNLOCK();
0a7de745 831 return EINVAL;
1c79356b
A
832 }
833
2d21ac55 834#if CONFIG_MACF
0a7de745 835 error = mac_posixshm_check_mmap(kauth_cred_get(), &pinfo->pshm_hdr, prot, flags);
2d21ac55
A
836 if (error) {
837 PSHM_SUBSYS_UNLOCK();
0a7de745 838 return error;
2d21ac55
A
839 }
840#endif
0a7de745
A
841 /* Grab an extra reference, so we can drop the lock while mapping. */
842 error = pshm_ref(pinfo);
843 if (error) {
844 PSHM_SUBSYS_UNLOCK();
845 return error;
846 }
91447636
A
847
848 PSHM_SUBSYS_UNLOCK();
1c79356b
A
849 user_map = current_map();
850
0a7de745 851 if (!(flags & MAP_FIXED)) {
91447636 852 alloc_flags = VM_FLAGS_ANYWHERE;
39236c6e 853 user_addr = vm_map_round_page(user_addr,
0a7de745 854 vm_map_page_mask(user_map));
1c79356b 855 } else {
39236c6e 856 if (user_addr != vm_map_round_page(user_addr,
0a7de745
A
857 vm_map_page_mask(user_map))) {
858 error = EINVAL;
859 goto out_deref;
860 }
861
91447636
A
862 /*
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.
867 */
868 alloc_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
1c79356b 869 }
0a7de745 870 docow = false;
1c79356b 871
b0d623f7 872 mapped_size = 0;
5ba3f43e
A
873 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
874 /* reserve the entire space first... */
b0d623f7 875 kret = vm_map_enter_mem_object(user_map,
0a7de745
A
876 &user_addr,
877 user_size,
878 0,
879 alloc_flags,
880 vmk_flags,
881 VM_KERN_MEMORY_NONE,
882 IPC_PORT_NULL,
883 0,
884 false,
885 VM_PROT_NONE,
886 VM_PROT_NONE,
887 VM_INHERIT_NONE);
b0d623f7 888 user_start_addr = user_addr;
1c79356b 889 if (kret != KERN_SUCCESS) {
0a7de745 890 goto out_deref;
1c79356b 891 }
b0d623f7 892
0a7de745
A
893 /* Now overwrite with the real mappings. */
894 for (map_pos = 0, pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs);
895 user_size != 0;
896 map_pos += pshmobj->pshmo_size, pshmobj = SLIST_NEXT(pshmobj, pshmo_next)) {
b0d623f7
A
897 if (pshmobj == NULL) {
898 /* nothing there to map !? */
0a7de745 899 goto out_deref;
b0d623f7
A
900 }
901 if (file_pos >= map_pos + pshmobj->pshmo_size) {
902 continue;
903 }
904 map_size = pshmobj->pshmo_size - (file_pos - map_pos);
905 if (map_size > user_size) {
906 map_size = user_size;
907 }
5ba3f43e 908 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
b0d623f7
A
909 kret = vm_map_enter_mem_object(
910 user_map,
911 &user_addr,
912 map_size,
913 0,
914 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
5ba3f43e
A
915 vmk_flags,
916 VM_KERN_MEMORY_NONE,
b0d623f7
A
917 pshmobj->pshmo_memobject,
918 file_pos - map_pos,
919 docow,
920 prot,
e8c3f781 921 max_prot,
b0d623f7 922 VM_INHERIT_SHARE);
0a7de745
A
923 if (kret != KERN_SUCCESS) {
924 goto out_deref;
925 }
b0d623f7
A
926
927 user_addr += map_size;
928 user_size -= map_size;
929 mapped_size += map_size;
930 file_pos += map_size;
931 }
932
91447636 933 PSHM_SUBSYS_LOCK();
b0d623f7 934 pnode->mapp_addr = user_start_addr;
1c79356b 935 pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
91447636 936 PSHM_SUBSYS_UNLOCK();
0a7de745
A
937out_deref:
938 PSHM_SUBSYS_LOCK();
939 pshm_deref(pinfo); /* drop the extra reference we had while mapping. */
940 PSHM_SUBSYS_UNLOCK();
b0d623f7
A
941 if (kret != KERN_SUCCESS) {
942 if (mapped_size != 0) {
943 (void) mach_vm_deallocate(current_map(),
0a7de745
A
944 user_start_addr,
945 mapped_size);
b0d623f7
A
946 }
947 }
948
1c79356b
A
949 switch (kret) {
950 case KERN_SUCCESS:
b0d623f7 951 *retval = (user_start_addr + pageoff);
0a7de745 952 return 0;
1c79356b
A
953 case KERN_INVALID_ADDRESS:
954 case KERN_NO_SPACE:
0a7de745 955 return ENOMEM;
1c79356b 956 case KERN_PROTECTION_FAILURE:
0a7de745 957 return EACCES;
1c79356b 958 default:
0a7de745 959 return EINVAL;
1c79356b 960 }
1c79356b
A
961}
962
0a7de745
A
963/*
964 * Remove a shared memory region name from the name lookup cache.
965 */
490019cf 966static int
0a7de745 967pshm_unlink_internal(pshm_info_t *pinfo)
490019cf 968{
490019cf
A
969 PSHM_SUBSYS_ASSERT_HELD();
970
0a7de745 971 if (pinfo == NULL) {
490019cf 972 return EINVAL;
0a7de745 973 }
490019cf 974
0a7de745 975 pshm_cache_delete(pinfo);
490019cf
A
976 pinfo->pshm_flags |= PSHM_REMOVED;
977
0a7de745
A
978 /* release the "unlink" reference */
979 pshm_deref(pinfo);
490019cf
A
980
981 return 0;
982}
983
1c79356b 984int
490019cf 985shm_unlink(proc_t p, struct shm_unlink_args *uap, __unused int32_t *retval)
1c79356b 986{
0a7de745
A
987 int error = 0;
988 pshm_info_t *pinfo = NULL;
989 pshm_info_t *name_pinfo = NULL;
1c79356b 990
0a7de745
A
991 /*
992 * Get the name from user args.
993 */
994 MALLOC(name_pinfo, pshm_info_t *, sizeof(pshm_info_t), M_SHM, M_WAITOK | M_ZERO);
995 if (name_pinfo == NULL) {
996 error = ENOSPC;
1c79356b
A
997 goto bad;
998 }
0a7de745
A
999 error = pshm_get_name(name_pinfo, uap->name);
1000 if (error != 0) {
1c79356b
A
1001 error = EINVAL;
1002 goto bad;
1003 }
1c79356b 1004
91447636 1005 PSHM_SUBSYS_LOCK();
0a7de745 1006 pinfo = pshm_cache_search(name_pinfo);
1c79356b 1007
0a7de745 1008 if (pinfo == NULL) {
39236c6e 1009 error = ENOENT;
0a7de745 1010 goto bad_unlock;
1c79356b 1011 }
490019cf 1012
2d21ac55 1013#if CONFIG_MACF
0a7de745 1014 error = mac_posixshm_check_unlink(kauth_cred_get(), &pinfo->pshm_hdr, name_pinfo->pshm_hdr.pshm_name);
2d21ac55 1015 if (error) {
0a7de745 1016 goto bad_unlock;
2d21ac55
A
1017 }
1018#endif
1c79356b 1019
0a7de745 1020 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid, pinfo->pshm_gid, pinfo->pshm_mode);
91447636 1021
0a7de745
A
1022 /*
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.
91447636 1028 */
0a7de745
A
1029 error = pshm_access(pinfo, FWRITE, kauth_cred_get(), p);
1030 if (error != 0 && pinfo->pshm_uid != kauth_getuid()) {
1031 goto bad_unlock;
316670eb 1032 }
91447636 1033
0a7de745
A
1034 error = pshm_unlink_internal(pinfo);
1035bad_unlock:
490019cf 1036 PSHM_SUBSYS_UNLOCK();
1c79356b 1037bad:
0a7de745
A
1038 if (name_pinfo != NULL) {
1039 FREE(name_pinfo, M_SHM);
1040 }
490019cf 1041 return error;
1c79356b 1042}
1c79356b 1043
0a7de745
A
1044/*
1045 * Add a new reference to a shared memory region.
1046 * Fails if we will overflow the reference counter.
1047 */
91447636 1048static int
0a7de745 1049pshm_ref(pshm_info_t *pinfo)
1c79356b 1050{
0a7de745 1051 PSHM_SUBSYS_ASSERT_HELD();
1c79356b 1052
0a7de745
A
1053 if (pinfo->pshm_usecount == PSHM_MAXCOUNT) {
1054 return EMFILE;
1c79356b 1055 }
0a7de745
A
1056 pinfo->pshm_usecount++;
1057 return 0;
1058}
1059
1060/*
1061 * Dereference a pshm_info_t. Delete the region if
1062 * this was the final reference count.
1063 */
1064static void
1065pshm_deref(pshm_info_t *pinfo)
1066{
1067 pshm_mobj_t *pshmobj;
1068
1069 PSHM_SUBSYS_ASSERT_HELD();
1070 if (pinfo->pshm_usecount == 0) {
1071 panic("negative usecount in pshm_close\n");
1c79356b 1072 }
91447636 1073 pinfo->pshm_usecount--; /* release this fd's reference */
1c79356b 1074
0a7de745 1075 if (pinfo->pshm_usecount == 0) {
b0d623f7 1076#if CONFIG_MACF
0a7de745 1077 mac_posixshm_label_destroy(&pinfo->pshm_hdr);
b0d623f7 1078#endif
91447636 1079 PSHM_SUBSYS_UNLOCK();
0a7de745 1080
91447636 1081 /*
0a7de745 1082 * Release references to any backing objects.
91447636 1083 */
0a7de745
A
1084 while ((pshmobj = SLIST_FIRST(&pinfo->pshm_mobjs)) != NULL) {
1085 SLIST_REMOVE_HEAD(&pinfo->pshm_mobjs, pshmo_next);
b0d623f7 1086 mach_memory_entry_port_release(pshmobj->pshmo_memobject);
b0d623f7
A
1087 FREE(pshmobj, M_SHM);
1088 }
0a7de745
A
1089
1090 /* free the pinfo itself */
1091 FREE(pinfo, M_SHM);
1092
91447636 1093 PSHM_SUBSYS_LOCK();
91447636 1094 }
1c79356b 1095}
9bccf70c 1096
2d21ac55 1097/* vfs_context_t passed to match prototype for struct fileops */
9bccf70c 1098static int
2d21ac55 1099pshm_closefile(struct fileglob *fg, __unused vfs_context_t ctx)
9bccf70c 1100{
0a7de745
A
1101 int error = EINVAL;
1102 pshmnode_t *pnode;
91447636
A
1103
1104 PSHM_SUBSYS_LOCK();
6d2010ae 1105
0a7de745
A
1106 pnode = (pshmnode_t *)fg->fg_data;
1107 if (pnode != NULL) {
1108 error = 0;
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;
6d2010ae 1113 }
6d2010ae
A
1114 }
1115
91447636 1116 PSHM_SUBSYS_UNLOCK();
0a7de745
A
1117 if (pnode != NULL) {
1118 FREE(pnode, M_SHM);
1119 }
6d2010ae 1120
0a7de745 1121 return error;
9bccf70c
A
1122}
1123
0c530ab8 1124int
0a7de745 1125fill_pshminfo(pshmnode_t * pshm, struct pshm_info * info)
0c530ab8 1126{
0a7de745 1127 pshm_info_t *pinfo;
2d21ac55 1128 struct vinfo_stat *sb;
0a7de745 1129
0c530ab8 1130 PSHM_SUBSYS_LOCK();
0a7de745 1131 if ((pinfo = pshm->pinfo) == NULL) {
0c530ab8 1132 PSHM_SUBSYS_UNLOCK();
0a7de745 1133 return EINVAL;
0c530ab8
A
1134 }
1135
1136 sb = &info->pshm_stat;
1137
0a7de745 1138 bzero(sb, sizeof(struct vinfo_stat));
2d21ac55
A
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;
0c530ab8
A
1143
1144 info->pshm_mappaddr = pshm->mapp_addr;
0a7de745 1145 bcopy(&pinfo->pshm_hdr.pshm_name[0], &info->pshm_name[0], PSHMNAMLEN + 1);
0c530ab8
A
1146
1147 PSHM_SUBSYS_UNLOCK();
0a7de745 1148 return 0;
0c530ab8
A
1149}
1150
2d21ac55
A
1151#if CONFIG_MACF
1152void
1153pshm_label_associate(struct fileproc *fp, struct vnode *vp, vfs_context_t ctx)
1154{
0a7de745
A
1155 pshmnode_t *pnode;
1156 pshm_info_t *pshm;
0c530ab8 1157
2d21ac55 1158 PSHM_SUBSYS_LOCK();
0a7de745 1159 pnode = (pshmnode_t *)fp->f_data;
2d21ac55
A
1160 if (pnode != NULL) {
1161 pshm = pnode->pinfo;
0a7de745 1162 if (pshm != NULL) {
2d21ac55 1163 mac_posixshm_vnode_label_associate(
0a7de745 1164 vfs_context_ucred(ctx), &pshm->pshm_hdr, pshm->pshm_label,
2d21ac55 1165 vp, vp->v_label);
0a7de745 1166 }
2d21ac55
A
1167 }
1168 PSHM_SUBSYS_UNLOCK();
1169}
1170#endif