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