]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/mach_port.c
xnu-3789.51.2.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_port.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 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.
8f6c56a5 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.
17 *
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
2d21ac55
A
56/*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
1c79356b
A
63/*
64 */
65/*
66 * File: ipc/mach_port.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Exported kernel calls. See mach/mach_port.defs.
71 */
72
73#include <mach_debug.h>
74#include <mach_rt.h>
75
76#include <mach/port.h>
77#include <mach/kern_return.h>
78#include <mach/notify.h>
79#include <mach/mach_param.h>
80#include <mach/vm_param.h>
81#include <mach/vm_prot.h>
82#include <mach/vm_map.h>
83#include <kern/task.h>
84#include <kern/counters.h>
91447636
A
85#include <kern/thread.h>
86#include <kern/kalloc.h>
1c79356b
A
87#include <mach/mach_port_server.h>
88#include <vm/vm_map.h>
89#include <vm/vm_kern.h>
90#include <ipc/ipc_entry.h>
91#include <ipc/ipc_space.h>
92#include <ipc/ipc_object.h>
93#include <ipc/ipc_notify.h>
94#include <ipc/ipc_port.h>
95#include <ipc/ipc_pset.h>
96#include <ipc/ipc_right.h>
97#include <ipc/ipc_kmsg.h>
98#include <kern/misc_protos.h>
2d21ac55
A
99#include <security/mac_mach_internal.h>
100
fe8ab488
A
101#if IMPORTANCE_INHERITANCE
102#include <ipc/ipc_importance.h>
103#endif
1c79356b 104
3e170ce0 105
1c79356b
A
106/*
107 * Forward declarations
108 */
109void mach_port_names_helper(
110 ipc_port_timestamp_t timestamp,
111 ipc_entry_t entry,
112 mach_port_name_t name,
113 mach_port_name_t *names,
114 mach_port_type_t *types,
91447636 115 ipc_entry_num_t *actualp);
1c79356b
A
116
117void mach_port_gst_helper(
118 ipc_pset_t pset,
1c79356b
A
119 ipc_entry_num_t maxnames,
120 mach_port_name_t *names,
121 ipc_entry_num_t *actualp);
122
123
39236c6e
A
124kern_return_t
125mach_port_guard_exception(
126 mach_port_name_t name,
127 uint64_t inguard,
128 uint64_t portguard,
129 unsigned reason);
130
131/* Needs port locked */
132void mach_port_get_status_helper(
133 ipc_port_t port,
134 mach_port_status_t *status);
135
1c79356b
A
136/* Zeroed template of qos flags */
137
138static mach_port_qos_t qos_template;
139
140/*
141 * Routine: mach_port_names_helper
142 * Purpose:
143 * A helper function for mach_port_names.
6d2010ae
A
144 *
145 * Conditions:
146 * Space containing entry is [at least] read-locked.
1c79356b
A
147 */
148
149void
150mach_port_names_helper(
151 ipc_port_timestamp_t timestamp,
152 ipc_entry_t entry,
153 mach_port_name_t name,
154 mach_port_name_t *names,
155 mach_port_type_t *types,
91447636 156 ipc_entry_num_t *actualp)
1c79356b
A
157{
158 ipc_entry_bits_t bits;
159 ipc_port_request_index_t request;
6d2010ae 160 mach_port_type_t type = 0;
1c79356b 161 ipc_entry_num_t actual;
6d2010ae 162 ipc_port_t port;
1c79356b
A
163
164 bits = entry->ie_bits;
165 request = entry->ie_request;
3e170ce0 166 __IGNORE_WCASTALIGN(port = (ipc_port_t) entry->ie_object);
1c79356b 167
6d2010ae
A
168 if (bits & MACH_PORT_TYPE_RECEIVE) {
169 assert(IP_VALID(port));
1c79356b 170
6d2010ae
A
171 if (request != IE_REQ_NONE) {
172 ip_lock(port);
173 assert(ip_active(port));
174 type |= ipc_port_request_type(port, name, request);
175 ip_unlock(port);
176 }
1c79356b 177
6d2010ae
A
178 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
179 mach_port_type_t reqtype;
1c79356b 180
6d2010ae
A
181 assert(IP_VALID(port));
182 ip_lock(port);
1c79356b 183
6d2010ae
A
184 reqtype = (request != IE_REQ_NONE) ?
185 ipc_port_request_type(port, name, request) : 0;
186
187 /*
188 * If the port is alive, or was alive when the mach_port_names
189 * started, then return that fact. Otherwise, pretend we found
190 * a dead name entry.
191 */
192 if (ip_active(port) || IP_TIMESTAMP_ORDER(timestamp, port->ip_timestamp)) {
193 type |= reqtype;
194 } else {
1c79356b
A
195 bits &= ~(IE_BITS_TYPE_MASK);
196 bits |= MACH_PORT_TYPE_DEAD_NAME;
6d2010ae
A
197 /* account for additional reference for dead-name notification */
198 if (reqtype != 0)
1c79356b 199 bits++;
1c79356b 200 }
6d2010ae 201 ip_unlock(port);
1c79356b
A
202 }
203
6d2010ae 204 type |= IE_BITS_TYPE(bits);
1c79356b
A
205
206 actual = *actualp;
207 names[actual] = name;
208 types[actual] = type;
209 *actualp = actual+1;
210}
211
212/*
213 * Routine: mach_port_names [kernel call]
214 * Purpose:
215 * Retrieves a list of the rights present in the space,
216 * along with type information. (Same as returned
217 * by mach_port_type.) The names are returned in
218 * no particular order, but they (and the type info)
219 * are an accurate snapshot of the space.
220 * Conditions:
221 * Nothing locked.
222 * Returns:
223 * KERN_SUCCESS Arrays of names and types returned.
224 * KERN_INVALID_TASK The space is null.
225 * KERN_INVALID_TASK The space is dead.
226 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
227 */
228
229kern_return_t
230mach_port_names(
231 ipc_space_t space,
232 mach_port_name_t **namesp,
233 mach_msg_type_number_t *namesCnt,
234 mach_port_type_t **typesp,
235 mach_msg_type_number_t *typesCnt)
236{
1c79356b
A
237 ipc_entry_t table;
238 ipc_entry_num_t tsize;
239 mach_port_index_t index;
240 ipc_entry_num_t actual; /* this many names */
241 ipc_port_timestamp_t timestamp; /* logical time of this operation */
242 mach_port_name_t *names;
243 mach_port_type_t *types;
244 kern_return_t kr;
245
246 vm_size_t size; /* size of allocated memory */
247 vm_offset_t addr1; /* allocated memory, for names */
248 vm_offset_t addr2; /* allocated memory, for types */
249 vm_map_copy_t memory1; /* copied-in memory, for names */
250 vm_map_copy_t memory2; /* copied-in memory, for types */
251
252 /* safe simplifying assumption */
39037602 253 static_assert(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
1c79356b
A
254
255 if (space == IS_NULL)
256 return KERN_INVALID_TASK;
257
258 size = 0;
259
260 for (;;) {
261 ipc_entry_num_t bound;
262 vm_size_t size_needed;
263
264 is_read_lock(space);
316670eb 265 if (!is_active(space)) {
1c79356b
A
266 is_read_unlock(space);
267 if (size != 0) {
268 kmem_free(ipc_kernel_map, addr1, size);
269 kmem_free(ipc_kernel_map, addr2, size);
270 }
271 return KERN_INVALID_TASK;
272 }
273
274 /* upper bound on number of names in the space */
316670eb 275 bound = space->is_table_size;
39236c6e
A
276 size_needed = vm_map_round_page(
277 (bound * sizeof(mach_port_name_t)),
278 VM_MAP_PAGE_MASK(ipc_kernel_map));
1c79356b
A
279
280 if (size_needed <= size)
281 break;
282
283 is_read_unlock(space);
284
285 if (size != 0) {
286 kmem_free(ipc_kernel_map, addr1, size);
287 kmem_free(ipc_kernel_map, addr2, size);
288 }
289 size = size_needed;
290
3e170ce0 291 kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_IPC));
1c79356b
A
292 if (kr != KERN_SUCCESS)
293 return KERN_RESOURCE_SHORTAGE;
294
3e170ce0 295 kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_IPC));
1c79356b
A
296 if (kr != KERN_SUCCESS) {
297 kmem_free(ipc_kernel_map, addr1, size);
298 return KERN_RESOURCE_SHORTAGE;
299 }
300
301 /* can't fault while we hold locks */
302
39236c6e
A
303 kr = vm_map_wire(
304 ipc_kernel_map,
305 vm_map_trunc_page(addr1,
306 VM_MAP_PAGE_MASK(ipc_kernel_map)),
307 vm_map_round_page(addr1 + size,
308 VM_MAP_PAGE_MASK(ipc_kernel_map)),
3e170ce0 309 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_MEMORY_TAG_MAKE(VM_KERN_MEMORY_IPC),
39236c6e 310 FALSE);
9bccf70c
A
311 if (kr != KERN_SUCCESS) {
312 kmem_free(ipc_kernel_map, addr1, size);
313 kmem_free(ipc_kernel_map, addr2, size);
314 return KERN_RESOURCE_SHORTAGE;
315 }
1c79356b 316
39236c6e
A
317 kr = vm_map_wire(
318 ipc_kernel_map,
319 vm_map_trunc_page(addr2,
320 VM_MAP_PAGE_MASK(ipc_kernel_map)),
321 vm_map_round_page(addr2 + size,
322 VM_MAP_PAGE_MASK(ipc_kernel_map)),
3e170ce0 323 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_MEMORY_TAG_MAKE(VM_KERN_MEMORY_IPC),
39236c6e 324 FALSE);
9bccf70c
A
325 if (kr != KERN_SUCCESS) {
326 kmem_free(ipc_kernel_map, addr1, size);
327 kmem_free(ipc_kernel_map, addr2, size);
328 return KERN_RESOURCE_SHORTAGE;
329 }
330
1c79356b
A
331 }
332 /* space is read-locked and active */
333
334 names = (mach_port_name_t *) addr1;
335 types = (mach_port_type_t *) addr2;
336 actual = 0;
337
338 timestamp = ipc_port_timestamp();
339
340 table = space->is_table;
341 tsize = space->is_table_size;
342
343 for (index = 0; index < tsize; index++) {
344 ipc_entry_t entry = &table[index];
345 ipc_entry_bits_t bits = entry->ie_bits;
346
347 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
348 mach_port_name_t name;
349
350 name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
351 mach_port_names_helper(timestamp, entry, name, names,
91447636 352 types, &actual);
1c79356b
A
353 }
354 }
355
1c79356b
A
356 is_read_unlock(space);
357
358 if (actual == 0) {
359 memory1 = VM_MAP_COPY_NULL;
360 memory2 = VM_MAP_COPY_NULL;
361
362 if (size != 0) {
363 kmem_free(ipc_kernel_map, addr1, size);
364 kmem_free(ipc_kernel_map, addr2, size);
365 }
366 } else {
367 vm_size_t size_used;
368 vm_size_t vm_size_used;
369
370 size_used = actual * sizeof(mach_port_name_t);
39236c6e
A
371 vm_size_used =
372 vm_map_round_page(size_used,
373 VM_MAP_PAGE_MASK(ipc_kernel_map));
1c79356b
A
374
375 /*
376 * Make used memory pageable and get it into
377 * copied-in form. Free any unused memory.
378 */
379
39236c6e
A
380 kr = vm_map_unwire(
381 ipc_kernel_map,
382 vm_map_trunc_page(addr1,
383 VM_MAP_PAGE_MASK(ipc_kernel_map)),
384 vm_map_round_page(addr1 + vm_size_used,
385 VM_MAP_PAGE_MASK(ipc_kernel_map)),
386 FALSE);
1c79356b
A
387 assert(kr == KERN_SUCCESS);
388
39236c6e
A
389 kr = vm_map_unwire(
390 ipc_kernel_map,
391 vm_map_trunc_page(addr2,
392 VM_MAP_PAGE_MASK(ipc_kernel_map)),
393 vm_map_round_page(addr2 + vm_size_used,
394 VM_MAP_PAGE_MASK(ipc_kernel_map)),
395 FALSE);
1c79356b
A
396 assert(kr == KERN_SUCCESS);
397
91447636
A
398 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
399 (vm_map_size_t)size_used, TRUE, &memory1);
1c79356b
A
400 assert(kr == KERN_SUCCESS);
401
91447636
A
402 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
403 (vm_map_size_t)size_used, TRUE, &memory2);
1c79356b
A
404 assert(kr == KERN_SUCCESS);
405
406 if (vm_size_used != size) {
407 kmem_free(ipc_kernel_map,
408 addr1 + vm_size_used, size - vm_size_used);
409 kmem_free(ipc_kernel_map,
410 addr2 + vm_size_used, size - vm_size_used);
411 }
412 }
413
414 *namesp = (mach_port_name_t *) memory1;
415 *namesCnt = actual;
416 *typesp = (mach_port_type_t *) memory2;
417 *typesCnt = actual;
418 return KERN_SUCCESS;
419}
420
421/*
422 * Routine: mach_port_type [kernel call]
423 * Purpose:
424 * Retrieves the type of a right in the space.
425 * The type is a bitwise combination of one or more
426 * of the following type bits:
427 * MACH_PORT_TYPE_SEND
428 * MACH_PORT_TYPE_RECEIVE
429 * MACH_PORT_TYPE_SEND_ONCE
430 * MACH_PORT_TYPE_PORT_SET
431 * MACH_PORT_TYPE_DEAD_NAME
432 * In addition, the following pseudo-type bits may be present:
433 * MACH_PORT_TYPE_DNREQUEST
434 * A dead-name notification is requested.
435 * Conditions:
436 * Nothing locked.
437 * Returns:
438 * KERN_SUCCESS Type is returned.
439 * KERN_INVALID_TASK The space is null.
440 * KERN_INVALID_TASK The space is dead.
441 * KERN_INVALID_NAME The name doesn't denote a right.
442 */
443
444kern_return_t
445mach_port_type(
446 ipc_space_t space,
447 mach_port_name_t name,
448 mach_port_type_t *typep)
449{
450 mach_port_urefs_t urefs;
451 ipc_entry_t entry;
452 kern_return_t kr;
453
454 if (space == IS_NULL)
455 return KERN_INVALID_TASK;
456
457 if (name == MACH_PORT_NULL)
458 return KERN_INVALID_NAME;
459
460 if (name == MACH_PORT_DEAD) {
461 *typep = MACH_PORT_TYPE_DEAD_NAME;
462 return KERN_SUCCESS;
463 }
464
465 kr = ipc_right_lookup_write(space, name, &entry);
466 if (kr != KERN_SUCCESS)
467 return kr;
1c79356b 468
316670eb 469 /* space is write-locked and active */
1c79356b 470 kr = ipc_right_info(space, name, entry, typep, &urefs);
316670eb
A
471 /* space is unlocked */
472
6d2010ae
A
473#if 1
474 /* JMM - workaround rdar://problem/9121297 (CF being too picky on these bits). */
475 *typep &= ~(MACH_PORT_TYPE_SPREQUEST | MACH_PORT_TYPE_SPREQUEST_DELAYED);
476#endif
477
1c79356b
A
478 return kr;
479}
480
481/*
482 * Routine: mach_port_rename [kernel call]
483 * Purpose:
484 * Changes the name denoting a right,
485 * from oname to nname.
486 * Conditions:
487 * Nothing locked.
488 * Returns:
489 * KERN_SUCCESS The right is renamed.
490 * KERN_INVALID_TASK The space is null.
491 * KERN_INVALID_TASK The space is dead.
492 * KERN_INVALID_NAME The oname doesn't denote a right.
493 * KERN_INVALID_VALUE The nname isn't a legal name.
494 * KERN_NAME_EXISTS The nname already denotes a right.
495 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
316670eb
A
496 *
497 * This interface is obsolete and always returns
498 * KERN_NOT_SUPPORTED.
1c79356b
A
499 */
500
501kern_return_t
502mach_port_rename(
316670eb
A
503 __unused ipc_space_t space,
504 __unused mach_port_name_t oname,
505 __unused mach_port_name_t nname)
1c79356b 506{
316670eb 507 return KERN_NOT_SUPPORTED;
1c79356b
A
508}
509
316670eb 510
1c79356b
A
511/*
512 * Routine: mach_port_allocate_name [kernel call]
513 * Purpose:
514 * Allocates a right in a space, using a specific name
515 * for the new right. Possible rights:
516 * MACH_PORT_RIGHT_RECEIVE
517 * MACH_PORT_RIGHT_PORT_SET
518 * MACH_PORT_RIGHT_DEAD_NAME
519 *
520 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
521 * has no extant send or send-once rights and no queued
522 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
523 * and its make-send count is 0. It is not a member of
524 * a port set. It has no registered no-senders or
525 * port-destroyed notification requests.
526 *
527 * A new port set has no members.
528 *
529 * A new dead name has one user reference.
530 * Conditions:
531 * Nothing locked.
532 * Returns:
533 * KERN_SUCCESS The right is allocated.
534 * KERN_INVALID_TASK The space is null.
535 * KERN_INVALID_TASK The space is dead.
536 * KERN_INVALID_VALUE The name isn't a legal name.
537 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
538 * KERN_NAME_EXISTS The name already denotes a right.
539 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
540 *
541 * Restrictions on name allocation: NT bits are reserved by kernel,
542 * must be set on any chosen name. Can't do this at all in kernel
543 * loaded server.
544 */
545
546kern_return_t
547mach_port_allocate_name(
548 ipc_space_t space,
549 mach_port_right_t right,
550 mach_port_name_t name)
551{
552 kern_return_t kr;
553 mach_port_qos_t qos = qos_template;
554
555 qos.name = TRUE;
556
557 if (!MACH_PORT_VALID(name))
558 return KERN_INVALID_VALUE;
559
9bccf70c 560 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
561 &qos, &name);
562 return (kr);
563}
564
565/*
566 * Routine: mach_port_allocate [kernel call]
567 * Purpose:
568 * Allocates a right in a space. Like mach_port_allocate_name,
569 * except that the implementation picks a name for the right.
570 * The name may be any legal name in the space that doesn't
571 * currently denote a right.
572 * Conditions:
573 * Nothing locked.
574 * Returns:
575 * KERN_SUCCESS The right is allocated.
576 * KERN_INVALID_TASK The space is null.
577 * KERN_INVALID_TASK The space is dead.
578 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
579 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
580 * KERN_NO_SPACE No room in space for another right.
581 */
582
583kern_return_t
584mach_port_allocate(
585 ipc_space_t space,
586 mach_port_right_t right,
587 mach_port_name_t *namep)
588{
589 kern_return_t kr;
590 mach_port_qos_t qos = qos_template;
591
9bccf70c 592 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
593 &qos, namep);
594 return (kr);
595}
596
597/*
598 * Routine: mach_port_allocate_qos [kernel call]
599 * Purpose:
600 * Allocates a right, with qos options, in a space. Like
601 * mach_port_allocate_name, except that the implementation
602 * picks a name for the right. The name may be any legal name
603 * in the space that doesn't currently denote a right.
604 * Conditions:
605 * Nothing locked.
606 * Returns:
607 * KERN_SUCCESS The right is allocated.
608 * KERN_INVALID_TASK The space is null.
609 * KERN_INVALID_TASK The space is dead.
610 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
611 * KERN_INVALID_ARGUMENT The qos request was invalid.
612 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
613 * KERN_NO_SPACE No room in space for another right.
614 */
615
616kern_return_t
617mach_port_allocate_qos(
618 ipc_space_t space,
619 mach_port_right_t right,
620 mach_port_qos_t *qosp,
621 mach_port_name_t *namep)
622{
623 kern_return_t kr;
624
9bccf70c 625 if (qosp->name)
1c79356b 626 return KERN_INVALID_ARGUMENT;
9bccf70c 627 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
628 qosp, namep);
629 return (kr);
630}
631
1c79356b
A
632/*
633 * Routine: mach_port_allocate_full [kernel call]
634 * Purpose:
635 * Allocates a right in a space. Supports all of the
636 * special cases, such as specifying a subsystem,
637 * a specific name, a real-time port, etc.
638 * The name may be any legal name in the space that doesn't
639 * currently denote a right.
640 * Conditions:
641 * Nothing locked.
642 * Returns:
643 * KERN_SUCCESS The right is allocated.
644 * KERN_INVALID_TASK The space is null.
645 * KERN_INVALID_TASK The space is dead.
646 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
647 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
648 * KERN_NO_SPACE No room in space for another right.
649 */
650
651kern_return_t
652mach_port_allocate_full(
653 ipc_space_t space,
654 mach_port_right_t right,
9bccf70c 655 mach_port_t proto,
1c79356b
A
656 mach_port_qos_t *qosp,
657 mach_port_name_t *namep)
658{
91447636 659 ipc_kmsg_t kmsg = IKM_NULL;
1c79356b
A
660 kern_return_t kr;
661
662 if (space == IS_NULL)
663 return (KERN_INVALID_TASK);
664
9bccf70c
A
665 if (proto != MACH_PORT_NULL)
666 return (KERN_INVALID_VALUE);
667
1c79356b
A
668 if (qosp->name) {
669 if (!MACH_PORT_VALID (*namep))
670 return (KERN_INVALID_VALUE);
1c79356b
A
671 }
672
1c79356b 673 if (qosp->prealloc) {
8ad349bb
A
674 if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
675 return KERN_RESOURCE_SHORTAGE;
676 } else {
677 mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
b7266188 678
8ad349bb
A
679 if (right != MACH_PORT_RIGHT_RECEIVE)
680 return (KERN_INVALID_VALUE);
b7266188
A
681
682 kmsg = (ipc_kmsg_t)ipc_kmsg_prealloc(size);
8ad349bb
A
683 if (kmsg == IKM_NULL)
684 return (KERN_RESOURCE_SHORTAGE);
685 }
1c79356b
A
686 }
687
688 switch (right) {
689 case MACH_PORT_RIGHT_RECEIVE:
690 {
691 ipc_port_t port;
692
693 if (qosp->name)
694 kr = ipc_port_alloc_name(space, *namep, &port);
695 else
696 kr = ipc_port_alloc(space, namep, &port);
697 if (kr == KERN_SUCCESS) {
91447636 698 if (kmsg != IKM_NULL)
1c79356b
A
699 ipc_kmsg_set_prealloc(kmsg, port);
700
1c79356b
A
701 ip_unlock(port);
702
91447636 703 } else if (kmsg != IKM_NULL)
1c79356b
A
704 ipc_kmsg_free(kmsg);
705 break;
706 }
707
708 case MACH_PORT_RIGHT_PORT_SET:
709 {
710 ipc_pset_t pset;
711
712 if (qosp->name)
713 kr = ipc_pset_alloc_name(space, *namep, &pset);
714 else
715 kr = ipc_pset_alloc(space, namep, &pset);
716 if (kr == KERN_SUCCESS)
717 ips_unlock(pset);
718 break;
719 }
720
721 case MACH_PORT_RIGHT_DEAD_NAME:
722 kr = ipc_object_alloc_dead(space, namep);
723 break;
724
725 default:
726 kr = KERN_INVALID_VALUE;
727 break;
728 }
729
730 return (kr);
731}
732
733/*
734 * Routine: mach_port_destroy [kernel call]
735 * Purpose:
736 * Cleans up and destroys all rights denoted by a name
737 * in a space. The destruction of a receive right
738 * destroys the port, unless a port-destroyed request
739 * has been made for it; the destruction of a port-set right
740 * destroys the port set.
741 * Conditions:
742 * Nothing locked.
743 * Returns:
744 * KERN_SUCCESS The name is destroyed.
745 * KERN_INVALID_TASK The space is null.
746 * KERN_INVALID_TASK The space is dead.
747 * KERN_INVALID_NAME The name doesn't denote a right.
748 */
749
750kern_return_t
751mach_port_destroy(
752 ipc_space_t space,
753 mach_port_name_t name)
754{
755 ipc_entry_t entry;
756 kern_return_t kr;
757
758 if (space == IS_NULL)
759 return KERN_INVALID_TASK;
760
761 if (!MACH_PORT_VALID(name))
762 return KERN_SUCCESS;
763
764 kr = ipc_right_lookup_write(space, name, &entry);
765 if (kr != KERN_SUCCESS)
766 return kr;
767 /* space is write-locked and active */
768
39236c6e 769 kr = ipc_right_destroy(space, name, entry, TRUE, 0); /* unlocks space */
1c79356b
A
770 return kr;
771}
772
773/*
774 * Routine: mach_port_deallocate [kernel call]
775 * Purpose:
776 * Deallocates a user reference from a send right,
777 * send-once right, or a dead-name right. May
778 * deallocate the right, if this is the last uref,
779 * and destroy the name, if it doesn't denote
780 * other rights.
781 * Conditions:
782 * Nothing locked.
783 * Returns:
784 * KERN_SUCCESS The uref is deallocated.
785 * KERN_INVALID_TASK The space is null.
786 * KERN_INVALID_TASK The space is dead.
787 * KERN_INVALID_NAME The name doesn't denote a right.
788 * KERN_INVALID_RIGHT The right isn't correct.
789 */
790
791kern_return_t
792mach_port_deallocate(
793 ipc_space_t space,
794 mach_port_name_t name)
795{
796 ipc_entry_t entry;
797 kern_return_t kr;
798
799 if (space == IS_NULL)
800 return KERN_INVALID_TASK;
801
802 if (!MACH_PORT_VALID(name))
803 return KERN_SUCCESS;
804
805 kr = ipc_right_lookup_write(space, name, &entry);
806 if (kr != KERN_SUCCESS)
807 return kr;
808 /* space is write-locked */
809
810 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
811 return kr;
812}
813
814/*
815 * Routine: mach_port_get_refs [kernel call]
816 * Purpose:
817 * Retrieves the number of user references held by a right.
818 * Receive rights, port-set rights, and send-once rights
819 * always have one user reference. Returns zero if the
820 * name denotes a right, but not the queried right.
821 * Conditions:
822 * Nothing locked.
823 * Returns:
824 * KERN_SUCCESS Number of urefs returned.
825 * KERN_INVALID_TASK The space is null.
826 * KERN_INVALID_TASK The space is dead.
827 * KERN_INVALID_VALUE "right" isn't a legal value.
828 * KERN_INVALID_NAME The name doesn't denote a right.
829 */
830
831kern_return_t
832mach_port_get_refs(
833 ipc_space_t space,
834 mach_port_name_t name,
835 mach_port_right_t right,
836 mach_port_urefs_t *urefsp)
837{
838 mach_port_type_t type;
839 mach_port_urefs_t urefs;
840 ipc_entry_t entry;
841 kern_return_t kr;
842
843 if (space == IS_NULL)
844 return KERN_INVALID_TASK;
845
846 if (right >= MACH_PORT_RIGHT_NUMBER)
847 return KERN_INVALID_VALUE;
848
849 if (!MACH_PORT_VALID(name)) {
850 if (right == MACH_PORT_RIGHT_SEND ||
851 right == MACH_PORT_RIGHT_SEND_ONCE) {
852 *urefsp = 1;
853 return KERN_SUCCESS;
854 }
855 return KERN_INVALID_NAME;
856 }
857
858 kr = ipc_right_lookup_write(space, name, &entry);
859 if (kr != KERN_SUCCESS)
860 return kr;
316670eb 861
1c79356b 862 /* space is write-locked and active */
316670eb
A
863 kr = ipc_right_info(space, name, entry, &type, &urefs);
864 /* space is unlocked */
1c79356b 865
1c79356b 866 if (kr != KERN_SUCCESS)
316670eb 867 return kr;
1c79356b
A
868
869 if (type & MACH_PORT_TYPE(right))
870 switch (right) {
871 case MACH_PORT_RIGHT_SEND_ONCE:
872 assert(urefs == 1);
873 /* fall-through */
874
875 case MACH_PORT_RIGHT_PORT_SET:
876 case MACH_PORT_RIGHT_RECEIVE:
877 *urefsp = 1;
878 break;
879
880 case MACH_PORT_RIGHT_DEAD_NAME:
881 case MACH_PORT_RIGHT_SEND:
882 assert(urefs > 0);
883 *urefsp = urefs;
884 break;
885
886 default:
887 panic("mach_port_get_refs: strange rights");
888 }
889 else
890 *urefsp = 0;
891
892 return kr;
893}
894
895/*
896 * Routine: mach_port_mod_refs
897 * Purpose:
898 * Modifies the number of user references held by a right.
899 * The resulting number of user references must be non-negative.
900 * If it is zero, the right is deallocated. If the name
901 * doesn't denote other rights, it is destroyed.
902 * Conditions:
903 * Nothing locked.
904 * Returns:
905 * KERN_SUCCESS Modified number of urefs.
906 * KERN_INVALID_TASK The space is null.
907 * KERN_INVALID_TASK The space is dead.
908 * KERN_INVALID_VALUE "right" isn't a legal value.
909 * KERN_INVALID_NAME The name doesn't denote a right.
910 * KERN_INVALID_RIGHT Name doesn't denote specified right.
911 * KERN_INVALID_VALUE Impossible modification to urefs.
912 * KERN_UREFS_OVERFLOW Urefs would overflow.
913 */
914
915kern_return_t
916mach_port_mod_refs(
917 ipc_space_t space,
918 mach_port_name_t name,
919 mach_port_right_t right,
920 mach_port_delta_t delta)
921{
922 ipc_entry_t entry;
923 kern_return_t kr;
924
925 if (space == IS_NULL)
926 return KERN_INVALID_TASK;
927
928 if (right >= MACH_PORT_RIGHT_NUMBER)
929 return KERN_INVALID_VALUE;
930
931 if (!MACH_PORT_VALID(name)) {
932 if (right == MACH_PORT_RIGHT_SEND ||
933 right == MACH_PORT_RIGHT_SEND_ONCE)
934 return KERN_SUCCESS;
935 return KERN_INVALID_NAME;
936 }
937
938 kr = ipc_right_lookup_write(space, name, &entry);
939 if (kr != KERN_SUCCESS)
940 return kr;
941 /* space is write-locked and active */
942
943 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
944 return kr;
945}
946
947
39236c6e
A
948/*
949 * Routine: mach_port_peek [kernel call]
950 * Purpose:
951 * Peek at the message queue for the specified receive
952 * right and return info about a message in the queue.
953 *
954 * On input, seqnop points to a sequence number value
955 * to match the message being peeked. If zero is specified
956 * as the seqno, the first message in the queue will be
957 * peeked.
958 *
959 * Only the following trailer types are currently supported:
960 * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
961 *
962 * or'ed with one of these element types:
963 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
964 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
965 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
966 * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
967 *
968 * On input, the value pointed to by trailer_sizep must be
969 * large enough to hold the requested trailer size.
970 *
971 * The message sequence number, id, size, requested trailer info
972 * and requested trailer size are returned in their respective
973 * output parameters upon success.
974 *
975 * Conditions:
976 * Nothing locked.
977 * Returns:
978 * KERN_SUCCESS Matching message found, out parameters set.
979 * KERN_INVALID_TASK The space is null or dead.
980 * KERN_INVALID_NAME The name doesn't denote a right.
981 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
982 * KERN_INVALID_VALUE The input parameter values are out of bounds.
983 * KERN_FAILURE The requested message was not found.
984 */
985
986kern_return_t
987mach_port_peek(
988 ipc_space_t space,
989 mach_port_name_t name,
990 mach_msg_trailer_type_t trailer_type,
991 mach_port_seqno_t *seqnop,
992 mach_msg_size_t *msg_sizep,
993 mach_msg_id_t *msg_idp,
994 mach_msg_trailer_info_t trailer_infop,
995 mach_msg_type_number_t *trailer_sizep)
996{
997 ipc_port_t port;
998 kern_return_t kr;
999 boolean_t found;
1000 mach_msg_max_trailer_t max_trailer;
1001
1002 if (space == IS_NULL)
1003 return KERN_INVALID_TASK;
1004
1005 if (!MACH_PORT_VALID(name))
1006 return KERN_INVALID_RIGHT;
1007
1008 /*
1009 * We don't allow anything greater than the audit trailer - to avoid
1010 * leaking the context pointer and to avoid variable-sized context issues.
1011 */
1012 if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
1013 REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep)
1014 return KERN_INVALID_VALUE;
1015
1016 *trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
1017
1018 kr = ipc_port_translate_receive(space, name, &port);
1019 if (kr != KERN_SUCCESS)
1020 return kr;
1021
1022 /* Port locked and active */
1023
1024 found = ipc_mqueue_peek(&port->ip_messages, seqnop,
39037602 1025 msg_sizep, msg_idp, &max_trailer, NULL);
39236c6e
A
1026 ip_unlock(port);
1027
1028 if (found != TRUE)
1029 return KERN_FAILURE;
1030
1031 max_trailer.msgh_seqno = *seqnop;
1032 memcpy(trailer_infop, &max_trailer, *trailer_sizep);
1033
1034 return KERN_SUCCESS;
1035}
1036
1c79356b
A
1037/*
1038 * Routine: mach_port_set_mscount [kernel call]
1039 * Purpose:
1040 * Changes a receive right's make-send count.
1041 * Conditions:
1042 * Nothing locked.
1043 * Returns:
1044 * KERN_SUCCESS Set make-send count.
1045 * KERN_INVALID_TASK The space is null.
1046 * KERN_INVALID_TASK The space is dead.
1047 * KERN_INVALID_NAME The name doesn't denote a right.
1048 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1049 */
1050
1051kern_return_t
1052mach_port_set_mscount(
1053 ipc_space_t space,
1054 mach_port_name_t name,
1055 mach_port_mscount_t mscount)
1056{
1057 ipc_port_t port;
1058 kern_return_t kr;
1059
1060 if (space == IS_NULL)
1061 return KERN_INVALID_TASK;
1062
1063 if (!MACH_PORT_VALID(name))
1064 return KERN_INVALID_RIGHT;
1065
1066 kr = ipc_port_translate_receive(space, name, &port);
1067 if (kr != KERN_SUCCESS)
1068 return kr;
1069 /* port is locked and active */
1070
1071 ipc_port_set_mscount(port, mscount);
1072
1073 ip_unlock(port);
1074 return KERN_SUCCESS;
1075}
1076
1077/*
1078 * Routine: mach_port_set_seqno [kernel call]
1079 * Purpose:
1080 * Changes a receive right's sequence number.
1081 * Conditions:
1082 * Nothing locked.
1083 * Returns:
1084 * KERN_SUCCESS Set sequence number.
1085 * KERN_INVALID_TASK The space is null.
1086 * KERN_INVALID_TASK The space is dead.
1087 * KERN_INVALID_NAME The name doesn't denote a right.
1088 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1089 */
1090
1091kern_return_t
1092mach_port_set_seqno(
1093 ipc_space_t space,
1094 mach_port_name_t name,
1095 mach_port_seqno_t seqno)
1096{
1097 ipc_port_t port;
1098 kern_return_t kr;
1099
1100 if (space == IS_NULL)
1101 return KERN_INVALID_TASK;
1102
1103 if (!MACH_PORT_VALID(name))
1104 return KERN_INVALID_RIGHT;
1105
1106 kr = ipc_port_translate_receive(space, name, &port);
1107 if (kr != KERN_SUCCESS)
1108 return kr;
1109 /* port is locked and active */
1110
1111 ipc_mqueue_set_seqno(&port->ip_messages, seqno);
1112
1113 ip_unlock(port);
1114 return KERN_SUCCESS;
1115}
1116
b0d623f7
A
1117/*
1118 * Routine: mach_port_get_context [kernel call]
1119 * Purpose:
1120 * Returns a receive right's context pointer.
1121 * Conditions:
1122 * Nothing locked.
1123 * Returns:
1124 * KERN_SUCCESS Set context pointer.
1125 * KERN_INVALID_TASK The space is null.
1126 * KERN_INVALID_TASK The space is dead.
1127 * KERN_INVALID_NAME The name doesn't denote a right.
1128 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1129 */
1130
1131kern_return_t
1132mach_port_get_context(
1133 ipc_space_t space,
1134 mach_port_name_t name,
316670eb 1135 mach_vm_address_t *context)
b0d623f7
A
1136{
1137 ipc_port_t port;
1138 kern_return_t kr;
1139
1140 if (space == IS_NULL)
1141 return KERN_INVALID_TASK;
1142
1143 if (!MACH_PORT_VALID(name))
1144 return KERN_INVALID_RIGHT;
1145
1146 kr = ipc_port_translate_receive(space, name, &port);
1147 if (kr != KERN_SUCCESS)
1148 return kr;
1149
39236c6e
A
1150 /* Port locked and active */
1151
1152 /* For strictly guarded ports, return empty context (which acts as guard) */
1153 if (port->ip_strict_guard)
1154 *context = 0;
1155 else
1156 *context = port->ip_context;
b0d623f7
A
1157
1158 ip_unlock(port);
1159 return KERN_SUCCESS;
1160}
1161
1162
1163/*
1164 * Routine: mach_port_set_context [kernel call]
1165 * Purpose:
1166 * Changes a receive right's context pointer.
1167 * Conditions:
1168 * Nothing locked.
1169 * Returns:
1170 * KERN_SUCCESS Set context pointer.
1171 * KERN_INVALID_TASK The space is null.
1172 * KERN_INVALID_TASK The space is dead.
1173 * KERN_INVALID_NAME The name doesn't denote a right.
1174 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
1175 */
1176
1177kern_return_t
1178mach_port_set_context(
1179 ipc_space_t space,
1180 mach_port_name_t name,
316670eb 1181 mach_vm_address_t context)
b0d623f7
A
1182{
1183 ipc_port_t port;
1184 kern_return_t kr;
1185
1186 if (space == IS_NULL)
1187 return KERN_INVALID_TASK;
1188
1189 if (!MACH_PORT_VALID(name))
1190 return KERN_INVALID_RIGHT;
1191
1192 kr = ipc_port_translate_receive(space, name, &port);
1193 if (kr != KERN_SUCCESS)
1194 return kr;
1195
1196 /* port is locked and active */
39236c6e
A
1197 if(port->ip_strict_guard) {
1198 uint64_t portguard = port->ip_context;
1199 ip_unlock(port);
1200 /* For strictly guarded ports, disallow overwriting context; Raise Exception */
1201 mach_port_guard_exception(name, context, portguard, kGUARD_EXC_SET_CONTEXT);
1202 return KERN_INVALID_ARGUMENT;
1203 }
1204
b0d623f7
A
1205 port->ip_context = context;
1206
1207 ip_unlock(port);
1208 return KERN_SUCCESS;
1209}
1210
1211
1c79356b
A
1212/*
1213 * Routine: mach_port_get_set_status [kernel call]
1214 * Purpose:
1215 * Retrieves a list of members in a port set.
1216 * Returns the space's name for each receive right member.
1217 * Conditions:
1218 * Nothing locked.
1219 * Returns:
1220 * KERN_SUCCESS Retrieved list of members.
1221 * KERN_INVALID_TASK The space is null.
1222 * KERN_INVALID_TASK The space is dead.
1223 * KERN_INVALID_NAME The name doesn't denote a right.
1224 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1225 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1226 */
1227
1228kern_return_t
1229mach_port_get_set_status(
1230 ipc_space_t space,
1231 mach_port_name_t name,
1232 mach_port_name_t **members,
1233 mach_msg_type_number_t *membersCnt)
1234{
1235 ipc_entry_num_t actual; /* this many members */
1236 ipc_entry_num_t maxnames; /* space for this many members */
1237 kern_return_t kr;
1238
1239 vm_size_t size; /* size of allocated memory */
1240 vm_offset_t addr; /* allocated memory */
1241 vm_map_copy_t memory; /* copied-in memory */
1242
1243 if (space == IS_NULL)
1244 return KERN_INVALID_TASK;
1245
1246 if (!MACH_PORT_VALID(name))
1247 return KERN_INVALID_RIGHT;
1248
39236c6e 1249 size = VM_MAP_PAGE_SIZE(ipc_kernel_map); /* initial guess */
1c79356b
A
1250
1251 for (;;) {
1c79356b 1252 mach_port_name_t *names;
39236c6e 1253 ipc_object_t psobj;
1c79356b
A
1254 ipc_pset_t pset;
1255
3e170ce0 1256 kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_IPC));
1c79356b
A
1257 if (kr != KERN_SUCCESS)
1258 return KERN_RESOURCE_SHORTAGE;
1259
1260 /* can't fault while we hold locks */
1261
1262 kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
3e170ce0 1263 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_MEMORY_TAG_MAKE(VM_KERN_MEMORY_IPC), FALSE);
1c79356b
A
1264 assert(kr == KERN_SUCCESS);
1265
39236c6e 1266 kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_PORT_SET, &psobj);
1c79356b
A
1267 if (kr != KERN_SUCCESS) {
1268 kmem_free(ipc_kernel_map, addr, size);
1269 return kr;
1270 }
1c79356b 1271
39236c6e 1272 /* just use a portset reference from here on out */
3e170ce0 1273 __IGNORE_WCASTALIGN(pset = (ipc_pset_t) psobj);
39236c6e
A
1274 ips_reference(pset);
1275 ips_unlock(pset);
1c79356b
A
1276
1277 names = (mach_port_name_t *) addr;
b0d623f7 1278 maxnames = (ipc_entry_num_t)(size / sizeof(mach_port_name_t));
1c79356b 1279
3e170ce0 1280 ipc_mqueue_set_gather_member_names(space, &pset->ips_messages, maxnames, names, &actual);
1c79356b 1281
39236c6e
A
1282 /* release the portset reference */
1283 ips_release(pset);
1c79356b
A
1284
1285 if (actual <= maxnames)
1286 break;
1287
1288 /* didn't have enough memory; allocate more */
1c79356b 1289 kmem_free(ipc_kernel_map, addr, size);
39236c6e
A
1290 size = vm_map_round_page(
1291 (actual * sizeof(mach_port_name_t)),
1292 VM_MAP_PAGE_MASK(ipc_kernel_map)) +
1293 VM_MAP_PAGE_SIZE(ipc_kernel_map);
1c79356b
A
1294 }
1295
1296 if (actual == 0) {
1297 memory = VM_MAP_COPY_NULL;
1298
1299 kmem_free(ipc_kernel_map, addr, size);
1300 } else {
1301 vm_size_t size_used;
1302 vm_size_t vm_size_used;
1303
1304 size_used = actual * sizeof(mach_port_name_t);
39236c6e
A
1305 vm_size_used = vm_map_round_page(
1306 size_used,
1307 VM_MAP_PAGE_MASK(ipc_kernel_map));
1c79356b
A
1308
1309 /*
1310 * Make used memory pageable and get it into
1311 * copied-in form. Free any unused memory.
1312 */
1313
39236c6e
A
1314 kr = vm_map_unwire(
1315 ipc_kernel_map,
1316 vm_map_trunc_page(addr,
1317 VM_MAP_PAGE_MASK(ipc_kernel_map)),
1318 vm_map_round_page(addr + vm_size_used,
1319 VM_MAP_PAGE_MASK(ipc_kernel_map)),
1320 FALSE);
1c79356b
A
1321 assert(kr == KERN_SUCCESS);
1322
91447636
A
1323 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1324 (vm_map_size_t)size_used, TRUE, &memory);
1c79356b
A
1325 assert(kr == KERN_SUCCESS);
1326
1327 if (vm_size_used != size)
1328 kmem_free(ipc_kernel_map,
1329 addr + vm_size_used, size - vm_size_used);
1330 }
1331
1332 *members = (mach_port_name_t *) memory;
1333 *membersCnt = actual;
1334 return KERN_SUCCESS;
1335}
1336
1337/*
1338 * Routine: mach_port_move_member [kernel call]
1339 * Purpose:
1340 * If after is MACH_PORT_NULL, removes member
1341 * from the port set it is in. Otherwise, adds
1342 * member to after, removing it from any set
1343 * it might already be in.
1344 * Conditions:
1345 * Nothing locked.
1346 * Returns:
1347 * KERN_SUCCESS Moved the port.
1348 * KERN_INVALID_TASK The space is null.
1349 * KERN_INVALID_TASK The space is dead.
1350 * KERN_INVALID_NAME Member didn't denote a right.
1351 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1352 * KERN_INVALID_NAME After didn't denote a right.
1353 * KERN_INVALID_RIGHT After didn't denote a port set right.
1354 * KERN_NOT_IN_SET
1355 * After is MACH_PORT_NULL and Member isn't in a port set.
1356 */
1357
1358kern_return_t
1359mach_port_move_member(
1360 ipc_space_t space,
1361 mach_port_name_t member,
1362 mach_port_name_t after)
1363{
1364 ipc_entry_t entry;
1365 ipc_port_t port;
1366 ipc_pset_t nset;
1367 kern_return_t kr;
3e170ce0
A
1368 uint64_t wq_link_id = 0;
1369 uint64_t wq_reserved_prepost = 0;
1c79356b
A
1370
1371 if (space == IS_NULL)
1372 return KERN_INVALID_TASK;
1373
1374 if (!MACH_PORT_VALID(member))
1375 return KERN_INVALID_RIGHT;
1376
3e170ce0 1377 if (after == MACH_PORT_DEAD) {
1c79356b 1378 return KERN_INVALID_RIGHT;
3e170ce0
A
1379 } else if (after == MACH_PORT_NULL) {
1380 wq_link_id = 0;
1381 } else {
1382 /*
1383 * We reserve both a link, and
1384 * enough prepost objects to complete
1385 * the set move atomically - we can't block
1386 * while we're holding the space lock, and
1387 * the ipc_pset_add calls ipc_mqueue_add
1388 * which may have to prepost this port onto
1389 * this set.
1390 */
1391 wq_link_id = waitq_link_reserve(NULL);
1392 wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
39037602 1393 WAITQ_DONT_LOCK);
3e170ce0 1394 }
1c79356b
A
1395
1396 kr = ipc_right_lookup_read(space, member, &entry);
1397 if (kr != KERN_SUCCESS)
316670eb 1398 goto done;
1c79356b
A
1399 /* space is read-locked and active */
1400
1401 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1402 is_read_unlock(space);
316670eb
A
1403 kr = KERN_INVALID_RIGHT;
1404 goto done;
1c79356b
A
1405 }
1406
3e170ce0 1407 __IGNORE_WCASTALIGN(port = (ipc_port_t) entry->ie_object);
1c79356b
A
1408 assert(port != IP_NULL);
1409
1410 if (after == MACH_PORT_NULL)
1411 nset = IPS_NULL;
1412 else {
1413 entry = ipc_entry_lookup(space, after);
1414 if (entry == IE_NULL) {
1415 is_read_unlock(space);
316670eb
A
1416 kr = KERN_INVALID_NAME;
1417 goto done;
1c79356b
A
1418 }
1419
1420 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1421 is_read_unlock(space);
316670eb
A
1422 kr = KERN_INVALID_RIGHT;
1423 goto done;
1c79356b
A
1424 }
1425
3e170ce0 1426 __IGNORE_WCASTALIGN(nset = (ipc_pset_t) entry->ie_object);
1c79356b
A
1427 assert(nset != IPS_NULL);
1428 }
1429 ip_lock(port);
39037602 1430 assert(ip_active(port));
3e170ce0 1431 ipc_pset_remove_from_all(port);
1c79356b
A
1432
1433 if (nset != IPS_NULL) {
1434 ips_lock(nset);
3e170ce0 1435 kr = ipc_pset_add(nset, port, &wq_link_id, &wq_reserved_prepost);
1c79356b
A
1436 ips_unlock(nset);
1437 }
1438 ip_unlock(port);
1439 is_read_unlock(space);
316670eb
A
1440
1441 done:
3e170ce0
A
1442
1443 /*
1444 * on success the ipc_pset_add() will consume the wq_link_id
1445 * value (resetting it to 0), so this function is always safe to call.
1446 */
1447 waitq_link_release(wq_link_id);
1448 waitq_prepost_release_reserve(wq_reserved_prepost);
316670eb 1449
1c79356b
A
1450 return kr;
1451}
1452
1453/*
1454 * Routine: mach_port_request_notification [kernel call]
1455 * Purpose:
1456 * Requests a notification. The caller supplies
1457 * a send-once right for the notification to use,
1458 * and the call returns the previously registered
1459 * send-once right, if any. Possible types:
1460 *
1461 * MACH_NOTIFY_PORT_DESTROYED
1462 * Requests a port-destroyed notification
1463 * for a receive right. Sync should be zero.
1464 * MACH_NOTIFY_NO_SENDERS
1465 * Requests a no-senders notification for a
1466 * receive right. If there are currently no
1467 * senders, sync is less than or equal to the
1468 * current make-send count, and a send-once right
1469 * is supplied, then an immediate no-senders
1470 * notification is generated.
1471 * MACH_NOTIFY_DEAD_NAME
1472 * Requests a dead-name notification for a send
1473 * or receive right. If the name is already a
1474 * dead name, sync is non-zero, and a send-once
1475 * right is supplied, then an immediate dead-name
1476 * notification is generated.
1477 * Conditions:
1478 * Nothing locked.
1479 * Returns:
1480 * KERN_SUCCESS Requested a notification.
1481 * KERN_INVALID_TASK The space is null.
1482 * KERN_INVALID_TASK The space is dead.
1483 * KERN_INVALID_VALUE Bad id value.
1484 * KERN_INVALID_NAME Name doesn't denote a right.
1485 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1486 * KERN_INVALID_CAPABILITY The notify port is dead.
1487 * MACH_NOTIFY_PORT_DESTROYED:
1488 * KERN_INVALID_VALUE Sync isn't zero.
1489 * MACH_NOTIFY_DEAD_NAME:
1490 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1491 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1492 * sync is zero or notify is IP_NULL.
1493 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1494 * generating immediate notif. would overflow urefs.
1495 */
1496
1497kern_return_t
1498mach_port_request_notification(
1499 ipc_space_t space,
1500 mach_port_name_t name,
1501 mach_msg_id_t id,
1502 mach_port_mscount_t sync,
1503 ipc_port_t notify,
1504 ipc_port_t *previousp)
1505{
1506 kern_return_t kr;
1c79356b
A
1507
1508 if (space == IS_NULL)
1509 return KERN_INVALID_TASK;
1510
1511 if (notify == IP_DEAD)
1512 return KERN_INVALID_CAPABILITY;
1513
1514#if NOTYET
1515 /*
1516 * Requesting notifications on RPC ports is an error.
1517 */
91447636
A
1518 {
1519 ipc_port_t port;
1520 ipc_entry_t entry;
1c79356b 1521
91447636
A
1522 kr = ipc_right_lookup_write(space, name, &entry);
1523 if (kr != KERN_SUCCESS)
1524 return kr;
1c79356b 1525
91447636
A
1526 port = (ipc_port_t) entry->ie_object;
1527
1528 if (port->ip_subsystem != NULL) {
1529 is_write_unlock(space);
1530 panic("mach_port_request_notification: on RPC port!!");
1531 return KERN_INVALID_CAPABILITY;
1532 }
1c79356b 1533 is_write_unlock(space);
1c79356b 1534 }
1c79356b
A
1535#endif /* NOTYET */
1536
1537
1538 switch (id) {
1539 case MACH_NOTIFY_PORT_DESTROYED: {
1540 ipc_port_t port, previous;
1541
1542 if (sync != 0)
1543 return KERN_INVALID_VALUE;
1544
1545 if (!MACH_PORT_VALID(name))
1546 return KERN_INVALID_RIGHT;
1547
1548 kr = ipc_port_translate_receive(space, name, &port);
1549 if (kr != KERN_SUCCESS)
1550 return kr;
1551 /* port is locked and active */
1552
1553 ipc_port_pdrequest(port, notify, &previous);
1554 /* port is unlocked */
1555
1556 *previousp = previous;
1557 break;
1558 }
1559
1560 case MACH_NOTIFY_NO_SENDERS: {
1561 ipc_port_t port;
1562
1563 if (!MACH_PORT_VALID(name))
1564 return KERN_INVALID_RIGHT;
1565
1566 kr = ipc_port_translate_receive(space, name, &port);
1567 if (kr != KERN_SUCCESS)
1568 return kr;
1569 /* port is locked and active */
1570
1571 ipc_port_nsrequest(port, sync, notify, previousp);
1572 /* port is unlocked */
1573 break;
1574 }
1575
6d2010ae
A
1576 case MACH_NOTIFY_SEND_POSSIBLE:
1577
1578 if (!MACH_PORT_VALID(name)) {
1579 return KERN_INVALID_ARGUMENT;
1580 }
1581
1582 kr = ipc_right_request_alloc(space, name, sync != 0,
1583 TRUE, notify, previousp);
1584 if (kr != KERN_SUCCESS)
1585 return kr;
1586 break;
1587
1c79356b
A
1588 case MACH_NOTIFY_DEAD_NAME:
1589
1590 if (!MACH_PORT_VALID(name)) {
1591 /*
1592 * Already dead.
1593 * Should do immediate delivery check -
1594 * will do that in the near future.
1595 */
1596 return KERN_INVALID_ARGUMENT;
1597 }
1598
6d2010ae
A
1599 kr = ipc_right_request_alloc(space, name, sync != 0,
1600 FALSE, notify, previousp);
1c79356b
A
1601 if (kr != KERN_SUCCESS)
1602 return kr;
1603 break;
1604
1605 default:
1606 return KERN_INVALID_VALUE;
1607 }
1608
1609 return KERN_SUCCESS;
1610}
1611
1612/*
1613 * Routine: mach_port_insert_right [kernel call]
1614 * Purpose:
1615 * Inserts a right into a space, as if the space
1616 * voluntarily received the right in a message,
1617 * except that the right gets the specified name.
1618 * Conditions:
1619 * Nothing locked.
1620 * Returns:
1621 * KERN_SUCCESS Inserted the right.
1622 * KERN_INVALID_TASK The space is null.
1623 * KERN_INVALID_TASK The space is dead.
1624 * KERN_INVALID_VALUE The name isn't a legal name.
1625 * KERN_NAME_EXISTS The name already denotes a right.
1626 * KERN_INVALID_VALUE Message doesn't carry a port right.
1627 * KERN_INVALID_CAPABILITY Port is null or dead.
1628 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1629 * KERN_RIGHT_EXISTS Space has rights under another name.
1630 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1631 */
1632
1633kern_return_t
1634mach_port_insert_right(
1635 ipc_space_t space,
1636 mach_port_name_t name,
1637 ipc_port_t poly,
1638 mach_msg_type_name_t polyPoly)
1639{
1640 if (space == IS_NULL)
1641 return KERN_INVALID_TASK;
1642
1643 if (!MACH_PORT_VALID(name) ||
1644 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1645 return KERN_INVALID_VALUE;
1646
1647 if (!IO_VALID((ipc_object_t) poly))
1648 return KERN_INVALID_CAPABILITY;
1649
1650 return ipc_object_copyout_name(space, (ipc_object_t) poly,
1651 polyPoly, FALSE, name);
1652}
1653
1654/*
1655 * Routine: mach_port_extract_right [kernel call]
1656 * Purpose:
1657 * Extracts a right from a space, as if the space
1658 * voluntarily sent the right to the caller.
1659 * Conditions:
1660 * Nothing locked.
1661 * Returns:
1662 * KERN_SUCCESS Extracted the right.
1663 * KERN_INVALID_TASK The space is null.
1664 * KERN_INVALID_TASK The space is dead.
1665 * KERN_INVALID_VALUE Requested type isn't a port right.
1666 * KERN_INVALID_NAME Name doesn't denote a right.
1667 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1668 */
1669
1670kern_return_t
1671mach_port_extract_right(
1672 ipc_space_t space,
1673 mach_port_name_t name,
1674 mach_msg_type_name_t msgt_name,
1675 ipc_port_t *poly,
1676 mach_msg_type_name_t *polyPoly)
1677{
1678 kern_return_t kr;
1679
1680 if (space == IS_NULL)
1681 return KERN_INVALID_TASK;
1682
1683 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1684 return KERN_INVALID_VALUE;
1685
1686 if (!MACH_PORT_VALID(name)) {
1687 /*
1688 * really should copy out a dead name, if it is a send or
1689 * send-once right being copied, but instead return an
1690 * error for now.
1691 */
1692 return KERN_INVALID_RIGHT;
1693 }
1694
1695 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1696
1697 if (kr == KERN_SUCCESS)
1698 *polyPoly = ipc_object_copyin_type(msgt_name);
1699 return kr;
1700}
1701
39236c6e
A
1702/*
1703 * Routine: mach_port_get_status_helper [helper]
1704 * Purpose:
1705 * Populates a mach_port_status_t structure with
1706 * port information.
1707 * Conditions:
1708 * Port needs to be locked
1709 * Returns:
1710 * None.
1711 */
1712void mach_port_get_status_helper(
1713 ipc_port_t port,
1714 mach_port_status_t *statusp)
1715{
39236c6e 1716 imq_lock(&port->ip_messages);
3e170ce0
A
1717 /* don't leak set IDs, just indicate that the port is in one or not */
1718 statusp->mps_pset = !!(port->ip_in_pset);
39236c6e
A
1719 statusp->mps_seqno = port->ip_messages.imq_seqno;
1720 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1721 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1722 imq_unlock(&port->ip_messages);
743345f9 1723
39236c6e
A
1724 statusp->mps_mscount = port->ip_mscount;
1725 statusp->mps_sorights = port->ip_sorights;
1726 statusp->mps_srights = port->ip_srights > 0;
1727 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1728 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1729 statusp->mps_flags = 0;
fe8ab488
A
1730 if (port->ip_impdonation) {
1731 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_IMP_DONATION;
1732 if (port->ip_tempowner) {
1733 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TEMPOWNER;
1734 if (IIT_NULL != port->ip_imp_task) {
1735 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_TASKPTR;
1736 }
1737 }
1738 }
1739 if (port->ip_guarded) {
1740 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_GUARDED;
1741 if (port->ip_strict_guard) {
1742 statusp->mps_flags |= MACH_PORT_STATUS_FLAG_STRICT_GUARD;
1743 }
1744 }
39236c6e
A
1745 return;
1746}
1747
1748
1c79356b
A
1749
1750kern_return_t
1751mach_port_get_attributes(
1752 ipc_space_t space,
1753 mach_port_name_t name,
1754 int flavor,
1755 mach_port_info_t info,
1756 mach_msg_type_number_t *count)
1757{
1758 ipc_port_t port;
1759 kern_return_t kr;
1760
1761 if (space == IS_NULL)
1762 return KERN_INVALID_TASK;
1763
1764 switch (flavor) {
1765 case MACH_PORT_LIMITS_INFO: {
1766 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1767
1768 if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1769 return KERN_FAILURE;
1770
1771 if (!MACH_PORT_VALID(name)) {
1772 *count = 0;
1773 break;
1774 }
1775
1776 kr = ipc_port_translate_receive(space, name, &port);
1777 if (kr != KERN_SUCCESS)
1778 return kr;
1779 /* port is locked and active */
1780
1781 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1782 *count = MACH_PORT_LIMITS_INFO_COUNT;
1783 ip_unlock(port);
1784 break;
1785 }
1786
1787 case MACH_PORT_RECEIVE_STATUS: {
39236c6e
A
1788 mach_port_status_t *statusp = (mach_port_status_t *)info;
1789
1790 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1791 return KERN_FAILURE;
1792
1c79356b
A
1793 if (!MACH_PORT_VALID(name))
1794 return KERN_INVALID_RIGHT;
1795
39236c6e
A
1796 kr = ipc_port_translate_receive(space, name, &port);
1797 if (kr != KERN_SUCCESS)
1798 return kr;
1799 /* port is locked and active */
1800 mach_port_get_status_helper(port, statusp);
1801 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1802 ip_unlock(port);
1803 break;
1804 }
1c79356b
A
1805
1806 case MACH_PORT_DNREQUESTS_SIZE: {
1807 ipc_port_request_t table;
1808
1809 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1810 return KERN_FAILURE;
1811
1812 if (!MACH_PORT_VALID(name)) {
1813 *(int *)info = 0;
1814 break;
1815 }
1816
1817 kr = ipc_port_translate_receive(space, name, &port);
1818 if (kr != KERN_SUCCESS)
1819 return kr;
1820 /* port is locked and active */
1821
6d2010ae 1822 table = port->ip_requests;
1c79356b
A
1823 if (table == IPR_NULL)
1824 *(int *)info = 0;
1825 else
1826 *(int *)info = table->ipr_size->its_size;
1827 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1828 ip_unlock(port);
1829 break;
1830 }
1831
39236c6e
A
1832 case MACH_PORT_INFO_EXT: {
1833 mach_port_info_ext_t *mp_info = (mach_port_info_ext_t *)info;
1834 if (*count < MACH_PORT_INFO_EXT_COUNT)
1835 return KERN_FAILURE;
1836
1837 if (!MACH_PORT_VALID(name))
1838 return KERN_INVALID_RIGHT;
1839
1840 kr = ipc_port_translate_receive(space, name, &port);
1841 if (kr != KERN_SUCCESS)
1842 return kr;
1843 /* port is locked and active */
1844 mach_port_get_status_helper(port, &mp_info->mpie_status);
1845 mp_info->mpie_boost_cnt = port->ip_impcount;
1846 *count = MACH_PORT_INFO_EXT_COUNT;
1847 ip_unlock(port);
1848 break;
1849 }
1850
1c79356b
A
1851 default:
1852 return KERN_INVALID_ARGUMENT;
1853 /*NOTREACHED*/
1854 }
1855
1856 return KERN_SUCCESS;
1857}
1858
1859kern_return_t
1860mach_port_set_attributes(
1861 ipc_space_t space,
1862 mach_port_name_t name,
1863 int flavor,
1864 mach_port_info_t info,
1865 mach_msg_type_number_t count)
1866{
1867 ipc_port_t port;
1868 kern_return_t kr;
1869
1870 if (space == IS_NULL)
1871 return KERN_INVALID_TASK;
1872
1873 switch (flavor) {
1874
1875 case MACH_PORT_LIMITS_INFO: {
1876 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1877
1878 if (count < MACH_PORT_LIMITS_INFO_COUNT)
1879 return KERN_FAILURE;
1880
1881 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1882 return KERN_INVALID_VALUE;
1883
1884 if (!MACH_PORT_VALID(name))
1885 return KERN_INVALID_RIGHT;
1886
1887 kr = ipc_port_translate_receive(space, name, &port);
1888 if (kr != KERN_SUCCESS)
1889 return kr;
1890 /* port is locked and active */
1891
1892 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1893 ip_unlock(port);
1894 break;
1895 }
1896 case MACH_PORT_DNREQUESTS_SIZE: {
1897 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1898 return KERN_FAILURE;
1899
1900 if (!MACH_PORT_VALID(name))
1901 return KERN_INVALID_RIGHT;
1902
1903 kr = ipc_port_translate_receive(space, name, &port);
1904 if (kr != KERN_SUCCESS)
1905 return kr;
1906 /* port is locked and active */
1907
6d2010ae 1908 kr = ipc_port_request_grow(port, *(int *)info);
1c79356b
A
1909 if (kr != KERN_SUCCESS)
1910 return kr;
1911 break;
1912 }
39236c6e
A
1913 case MACH_PORT_TEMPOWNER:
1914 if (!MACH_PORT_VALID(name))
1915 return KERN_INVALID_RIGHT;
1916
fe8ab488 1917 ipc_importance_task_t release_imp_task = IIT_NULL;
39236c6e
A
1918 natural_t assertcnt = 0;
1919
1920 kr = ipc_port_translate_receive(space, name, &port);
1921 if (kr != KERN_SUCCESS)
1922 return kr;
39236c6e
A
1923 /* port is locked and active */
1924
fe8ab488
A
1925 /*
1926 * don't allow temp-owner importance donation if user
1927 * associated it with a kobject already (timer, host_notify target).
1928 */
1929 if (is_ipc_kobject(ip_kotype(port))) {
1930 ip_unlock(port);
1931 return KERN_INVALID_ARGUMENT;
1932 }
1933
39236c6e 1934 if (port->ip_tempowner != 0) {
fe8ab488 1935 if (IIT_NULL != port->ip_imp_task) {
39236c6e 1936 release_imp_task = port->ip_imp_task;
fe8ab488 1937 port->ip_imp_task = IIT_NULL;
39236c6e
A
1938 assertcnt = port->ip_impcount;
1939 }
1940 } else {
1941 assertcnt = port->ip_impcount;
1942 }
1943
1944 port->ip_impdonation = 1;
1945 port->ip_tempowner = 1;
1946 ip_unlock(port);
1947
1948#if IMPORTANCE_INHERITANCE
1949 /* drop assertions from previous destination task */
fe8ab488
A
1950 if (release_imp_task != IIT_NULL) {
1951 assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
39236c6e 1952 if (assertcnt > 0)
fe8ab488
A
1953 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1954 ipc_importance_task_release(release_imp_task);
39236c6e 1955 } else if (assertcnt > 0) {
fe8ab488
A
1956 release_imp_task = current_task()->task_imp_base;
1957 if (release_imp_task != IIT_NULL &&
1958 ipc_importance_task_is_any_receiver_type(release_imp_task)) {
1959 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1960 }
39236c6e
A
1961 }
1962#else
fe8ab488
A
1963 if (release_imp_task != IIT_NULL)
1964 ipc_importance_task_release(release_imp_task);
39236c6e
A
1965#endif /* IMPORTANCE_INHERITANCE */
1966
1967 break;
fe8ab488 1968
39236c6e 1969#if IMPORTANCE_INHERITANCE
fe8ab488 1970 case MACH_PORT_DENAP_RECEIVER:
39236c6e
A
1971 case MACH_PORT_IMPORTANCE_RECEIVER:
1972 if (!MACH_PORT_VALID(name))
1973 return KERN_INVALID_RIGHT;
1974
1975 kr = ipc_port_translate_receive(space, name, &port);
1976 if (kr != KERN_SUCCESS)
1977 return kr;
39236c6e 1978
fe8ab488
A
1979 /*
1980 * don't allow importance donation if user associated
1981 * it with a kobject already (timer, host_notify target).
1982 */
1983 if (is_ipc_kobject(ip_kotype(port))) {
1984 ip_unlock(port);
1985 return KERN_INVALID_ARGUMENT;
1986 }
1987
1988 /* port is locked and active */
39236c6e
A
1989 port->ip_impdonation = 1;
1990 ip_unlock(port);
1991
1992 break;
1993#endif /* IMPORTANCE_INHERITANCE */
1994
1c79356b
A
1995 default:
1996 return KERN_INVALID_ARGUMENT;
1997 /*NOTREACHED*/
1998 }
1999 return KERN_SUCCESS;
2000}
2001
2002/*
2003 * Routine: mach_port_insert_member [kernel call]
2004 * Purpose:
2005 * Add the receive right, specified by name, to
2006 * a portset.
2007 * The port cannot already be a member of the set.
2008 * Conditions:
2009 * Nothing locked.
2010 * Returns:
2011 * KERN_SUCCESS Moved the port.
2012 * KERN_INVALID_TASK The space is null.
2013 * KERN_INVALID_TASK The space is dead.
2014 * KERN_INVALID_NAME name didn't denote a right.
2015 * KERN_INVALID_RIGHT name didn't denote a receive right.
2016 * KERN_INVALID_NAME pset_name didn't denote a right.
2017 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
2018 * KERN_ALREADY_IN_SET name was already a member of pset.
2019 */
2020
2021kern_return_t
2022mach_port_insert_member(
2023 ipc_space_t space,
2024 mach_port_name_t name,
2025 mach_port_name_t psname)
2026{
2027 ipc_object_t obj;
2028 ipc_object_t psobj;
2029 kern_return_t kr;
3e170ce0
A
2030 uint64_t wq_link_id;
2031 uint64_t wq_reserved_prepost;
1c79356b
A
2032
2033 if (space == IS_NULL)
2034 return KERN_INVALID_TASK;
2035
2036 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
2037 return KERN_INVALID_RIGHT;
2038
3e170ce0
A
2039 wq_link_id = waitq_link_reserve(NULL);
2040 wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
39037602 2041 WAITQ_DONT_LOCK);
316670eb 2042
1c79356b
A
2043 kr = ipc_object_translate_two(space,
2044 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2045 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2046 if (kr != KERN_SUCCESS)
316670eb 2047 goto done;
1c79356b
A
2048
2049 /* obj and psobj are locked (and were locked in that order) */
2050 assert(psobj != IO_NULL);
2051 assert(obj != IO_NULL);
2052
3e170ce0
A
2053 __IGNORE_WCASTALIGN(kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj,
2054 &wq_link_id, &wq_reserved_prepost));
2055
1c79356b
A
2056 io_unlock(psobj);
2057 io_unlock(obj);
316670eb
A
2058
2059 done:
3e170ce0
A
2060 /* on success, wq_link_id is reset to 0, so this is always safe */
2061 waitq_link_release(wq_link_id);
2062 waitq_prepost_release_reserve(wq_reserved_prepost);
316670eb 2063
1c79356b
A
2064 return kr;
2065}
2066
2067/*
2068 * Routine: mach_port_extract_member [kernel call]
2069 * Purpose:
2070 * Remove a port from one portset that it is a member of.
2071 * Conditions:
2072 * Nothing locked.
2073 * Returns:
2074 * KERN_SUCCESS Moved the port.
2075 * KERN_INVALID_TASK The space is null.
2076 * KERN_INVALID_TASK The space is dead.
2077 * KERN_INVALID_NAME Member didn't denote a right.
2078 * KERN_INVALID_RIGHT Member didn't denote a receive right.
2079 * KERN_INVALID_NAME After didn't denote a right.
2080 * KERN_INVALID_RIGHT After didn't denote a port set right.
2081 * KERN_NOT_IN_SET
2082 * After is MACH_PORT_NULL and Member isn't in a port set.
2083 */
2084
2085kern_return_t
2086mach_port_extract_member(
2087 ipc_space_t space,
2088 mach_port_name_t name,
2089 mach_port_name_t psname)
2090{
1c79356b
A
2091 ipc_object_t psobj;
2092 ipc_object_t obj;
2093 kern_return_t kr;
2094
2095 if (space == IS_NULL)
2096 return KERN_INVALID_TASK;
2097
2098 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
2099 return KERN_INVALID_RIGHT;
2100
2101 kr = ipc_object_translate_two(space,
2102 name, MACH_PORT_RIGHT_RECEIVE, &obj,
2103 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
2104 if (kr != KERN_SUCCESS)
2105 return kr;
2106
2107 /* obj and psobj are both locked (and were locked in that order) */
2108 assert(psobj != IO_NULL);
2109 assert(obj != IO_NULL);
2110
3e170ce0
A
2111 __IGNORE_WCASTALIGN(kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj));
2112
1c79356b
A
2113 io_unlock(psobj);
2114 io_unlock(obj);
316670eb 2115
1c79356b
A
2116 return kr;
2117}
2118
91447636
A
2119/*
2120 * task_set_port_space:
2121 *
2122 * Set port name space of task to specified size.
2123 */
2124kern_return_t
2125task_set_port_space(
2126 ipc_space_t space,
2127 int table_entries)
2128{
2129 kern_return_t kr;
2130
490019cf
A
2131 if (space == IS_NULL)
2132 return KERN_INVALID_TASK;
2133
91447636 2134 is_write_lock(space);
6d2010ae 2135
316670eb 2136 if (!is_active(space)) {
6d2010ae
A
2137 is_write_unlock(space);
2138 return KERN_INVALID_TASK;
2139 }
2140
91447636
A
2141 kr = ipc_entry_grow_table(space, table_entries);
2142 if (kr == KERN_SUCCESS)
2143 is_write_unlock(space);
2144 return kr;
2145}
2146
39236c6e
A
2147/*
2148 * Routine: mach_port_guard_locked [helper routine]
2149 * Purpose:
2150 * Sets a new guard for a locked port.
2151 * Conditions:
2152 * Port Locked.
2153 * Returns:
2154 * KERN_SUCCESS Port Guarded.
2155 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2156 */
2157static kern_return_t
2158mach_port_guard_locked(
2159 ipc_port_t port,
2160 uint64_t guard,
2161 boolean_t strict)
2162{
2163 if (port->ip_context)
2164 return KERN_INVALID_ARGUMENT;
2165
2166 port->ip_context = guard;
2167 port->ip_guarded = 1;
2168 port->ip_strict_guard = (strict)?1:0;
2169 return KERN_SUCCESS;
2170}
2171
2172/*
2173 * Routine: mach_port_unguard_locked [helper routine]
2174 * Purpose:
2175 * Removes guard for a locked port.
2176 * Conditions:
2177 * Port Locked.
2178 * Returns:
2179 * KERN_SUCCESS Port Unguarded.
2180 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2181 * This also raises a EXC_GUARD exception.
2182 */
2183static kern_return_t
2184mach_port_unguard_locked(
2185 ipc_port_t port,
2186 mach_port_name_t name,
2187 uint64_t guard)
2188{
2189 /* Port locked and active */
2190 if (!port->ip_guarded) {
2191 /* Port already unguarded; Raise exception */
2192 mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
2193 return KERN_INVALID_ARGUMENT;
2194 }
2195
2196 if (port->ip_context != guard) {
2197 /* Incorrect guard; Raise exception */
2198 mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
2199 return KERN_INVALID_ARGUMENT;
2200 }
2201
2202 port->ip_context = 0;
2203 port->ip_guarded = port->ip_strict_guard = 0;
2204 return KERN_SUCCESS;
2205}
2206
2207
2208/*
2209 * Routine: mach_port_guard_exception [helper routine]
2210 * Purpose:
2211 * Marks the thread with AST_GUARD for mach port guard violation.
2212 * Also saves exception info in thread structure.
2213 * Conditions:
2214 * None.
2215 * Returns:
2216 * KERN_FAILURE Thread marked with AST_GUARD.
2217 */
2218kern_return_t
2219mach_port_guard_exception(
39037602
A
2220 mach_port_name_t name,
2221 __unused uint64_t inguard,
2222 uint64_t portguard,
2223 unsigned reason)
39236c6e
A
2224{
2225 thread_t t = current_thread();
2226 uint64_t code, subcode;
2227
39236c6e
A
2228 /*
2229 * EXC_GUARD namespace for mach ports
2230 *
2231 *
2232 * Mach Port guards use the exception codes like
2233 *
2234 * code:
2235 * +----------------------------------------------------------------+
2236 * |[63:61] GUARD_TYPE_MACH_PORT | [60:32] flavor | [31:0] port name|
2237 * +----------------------------------------------------------------+
2238 *
2239 * subcode:
2240 * +----------------------------------------------------------------+
2241 * | [63:0] guard value |
2242 * +----------------------------------------------------------------+
2243 */
2244
2245 code = (((uint64_t)GUARD_TYPE_MACH_PORT) << 61) |
2246 (((uint64_t)reason) << 32) |
2247 ((uint64_t)name);
2248 subcode = (uint64_t)(portguard);
2249
2250 t->guard_exc_info.code = code;
2251 t->guard_exc_info.subcode = subcode;
2252
2253 /* Mark thread with AST_GUARD */
2254 thread_guard_violation(t, GUARD_TYPE_MACH_PORT);
2255 return KERN_FAILURE;
2256}
2257
2258
2259/*
2260 * Routine: mach_port_guard_ast
2261 * Purpose:
2262 * Raises an exception for mach port guard violation.
2263 * Conditions:
2264 * None.
2265 * Returns:
2266 * None.
2267 */
2268
2269void
2270mach_port_guard_ast(thread_t t)
2271{
39236c6e 2272 /* Raise an EXC_GUARD exception */
3e170ce0 2273 task_exception_notify(EXC_GUARD, t->guard_exc_info.code, t->guard_exc_info.subcode);
39236c6e
A
2274
2275 /* Terminate task which caused the exception */
3e170ce0 2276 task_bsdtask_kill(current_task());
39236c6e
A
2277 return;
2278}
2279
2280/*
2281 * Routine: mach_port_construct [kernel call]
2282 * Purpose:
2283 * Constructs a mach port with the provided set of options.
2284 * Conditions:
2285 * None.
2286 * Returns:
2287 * KERN_SUCCESS The right is allocated.
2288 * KERN_INVALID_TASK The space is null.
2289 * KERN_INVALID_TASK The space is dead.
2290 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
2291 * KERN_NO_SPACE No room in space for another right.
2292 * KERN_FAILURE Illegal option values requested.
2293 */
2294
2295kern_return_t
2296mach_port_construct(
2297 ipc_space_t space,
2298 mach_port_options_t *options,
2299 uint64_t context,
2300 mach_port_name_t *name)
2301{
2302 kern_return_t kr;
2303 ipc_port_t port;
2304
2305 if (space == IS_NULL)
2306 return (KERN_INVALID_TASK);
2307
2308 /* Allocate a new port in the IPC space */
2309 kr = ipc_port_alloc(space, name, &port);
2310 if (kr != KERN_SUCCESS)
2311 return kr;
2312
2313 /* Port locked and active */
2314 if (options->flags & MPO_CONTEXT_AS_GUARD) {
2315 kr = mach_port_guard_locked(port, (uint64_t) context, (options->flags & MPO_STRICT));
2316 /* A newly allocated and locked port should always be guarded successfully */
2317 assert(kr == KERN_SUCCESS);
2318 } else {
2319 port->ip_context = context;
2320 }
2321
2322 /* Unlock port */
2323 ip_unlock(port);
2324
2325 /* Set port attributes as requested */
2326
2327 if (options->flags & MPO_QLIMIT) {
2328 kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
2329 (mach_port_info_t)&options->mpl, sizeof(options->mpl)/sizeof(int));
2330 if (kr != KERN_SUCCESS)
2331 goto cleanup;
2332 }
2333
2334 if (options->flags & MPO_TEMPOWNER) {
2335 kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
2336 if (kr != KERN_SUCCESS)
2337 goto cleanup;
2338 }
2339
2340 if (options->flags & MPO_IMPORTANCE_RECEIVER) {
2341 kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
2342 if (kr != KERN_SUCCESS)
2343 goto cleanup;
2344 }
2345
fe8ab488
A
2346 if (options->flags & MPO_DENAP_RECEIVER) {
2347 kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
2348 if (kr != KERN_SUCCESS)
2349 goto cleanup;
2350 }
2351
39236c6e
A
2352 if (options->flags & MPO_INSERT_SEND_RIGHT) {
2353 kr = ipc_object_copyin(space, *name, MACH_MSG_TYPE_MAKE_SEND, (ipc_object_t *)&port);
2354 if (kr != KERN_SUCCESS)
2355 goto cleanup;
2356
2357 kr = mach_port_insert_right(space, *name, port, MACH_MSG_TYPE_PORT_SEND);
2358 if (kr != KERN_SUCCESS)
2359 goto cleanup;
2360 }
2361
2362 return KERN_SUCCESS;
2363
2364cleanup:
2365 /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
2366 (void) mach_port_destruct(space, *name, 0, context);
2367 return kr;
2368}
2369
2370/*
2371 * Routine: mach_port_destruct [kernel call]
2372 * Purpose:
2373 * Destroys a mach port with appropriate guard
2374 * Conditions:
2375 * None.
2376 * Returns:
2377 * KERN_SUCCESS The name is destroyed.
2378 * KERN_INVALID_TASK The space is null.
2379 * KERN_INVALID_TASK The space is dead.
2380 * KERN_INVALID_NAME The name doesn't denote a right.
2381 * KERN_INVALID_RIGHT The right isn't correct.
2382 * KERN_INVALID_VALUE The delta for send right is incorrect.
2383 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2384 * This also raises a EXC_GUARD exception.
2385 */
2386
2387kern_return_t
2388mach_port_destruct(
2389 ipc_space_t space,
2390 mach_port_name_t name,
2391 mach_port_delta_t srdelta,
2392 uint64_t guard)
2393{
2394 kern_return_t kr;
2395 ipc_entry_t entry;
2396
2397 if (space == IS_NULL)
2398 return KERN_INVALID_TASK;
2399
2400 if (!MACH_PORT_VALID(name))
2401 return KERN_INVALID_NAME;
2402
2403 /* Remove reference for receive right */
2404 kr = ipc_right_lookup_write(space, name, &entry);
2405 if (kr != KERN_SUCCESS)
2406 return kr;
2407 /* space is write-locked and active */
2408 kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */
2409
2410 return kr;
2411}
2412
2413/*
2414 * Routine: mach_port_guard [kernel call]
2415 * Purpose:
2416 * Guard a mach port with specified guard value.
2417 * The context field of the port is used as the guard.
2418 * Conditions:
2419 * None.
2420 * Returns:
2421 * KERN_SUCCESS The name is destroyed.
2422 * KERN_INVALID_TASK The space is null.
2423 * KERN_INVALID_TASK The space is dead.
2424 * KERN_INVALID_NAME The name doesn't denote a right.
2425 * KERN_INVALID_RIGHT The right isn't correct.
2426 * KERN_INVALID_ARGUMENT Port already contains a context/guard.
2427 */
2428kern_return_t
2429mach_port_guard(
2430 ipc_space_t space,
2431 mach_port_name_t name,
2432 uint64_t guard,
2433 boolean_t strict)
2434{
2435 kern_return_t kr;
2436 ipc_port_t port;
2437
2438 if (space == IS_NULL)
2439 return KERN_INVALID_TASK;
2440
2441 if (!MACH_PORT_VALID(name))
2442 return KERN_INVALID_NAME;
2443
2444 /* Guard can be applied only to receive rights */
2445 kr = ipc_port_translate_receive(space, name, &port);
2446 if (kr != KERN_SUCCESS)
2447 return kr;
2448
2449 /* Port locked and active */
2450 kr = mach_port_guard_locked(port, guard, strict);
2451 ip_unlock(port);
2452
2453 return kr;
2454
2455}
2456
2457/*
2458 * Routine: mach_port_unguard [kernel call]
2459 * Purpose:
2460 * Unguard a mach port with specified guard value.
2461 * Conditions:
2462 * None.
2463 * Returns:
2464 * KERN_SUCCESS The name is destroyed.
2465 * KERN_INVALID_TASK The space is null.
2466 * KERN_INVALID_TASK The space is dead.
2467 * KERN_INVALID_NAME The name doesn't denote a right.
2468 * KERN_INVALID_RIGHT The right isn't correct.
2469 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
2470 * This also raises a EXC_GUARD exception.
2471 */
2472kern_return_t
2473mach_port_unguard(
2474 ipc_space_t space,
2475 mach_port_name_t name,
2476 uint64_t guard)
2477{
2478
2479 kern_return_t kr;
2480 ipc_port_t port;
2481
2482 if (space == IS_NULL)
2483 return KERN_INVALID_TASK;
2484
2485 if (!MACH_PORT_VALID(name))
2486 return KERN_INVALID_NAME;
2487
2488 kr = ipc_port_translate_receive(space, name, &port);
2489 if (kr != KERN_SUCCESS)
2490 return kr;
2491
2492 /* Port locked and active */
2493 kr = mach_port_unguard_locked(port, name, guard);
2494 ip_unlock(port);
2495 return kr;
2496}
2497