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