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