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