]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/mach_port.c
xnu-1228.15.4.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,
117 ipc_port_t port,
118 ipc_entry_num_t maxnames,
119 mach_port_name_t *names,
120 ipc_entry_num_t *actualp);
121
122
123/* Zeroed template of qos flags */
124
125static mach_port_qos_t qos_template;
126
127/*
128 * Routine: mach_port_names_helper
129 * Purpose:
130 * A helper function for mach_port_names.
131 */
132
133void
134mach_port_names_helper(
135 ipc_port_timestamp_t timestamp,
136 ipc_entry_t entry,
137 mach_port_name_t name,
138 mach_port_name_t *names,
139 mach_port_type_t *types,
91447636 140 ipc_entry_num_t *actualp)
1c79356b
A
141{
142 ipc_entry_bits_t bits;
143 ipc_port_request_index_t request;
144 mach_port_type_t type;
145 ipc_entry_num_t actual;
146
147 bits = entry->ie_bits;
148 request = entry->ie_request;
149 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
150 ipc_port_t port;
151 boolean_t died;
152
153 port = (ipc_port_t) entry->ie_object;
154 assert(port != IP_NULL);
155
156 /*
157 * The timestamp serializes mach_port_names
158 * with ipc_port_destroy. If the port died,
159 * but after mach_port_names started, pretend
160 * that it isn't dead.
161 */
162
163 ip_lock(port);
164 died = (!ip_active(port) &&
165 IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
166 ip_unlock(port);
167
168 if (died) {
169 /* pretend this is a dead-name entry */
170
171 bits &= ~(IE_BITS_TYPE_MASK);
172 bits |= MACH_PORT_TYPE_DEAD_NAME;
173 if (request != 0)
174 bits++;
175 request = 0;
176 }
177 }
178
179 type = IE_BITS_TYPE(bits);
180 if (request != 0)
181 type |= MACH_PORT_TYPE_DNREQUEST;
182
183 actual = *actualp;
184 names[actual] = name;
185 types[actual] = type;
186 *actualp = actual+1;
187}
188
189/*
190 * Routine: mach_port_names [kernel call]
191 * Purpose:
192 * Retrieves a list of the rights present in the space,
193 * along with type information. (Same as returned
194 * by mach_port_type.) The names are returned in
195 * no particular order, but they (and the type info)
196 * are an accurate snapshot of the space.
197 * Conditions:
198 * Nothing locked.
199 * Returns:
200 * KERN_SUCCESS Arrays of names and types returned.
201 * KERN_INVALID_TASK The space is null.
202 * KERN_INVALID_TASK The space is dead.
203 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
204 */
205
206kern_return_t
207mach_port_names(
208 ipc_space_t space,
209 mach_port_name_t **namesp,
210 mach_msg_type_number_t *namesCnt,
211 mach_port_type_t **typesp,
212 mach_msg_type_number_t *typesCnt)
213{
1c79356b
A
214 ipc_tree_entry_t tentry;
215 ipc_entry_t table;
216 ipc_entry_num_t tsize;
217 mach_port_index_t index;
218 ipc_entry_num_t actual; /* this many names */
219 ipc_port_timestamp_t timestamp; /* logical time of this operation */
220 mach_port_name_t *names;
221 mach_port_type_t *types;
222 kern_return_t kr;
223
224 vm_size_t size; /* size of allocated memory */
225 vm_offset_t addr1; /* allocated memory, for names */
226 vm_offset_t addr2; /* allocated memory, for types */
227 vm_map_copy_t memory1; /* copied-in memory, for names */
228 vm_map_copy_t memory2; /* copied-in memory, for types */
229
230 /* safe simplifying assumption */
231 assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
232
233 if (space == IS_NULL)
234 return KERN_INVALID_TASK;
235
236 size = 0;
237
238 for (;;) {
239 ipc_entry_num_t bound;
240 vm_size_t size_needed;
241
242 is_read_lock(space);
243 if (!space->is_active) {
244 is_read_unlock(space);
245 if (size != 0) {
246 kmem_free(ipc_kernel_map, addr1, size);
247 kmem_free(ipc_kernel_map, addr2, size);
248 }
249 return KERN_INVALID_TASK;
250 }
251
252 /* upper bound on number of names in the space */
253
254 bound = space->is_table_size + space->is_tree_total;
91447636 255 size_needed = round_page(bound * sizeof(mach_port_name_t));
1c79356b
A
256
257 if (size_needed <= size)
258 break;
259
260 is_read_unlock(space);
261
262 if (size != 0) {
263 kmem_free(ipc_kernel_map, addr1, size);
264 kmem_free(ipc_kernel_map, addr2, size);
265 }
266 size = size_needed;
267
91447636 268 kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE);
1c79356b
A
269 if (kr != KERN_SUCCESS)
270 return KERN_RESOURCE_SHORTAGE;
271
91447636 272 kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE);
1c79356b
A
273 if (kr != KERN_SUCCESS) {
274 kmem_free(ipc_kernel_map, addr1, size);
275 return KERN_RESOURCE_SHORTAGE;
276 }
277
278 /* can't fault while we hold locks */
279
91447636
A
280 kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr1),
281 vm_map_round_page(addr1 + size),
282 VM_PROT_READ|VM_PROT_WRITE, FALSE);
9bccf70c
A
283 if (kr != KERN_SUCCESS) {
284 kmem_free(ipc_kernel_map, addr1, size);
285 kmem_free(ipc_kernel_map, addr2, size);
286 return KERN_RESOURCE_SHORTAGE;
287 }
1c79356b 288
91447636
A
289 kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr2),
290 vm_map_round_page(addr2 + size),
291 VM_PROT_READ|VM_PROT_WRITE, FALSE);
9bccf70c
A
292 if (kr != KERN_SUCCESS) {
293 kmem_free(ipc_kernel_map, addr1, size);
294 kmem_free(ipc_kernel_map, addr2, size);
295 return KERN_RESOURCE_SHORTAGE;
296 }
297
1c79356b
A
298 }
299 /* space is read-locked and active */
300
301 names = (mach_port_name_t *) addr1;
302 types = (mach_port_type_t *) addr2;
303 actual = 0;
304
305 timestamp = ipc_port_timestamp();
306
307 table = space->is_table;
308 tsize = space->is_table_size;
309
310 for (index = 0; index < tsize; index++) {
311 ipc_entry_t entry = &table[index];
312 ipc_entry_bits_t bits = entry->ie_bits;
313
314 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
315 mach_port_name_t name;
316
317 name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
318 mach_port_names_helper(timestamp, entry, name, names,
91447636 319 types, &actual);
1c79356b
A
320 }
321 }
322
323 for (tentry = ipc_splay_traverse_start(&space->is_tree);
324 tentry != ITE_NULL;
325 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
326 ipc_entry_t entry = &tentry->ite_entry;
327 mach_port_name_t name = tentry->ite_name;
328
329 assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
330 mach_port_names_helper(timestamp, entry, name, names,
91447636 331 types, &actual);
1c79356b
A
332 }
333 ipc_splay_traverse_finish(&space->is_tree);
334 is_read_unlock(space);
335
336 if (actual == 0) {
337 memory1 = VM_MAP_COPY_NULL;
338 memory2 = VM_MAP_COPY_NULL;
339
340 if (size != 0) {
341 kmem_free(ipc_kernel_map, addr1, size);
342 kmem_free(ipc_kernel_map, addr2, size);
343 }
344 } else {
345 vm_size_t size_used;
346 vm_size_t vm_size_used;
347
348 size_used = actual * sizeof(mach_port_name_t);
91447636 349 vm_size_used = round_page(size_used);
1c79356b
A
350
351 /*
352 * Make used memory pageable and get it into
353 * copied-in form. Free any unused memory.
354 */
355
91447636
A
356 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr1),
357 vm_map_round_page(addr1 + vm_size_used), FALSE);
1c79356b
A
358 assert(kr == KERN_SUCCESS);
359
91447636
A
360 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr2),
361 vm_map_round_page(addr2 + vm_size_used), FALSE);
1c79356b
A
362 assert(kr == KERN_SUCCESS);
363
91447636
A
364 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
365 (vm_map_size_t)size_used, TRUE, &memory1);
1c79356b
A
366 assert(kr == KERN_SUCCESS);
367
91447636
A
368 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
369 (vm_map_size_t)size_used, TRUE, &memory2);
1c79356b
A
370 assert(kr == KERN_SUCCESS);
371
372 if (vm_size_used != size) {
373 kmem_free(ipc_kernel_map,
374 addr1 + vm_size_used, size - vm_size_used);
375 kmem_free(ipc_kernel_map,
376 addr2 + vm_size_used, size - vm_size_used);
377 }
378 }
379
380 *namesp = (mach_port_name_t *) memory1;
381 *namesCnt = actual;
382 *typesp = (mach_port_type_t *) memory2;
383 *typesCnt = actual;
384 return KERN_SUCCESS;
385}
386
387/*
388 * Routine: mach_port_type [kernel call]
389 * Purpose:
390 * Retrieves the type of a right in the space.
391 * The type is a bitwise combination of one or more
392 * of the following type bits:
393 * MACH_PORT_TYPE_SEND
394 * MACH_PORT_TYPE_RECEIVE
395 * MACH_PORT_TYPE_SEND_ONCE
396 * MACH_PORT_TYPE_PORT_SET
397 * MACH_PORT_TYPE_DEAD_NAME
398 * In addition, the following pseudo-type bits may be present:
399 * MACH_PORT_TYPE_DNREQUEST
400 * A dead-name notification is requested.
401 * Conditions:
402 * Nothing locked.
403 * Returns:
404 * KERN_SUCCESS Type is returned.
405 * KERN_INVALID_TASK The space is null.
406 * KERN_INVALID_TASK The space is dead.
407 * KERN_INVALID_NAME The name doesn't denote a right.
408 */
409
410kern_return_t
411mach_port_type(
412 ipc_space_t space,
413 mach_port_name_t name,
414 mach_port_type_t *typep)
415{
416 mach_port_urefs_t urefs;
417 ipc_entry_t entry;
418 kern_return_t kr;
419
420 if (space == IS_NULL)
421 return KERN_INVALID_TASK;
422
423 if (name == MACH_PORT_NULL)
424 return KERN_INVALID_NAME;
425
426 if (name == MACH_PORT_DEAD) {
427 *typep = MACH_PORT_TYPE_DEAD_NAME;
428 return KERN_SUCCESS;
429 }
430
431 kr = ipc_right_lookup_write(space, name, &entry);
432 if (kr != KERN_SUCCESS)
433 return kr;
434 /* space is write-locked and active */
435
436 kr = ipc_right_info(space, name, entry, typep, &urefs);
437 if (kr == KERN_SUCCESS)
438 is_write_unlock(space);
439 /* space is unlocked */
440 return kr;
441}
442
443/*
444 * Routine: mach_port_rename [kernel call]
445 * Purpose:
446 * Changes the name denoting a right,
447 * from oname to nname.
448 * Conditions:
449 * Nothing locked.
450 * Returns:
451 * KERN_SUCCESS The right is renamed.
452 * KERN_INVALID_TASK The space is null.
453 * KERN_INVALID_TASK The space is dead.
454 * KERN_INVALID_NAME The oname doesn't denote a right.
455 * KERN_INVALID_VALUE The nname isn't a legal name.
456 * KERN_NAME_EXISTS The nname already denotes a right.
457 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
458 */
459
460kern_return_t
461mach_port_rename(
462 ipc_space_t space,
463 mach_port_name_t oname,
464 mach_port_name_t nname)
465{
466 if (space == IS_NULL)
467 return KERN_INVALID_TASK;
468
469 if (!MACH_PORT_VALID(oname))
470 return KERN_INVALID_NAME;
471
472 if (!MACH_PORT_VALID(nname))
473 return KERN_INVALID_VALUE;
474
475 return ipc_object_rename(space, oname, nname);
476}
477
478/*
479 * Routine: mach_port_allocate_name [kernel call]
480 * Purpose:
481 * Allocates a right in a space, using a specific name
482 * for the new right. Possible rights:
483 * MACH_PORT_RIGHT_RECEIVE
484 * MACH_PORT_RIGHT_PORT_SET
485 * MACH_PORT_RIGHT_DEAD_NAME
486 *
487 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
488 * has no extant send or send-once rights and no queued
489 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
490 * and its make-send count is 0. It is not a member of
491 * a port set. It has no registered no-senders or
492 * port-destroyed notification requests.
493 *
494 * A new port set has no members.
495 *
496 * A new dead name has one user reference.
497 * Conditions:
498 * Nothing locked.
499 * Returns:
500 * KERN_SUCCESS The right is allocated.
501 * KERN_INVALID_TASK The space is null.
502 * KERN_INVALID_TASK The space is dead.
503 * KERN_INVALID_VALUE The name isn't a legal name.
504 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
505 * KERN_NAME_EXISTS The name already denotes a right.
506 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
507 *
508 * Restrictions on name allocation: NT bits are reserved by kernel,
509 * must be set on any chosen name. Can't do this at all in kernel
510 * loaded server.
511 */
512
513kern_return_t
514mach_port_allocate_name(
515 ipc_space_t space,
516 mach_port_right_t right,
517 mach_port_name_t name)
518{
519 kern_return_t kr;
520 mach_port_qos_t qos = qos_template;
521
522 qos.name = TRUE;
523
524 if (!MACH_PORT_VALID(name))
525 return KERN_INVALID_VALUE;
526
9bccf70c 527 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
528 &qos, &name);
529 return (kr);
530}
531
532/*
533 * Routine: mach_port_allocate [kernel call]
534 * Purpose:
535 * Allocates a right in a space. Like mach_port_allocate_name,
536 * except that the implementation picks a name for the right.
537 * The name may be any legal name in the space that doesn't
538 * currently denote a right.
539 * Conditions:
540 * Nothing locked.
541 * Returns:
542 * KERN_SUCCESS The right is allocated.
543 * KERN_INVALID_TASK The space is null.
544 * KERN_INVALID_TASK The space is dead.
545 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
546 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
547 * KERN_NO_SPACE No room in space for another right.
548 */
549
550kern_return_t
551mach_port_allocate(
552 ipc_space_t space,
553 mach_port_right_t right,
554 mach_port_name_t *namep)
555{
556 kern_return_t kr;
557 mach_port_qos_t qos = qos_template;
558
9bccf70c 559 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
560 &qos, namep);
561 return (kr);
562}
563
564/*
565 * Routine: mach_port_allocate_qos [kernel call]
566 * Purpose:
567 * Allocates a right, with qos options, in a space. Like
568 * mach_port_allocate_name, except that the implementation
569 * picks a name for the right. The name may be any legal name
570 * in the space that doesn't currently denote a right.
571 * Conditions:
572 * Nothing locked.
573 * Returns:
574 * KERN_SUCCESS The right is allocated.
575 * KERN_INVALID_TASK The space is null.
576 * KERN_INVALID_TASK The space is dead.
577 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
578 * KERN_INVALID_ARGUMENT The qos request was invalid.
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_qos(
585 ipc_space_t space,
586 mach_port_right_t right,
587 mach_port_qos_t *qosp,
588 mach_port_name_t *namep)
589{
590 kern_return_t kr;
591
9bccf70c 592 if (qosp->name)
1c79356b 593 return KERN_INVALID_ARGUMENT;
9bccf70c 594 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
1c79356b
A
595 qosp, namep);
596 return (kr);
597}
598
1c79356b
A
599/*
600 * Routine: mach_port_allocate_full [kernel call]
601 * Purpose:
602 * Allocates a right in a space. Supports all of the
603 * special cases, such as specifying a subsystem,
604 * a specific name, a real-time port, etc.
605 * The name may be any legal name in the space that doesn't
606 * currently denote a right.
607 * Conditions:
608 * Nothing locked.
609 * Returns:
610 * KERN_SUCCESS The right is allocated.
611 * KERN_INVALID_TASK The space is null.
612 * KERN_INVALID_TASK The space is dead.
613 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
614 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
615 * KERN_NO_SPACE No room in space for another right.
616 */
617
618kern_return_t
619mach_port_allocate_full(
620 ipc_space_t space,
621 mach_port_right_t right,
9bccf70c 622 mach_port_t proto,
1c79356b
A
623 mach_port_qos_t *qosp,
624 mach_port_name_t *namep)
625{
91447636 626 ipc_kmsg_t kmsg = IKM_NULL;
1c79356b
A
627 kern_return_t kr;
628
629 if (space == IS_NULL)
630 return (KERN_INVALID_TASK);
631
9bccf70c
A
632 if (proto != MACH_PORT_NULL)
633 return (KERN_INVALID_VALUE);
634
1c79356b
A
635 if (qosp->name) {
636 if (!MACH_PORT_VALID (*namep))
637 return (KERN_INVALID_VALUE);
638 if (is_fast_space (space))
639 return (KERN_FAILURE);
640 }
641
1c79356b 642 if (qosp->prealloc) {
8ad349bb
A
643 if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
644 return KERN_RESOURCE_SHORTAGE;
645 } else {
646 mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
647 if (right != MACH_PORT_RIGHT_RECEIVE)
648 return (KERN_INVALID_VALUE);
649 kmsg = (ipc_kmsg_t)ipc_kmsg_alloc(size);
650 if (kmsg == IKM_NULL)
651 return (KERN_RESOURCE_SHORTAGE);
652 }
1c79356b
A
653 }
654
655 switch (right) {
656 case MACH_PORT_RIGHT_RECEIVE:
657 {
658 ipc_port_t port;
659
660 if (qosp->name)
661 kr = ipc_port_alloc_name(space, *namep, &port);
662 else
663 kr = ipc_port_alloc(space, namep, &port);
664 if (kr == KERN_SUCCESS) {
91447636 665 if (kmsg != IKM_NULL)
1c79356b
A
666 ipc_kmsg_set_prealloc(kmsg, port);
667
1c79356b
A
668 ip_unlock(port);
669
91447636 670 } else if (kmsg != IKM_NULL)
1c79356b
A
671 ipc_kmsg_free(kmsg);
672 break;
673 }
674
675 case MACH_PORT_RIGHT_PORT_SET:
676 {
677 ipc_pset_t pset;
678
679 if (qosp->name)
680 kr = ipc_pset_alloc_name(space, *namep, &pset);
681 else
682 kr = ipc_pset_alloc(space, namep, &pset);
683 if (kr == KERN_SUCCESS)
684 ips_unlock(pset);
685 break;
686 }
687
688 case MACH_PORT_RIGHT_DEAD_NAME:
689 kr = ipc_object_alloc_dead(space, namep);
690 break;
691
692 default:
693 kr = KERN_INVALID_VALUE;
694 break;
695 }
696
697 return (kr);
698}
699
700/*
701 * Routine: mach_port_destroy [kernel call]
702 * Purpose:
703 * Cleans up and destroys all rights denoted by a name
704 * in a space. The destruction of a receive right
705 * destroys the port, unless a port-destroyed request
706 * has been made for it; the destruction of a port-set right
707 * destroys the port set.
708 * Conditions:
709 * Nothing locked.
710 * Returns:
711 * KERN_SUCCESS The name is destroyed.
712 * KERN_INVALID_TASK The space is null.
713 * KERN_INVALID_TASK The space is dead.
714 * KERN_INVALID_NAME The name doesn't denote a right.
715 */
716
717kern_return_t
718mach_port_destroy(
719 ipc_space_t space,
720 mach_port_name_t name)
721{
722 ipc_entry_t entry;
723 kern_return_t kr;
724
725 if (space == IS_NULL)
726 return KERN_INVALID_TASK;
727
728 if (!MACH_PORT_VALID(name))
729 return KERN_SUCCESS;
730
731 kr = ipc_right_lookup_write(space, name, &entry);
732 if (kr != KERN_SUCCESS)
733 return kr;
734 /* space is write-locked and active */
735
736 kr = ipc_right_destroy(space, name, entry);
737 is_write_unlock(space);
738 return kr;
739}
740
741/*
742 * Routine: mach_port_deallocate [kernel call]
743 * Purpose:
744 * Deallocates a user reference from a send right,
745 * send-once right, or a dead-name right. May
746 * deallocate the right, if this is the last uref,
747 * and destroy the name, if it doesn't denote
748 * other rights.
749 * Conditions:
750 * Nothing locked.
751 * Returns:
752 * KERN_SUCCESS The uref is deallocated.
753 * KERN_INVALID_TASK The space is null.
754 * KERN_INVALID_TASK The space is dead.
755 * KERN_INVALID_NAME The name doesn't denote a right.
756 * KERN_INVALID_RIGHT The right isn't correct.
757 */
758
759kern_return_t
760mach_port_deallocate(
761 ipc_space_t space,
762 mach_port_name_t name)
763{
764 ipc_entry_t entry;
765 kern_return_t kr;
766
767 if (space == IS_NULL)
768 return KERN_INVALID_TASK;
769
770 if (!MACH_PORT_VALID(name))
771 return KERN_SUCCESS;
772
773 kr = ipc_right_lookup_write(space, name, &entry);
774 if (kr != KERN_SUCCESS)
775 return kr;
776 /* space is write-locked */
777
778 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
779 return kr;
780}
781
782/*
783 * Routine: mach_port_get_refs [kernel call]
784 * Purpose:
785 * Retrieves the number of user references held by a right.
786 * Receive rights, port-set rights, and send-once rights
787 * always have one user reference. Returns zero if the
788 * name denotes a right, but not the queried right.
789 * Conditions:
790 * Nothing locked.
791 * Returns:
792 * KERN_SUCCESS Number of urefs returned.
793 * KERN_INVALID_TASK The space is null.
794 * KERN_INVALID_TASK The space is dead.
795 * KERN_INVALID_VALUE "right" isn't a legal value.
796 * KERN_INVALID_NAME The name doesn't denote a right.
797 */
798
799kern_return_t
800mach_port_get_refs(
801 ipc_space_t space,
802 mach_port_name_t name,
803 mach_port_right_t right,
804 mach_port_urefs_t *urefsp)
805{
806 mach_port_type_t type;
807 mach_port_urefs_t urefs;
808 ipc_entry_t entry;
809 kern_return_t kr;
810
811 if (space == IS_NULL)
812 return KERN_INVALID_TASK;
813
814 if (right >= MACH_PORT_RIGHT_NUMBER)
815 return KERN_INVALID_VALUE;
816
817 if (!MACH_PORT_VALID(name)) {
818 if (right == MACH_PORT_RIGHT_SEND ||
819 right == MACH_PORT_RIGHT_SEND_ONCE) {
820 *urefsp = 1;
821 return KERN_SUCCESS;
822 }
823 return KERN_INVALID_NAME;
824 }
825
826 kr = ipc_right_lookup_write(space, name, &entry);
827 if (kr != KERN_SUCCESS)
828 return kr;
829 /* space is write-locked and active */
830
831 kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
832 if (kr != KERN_SUCCESS)
833 return kr; /* space is unlocked */
834 is_write_unlock(space);
835
836 if (type & MACH_PORT_TYPE(right))
837 switch (right) {
838 case MACH_PORT_RIGHT_SEND_ONCE:
839 assert(urefs == 1);
840 /* fall-through */
841
842 case MACH_PORT_RIGHT_PORT_SET:
843 case MACH_PORT_RIGHT_RECEIVE:
844 *urefsp = 1;
845 break;
846
847 case MACH_PORT_RIGHT_DEAD_NAME:
848 case MACH_PORT_RIGHT_SEND:
849 assert(urefs > 0);
850 *urefsp = urefs;
851 break;
852
853 default:
854 panic("mach_port_get_refs: strange rights");
855 }
856 else
857 *urefsp = 0;
858
859 return kr;
860}
861
862/*
863 * Routine: mach_port_mod_refs
864 * Purpose:
865 * Modifies the number of user references held by a right.
866 * The resulting number of user references must be non-negative.
867 * If it is zero, the right is deallocated. If the name
868 * doesn't denote other rights, it is destroyed.
869 * Conditions:
870 * Nothing locked.
871 * Returns:
872 * KERN_SUCCESS Modified number of urefs.
873 * KERN_INVALID_TASK The space is null.
874 * KERN_INVALID_TASK The space is dead.
875 * KERN_INVALID_VALUE "right" isn't a legal value.
876 * KERN_INVALID_NAME The name doesn't denote a right.
877 * KERN_INVALID_RIGHT Name doesn't denote specified right.
878 * KERN_INVALID_VALUE Impossible modification to urefs.
879 * KERN_UREFS_OVERFLOW Urefs would overflow.
880 */
881
882kern_return_t
883mach_port_mod_refs(
884 ipc_space_t space,
885 mach_port_name_t name,
886 mach_port_right_t right,
887 mach_port_delta_t delta)
888{
889 ipc_entry_t entry;
890 kern_return_t kr;
891
892 if (space == IS_NULL)
893 return KERN_INVALID_TASK;
894
895 if (right >= MACH_PORT_RIGHT_NUMBER)
896 return KERN_INVALID_VALUE;
897
898 if (!MACH_PORT_VALID(name)) {
899 if (right == MACH_PORT_RIGHT_SEND ||
900 right == MACH_PORT_RIGHT_SEND_ONCE)
901 return KERN_SUCCESS;
902 return KERN_INVALID_NAME;
903 }
904
905 kr = ipc_right_lookup_write(space, name, &entry);
906 if (kr != KERN_SUCCESS)
907 return kr;
908 /* space is write-locked and active */
909
910 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
911 return kr;
912}
913
914
915/*
916 * Routine: mach_port_set_mscount [kernel call]
917 * Purpose:
918 * Changes a receive right's make-send count.
919 * Conditions:
920 * Nothing locked.
921 * Returns:
922 * KERN_SUCCESS Set make-send count.
923 * KERN_INVALID_TASK The space is null.
924 * KERN_INVALID_TASK The space is dead.
925 * KERN_INVALID_NAME The name doesn't denote a right.
926 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
927 */
928
929kern_return_t
930mach_port_set_mscount(
931 ipc_space_t space,
932 mach_port_name_t name,
933 mach_port_mscount_t mscount)
934{
935 ipc_port_t port;
936 kern_return_t kr;
937
938 if (space == IS_NULL)
939 return KERN_INVALID_TASK;
940
941 if (!MACH_PORT_VALID(name))
942 return KERN_INVALID_RIGHT;
943
944 kr = ipc_port_translate_receive(space, name, &port);
945 if (kr != KERN_SUCCESS)
946 return kr;
947 /* port is locked and active */
948
949 ipc_port_set_mscount(port, mscount);
950
951 ip_unlock(port);
952 return KERN_SUCCESS;
953}
954
955/*
956 * Routine: mach_port_set_seqno [kernel call]
957 * Purpose:
958 * Changes a receive right's sequence number.
959 * Conditions:
960 * Nothing locked.
961 * Returns:
962 * KERN_SUCCESS Set sequence number.
963 * KERN_INVALID_TASK The space is null.
964 * KERN_INVALID_TASK The space is dead.
965 * KERN_INVALID_NAME The name doesn't denote a right.
966 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
967 */
968
969kern_return_t
970mach_port_set_seqno(
971 ipc_space_t space,
972 mach_port_name_t name,
973 mach_port_seqno_t seqno)
974{
975 ipc_port_t port;
976 kern_return_t kr;
977
978 if (space == IS_NULL)
979 return KERN_INVALID_TASK;
980
981 if (!MACH_PORT_VALID(name))
982 return KERN_INVALID_RIGHT;
983
984 kr = ipc_port_translate_receive(space, name, &port);
985 if (kr != KERN_SUCCESS)
986 return kr;
987 /* port is locked and active */
988
989 ipc_mqueue_set_seqno(&port->ip_messages, seqno);
990
991 ip_unlock(port);
992 return KERN_SUCCESS;
993}
994
995/*
996 * Routine: mach_port_gst_helper
997 * Purpose:
998 * A helper function for mach_port_get_set_status.
999 */
1000
1001void
1002mach_port_gst_helper(
1003 ipc_pset_t pset,
1004 ipc_port_t port,
1005 ipc_entry_num_t maxnames,
1006 mach_port_name_t *names,
1007 ipc_entry_num_t *actualp)
1008{
1c79356b
A
1009 mach_port_name_t name;
1010
1011 assert(port != IP_NULL);
1012
1013 ip_lock(port);
1014 assert(ip_active(port));
1015
1016 name = port->ip_receiver_name;
1017 assert(name != MACH_PORT_NULL);
1018
1019 ip_unlock(port);
1020
1021 if (ipc_pset_member(pset, port)) {
1022 ipc_entry_num_t actual = *actualp;
1023
1024 if (actual < maxnames)
1025 names[actual] = name;
1026
1027 *actualp = actual+1;
1028 }
1029}
1030
1031/*
1032 * Routine: mach_port_get_set_status [kernel call]
1033 * Purpose:
1034 * Retrieves a list of members in a port set.
1035 * Returns the space's name for each receive right member.
1036 * Conditions:
1037 * Nothing locked.
1038 * Returns:
1039 * KERN_SUCCESS Retrieved list of members.
1040 * KERN_INVALID_TASK The space is null.
1041 * KERN_INVALID_TASK The space is dead.
1042 * KERN_INVALID_NAME The name doesn't denote a right.
1043 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1044 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1045 */
1046
1047kern_return_t
1048mach_port_get_set_status(
1049 ipc_space_t space,
1050 mach_port_name_t name,
1051 mach_port_name_t **members,
1052 mach_msg_type_number_t *membersCnt)
1053{
1054 ipc_entry_num_t actual; /* this many members */
1055 ipc_entry_num_t maxnames; /* space for this many members */
1056 kern_return_t kr;
1057
1058 vm_size_t size; /* size of allocated memory */
1059 vm_offset_t addr; /* allocated memory */
1060 vm_map_copy_t memory; /* copied-in memory */
1061
1062 if (space == IS_NULL)
1063 return KERN_INVALID_TASK;
1064
1065 if (!MACH_PORT_VALID(name))
1066 return KERN_INVALID_RIGHT;
1067
1068 size = PAGE_SIZE; /* initial guess */
1069
1070 for (;;) {
1071 ipc_tree_entry_t tentry;
1072 ipc_entry_t entry, table;
1073 ipc_entry_num_t tsize;
1074 mach_port_index_t index;
1075 mach_port_name_t *names;
1076 ipc_pset_t pset;
1077
91447636 1078 kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE);
1c79356b
A
1079 if (kr != KERN_SUCCESS)
1080 return KERN_RESOURCE_SHORTAGE;
1081
1082 /* can't fault while we hold locks */
1083
1084 kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1085 VM_PROT_READ|VM_PROT_WRITE, FALSE);
1086 assert(kr == KERN_SUCCESS);
1087
1088 kr = ipc_right_lookup_read(space, name, &entry);
1089 if (kr != KERN_SUCCESS) {
1090 kmem_free(ipc_kernel_map, addr, size);
1091 return kr;
1092 }
1093 /* space is read-locked and active */
1094
1095 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
1096 is_read_unlock(space);
1097 kmem_free(ipc_kernel_map, addr, size);
1098 return KERN_INVALID_RIGHT;
1099 }
1100
1101 pset = (ipc_pset_t) entry->ie_object;
1102 assert(pset != IPS_NULL);
1103 /* the port set must be active */
1104
1105 names = (mach_port_name_t *) addr;
1106 maxnames = size / sizeof(mach_port_name_t);
1107 actual = 0;
1108
1109 table = space->is_table;
1110 tsize = space->is_table_size;
1111
1112 for (index = 0; index < tsize; index++) {
1113 ipc_entry_t ientry = &table[index];
1114
1115 if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
1116 ipc_port_t port =
1117 (ipc_port_t) ientry->ie_object;
1118
1119 mach_port_gst_helper(pset, port,
1120 maxnames, names, &actual);
1121 }
1122 }
1123
1124 for (tentry = ipc_splay_traverse_start(&space->is_tree);
1125 tentry != ITE_NULL;
1126 tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
1127 ipc_entry_bits_t bits = tentry->ite_bits;
1128
1129 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
1130
1131 if (bits & MACH_PORT_TYPE_RECEIVE) {
1132 ipc_port_t port = (ipc_port_t) tentry->ite_object;
1133
1134 mach_port_gst_helper(pset, port, maxnames,
1135 names, &actual);
1136 }
1137 }
1138 ipc_splay_traverse_finish(&space->is_tree);
1139 is_read_unlock(space);
1140
1141 if (actual <= maxnames)
1142 break;
1143
1144 /* didn't have enough memory; allocate more */
1145
1146 kmem_free(ipc_kernel_map, addr, size);
91447636 1147 size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
1c79356b
A
1148 }
1149
1150 if (actual == 0) {
1151 memory = VM_MAP_COPY_NULL;
1152
1153 kmem_free(ipc_kernel_map, addr, size);
1154 } else {
1155 vm_size_t size_used;
1156 vm_size_t vm_size_used;
1157
1158 size_used = actual * sizeof(mach_port_name_t);
91447636 1159 vm_size_used = round_page(size_used);
1c79356b
A
1160
1161 /*
1162 * Make used memory pageable and get it into
1163 * copied-in form. Free any unused memory.
1164 */
1165
91447636
A
1166 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr),
1167 vm_map_round_page(addr + vm_size_used), FALSE);
1c79356b
A
1168 assert(kr == KERN_SUCCESS);
1169
91447636
A
1170 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1171 (vm_map_size_t)size_used, TRUE, &memory);
1c79356b
A
1172 assert(kr == KERN_SUCCESS);
1173
1174 if (vm_size_used != size)
1175 kmem_free(ipc_kernel_map,
1176 addr + vm_size_used, size - vm_size_used);
1177 }
1178
1179 *members = (mach_port_name_t *) memory;
1180 *membersCnt = actual;
1181 return KERN_SUCCESS;
1182}
1183
1184/*
1185 * Routine: mach_port_move_member [kernel call]
1186 * Purpose:
1187 * If after is MACH_PORT_NULL, removes member
1188 * from the port set it is in. Otherwise, adds
1189 * member to after, removing it from any set
1190 * it might already be in.
1191 * Conditions:
1192 * Nothing locked.
1193 * Returns:
1194 * KERN_SUCCESS Moved the port.
1195 * KERN_INVALID_TASK The space is null.
1196 * KERN_INVALID_TASK The space is dead.
1197 * KERN_INVALID_NAME Member didn't denote a right.
1198 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1199 * KERN_INVALID_NAME After didn't denote a right.
1200 * KERN_INVALID_RIGHT After didn't denote a port set right.
1201 * KERN_NOT_IN_SET
1202 * After is MACH_PORT_NULL and Member isn't in a port set.
1203 */
1204
1205kern_return_t
1206mach_port_move_member(
1207 ipc_space_t space,
1208 mach_port_name_t member,
1209 mach_port_name_t after)
1210{
1211 ipc_entry_t entry;
1212 ipc_port_t port;
1213 ipc_pset_t nset;
1214 kern_return_t kr;
1215
1216 if (space == IS_NULL)
1217 return KERN_INVALID_TASK;
1218
1219 if (!MACH_PORT_VALID(member))
1220 return KERN_INVALID_RIGHT;
1221
1222 if (after == MACH_PORT_DEAD)
1223 return KERN_INVALID_RIGHT;
1224
1225 kr = ipc_right_lookup_read(space, member, &entry);
1226 if (kr != KERN_SUCCESS)
1227 return kr;
1228 /* space is read-locked and active */
1229
1230 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1231 is_read_unlock(space);
1232 return KERN_INVALID_RIGHT;
1233 }
1234
1235 port = (ipc_port_t) entry->ie_object;
1236 assert(port != IP_NULL);
1237
1238 if (after == MACH_PORT_NULL)
1239 nset = IPS_NULL;
1240 else {
1241 entry = ipc_entry_lookup(space, after);
1242 if (entry == IE_NULL) {
1243 is_read_unlock(space);
1244 return KERN_INVALID_NAME;
1245 }
1246
1247 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1248 is_read_unlock(space);
1249 return KERN_INVALID_RIGHT;
1250 }
1251
1252 nset = (ipc_pset_t) entry->ie_object;
1253 assert(nset != IPS_NULL);
1254 }
1255 ip_lock(port);
9bccf70c 1256 ipc_pset_remove_from_all(port);
1c79356b
A
1257
1258 if (nset != IPS_NULL) {
1259 ips_lock(nset);
1260 kr = ipc_pset_add(nset, port);
1261 ips_unlock(nset);
1262 }
1263 ip_unlock(port);
1264 is_read_unlock(space);
1265 return kr;
1266}
1267
1268/*
1269 * Routine: mach_port_request_notification [kernel call]
1270 * Purpose:
1271 * Requests a notification. The caller supplies
1272 * a send-once right for the notification to use,
1273 * and the call returns the previously registered
1274 * send-once right, if any. Possible types:
1275 *
1276 * MACH_NOTIFY_PORT_DESTROYED
1277 * Requests a port-destroyed notification
1278 * for a receive right. Sync should be zero.
1279 * MACH_NOTIFY_NO_SENDERS
1280 * Requests a no-senders notification for a
1281 * receive right. If there are currently no
1282 * senders, sync is less than or equal to the
1283 * current make-send count, and a send-once right
1284 * is supplied, then an immediate no-senders
1285 * notification is generated.
1286 * MACH_NOTIFY_DEAD_NAME
1287 * Requests a dead-name notification for a send
1288 * or receive right. If the name is already a
1289 * dead name, sync is non-zero, and a send-once
1290 * right is supplied, then an immediate dead-name
1291 * notification is generated.
1292 * Conditions:
1293 * Nothing locked.
1294 * Returns:
1295 * KERN_SUCCESS Requested a notification.
1296 * KERN_INVALID_TASK The space is null.
1297 * KERN_INVALID_TASK The space is dead.
1298 * KERN_INVALID_VALUE Bad id value.
1299 * KERN_INVALID_NAME Name doesn't denote a right.
1300 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1301 * KERN_INVALID_CAPABILITY The notify port is dead.
1302 * MACH_NOTIFY_PORT_DESTROYED:
1303 * KERN_INVALID_VALUE Sync isn't zero.
1304 * MACH_NOTIFY_DEAD_NAME:
1305 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1306 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1307 * sync is zero or notify is IP_NULL.
1308 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1309 * generating immediate notif. would overflow urefs.
1310 */
1311
1312kern_return_t
1313mach_port_request_notification(
1314 ipc_space_t space,
1315 mach_port_name_t name,
1316 mach_msg_id_t id,
1317 mach_port_mscount_t sync,
1318 ipc_port_t notify,
1319 ipc_port_t *previousp)
1320{
1321 kern_return_t kr;
1c79356b
A
1322
1323 if (space == IS_NULL)
1324 return KERN_INVALID_TASK;
1325
1326 if (notify == IP_DEAD)
1327 return KERN_INVALID_CAPABILITY;
1328
1329#if NOTYET
1330 /*
1331 * Requesting notifications on RPC ports is an error.
1332 */
91447636
A
1333 {
1334 ipc_port_t port;
1335 ipc_entry_t entry;
1c79356b 1336
91447636
A
1337 kr = ipc_right_lookup_write(space, name, &entry);
1338 if (kr != KERN_SUCCESS)
1339 return kr;
1c79356b 1340
91447636
A
1341 port = (ipc_port_t) entry->ie_object;
1342
1343 if (port->ip_subsystem != NULL) {
1344 is_write_unlock(space);
1345 panic("mach_port_request_notification: on RPC port!!");
1346 return KERN_INVALID_CAPABILITY;
1347 }
1c79356b 1348 is_write_unlock(space);
1c79356b 1349 }
1c79356b
A
1350#endif /* NOTYET */
1351
1352
1353 switch (id) {
1354 case MACH_NOTIFY_PORT_DESTROYED: {
1355 ipc_port_t port, previous;
1356
1357 if (sync != 0)
1358 return KERN_INVALID_VALUE;
1359
1360 if (!MACH_PORT_VALID(name))
1361 return KERN_INVALID_RIGHT;
1362
1363 kr = ipc_port_translate_receive(space, name, &port);
1364 if (kr != KERN_SUCCESS)
1365 return kr;
1366 /* port is locked and active */
1367
1368 ipc_port_pdrequest(port, notify, &previous);
1369 /* port is unlocked */
1370
1371 *previousp = previous;
1372 break;
1373 }
1374
1375 case MACH_NOTIFY_NO_SENDERS: {
1376 ipc_port_t port;
1377
1378 if (!MACH_PORT_VALID(name))
1379 return KERN_INVALID_RIGHT;
1380
1381 kr = ipc_port_translate_receive(space, name, &port);
1382 if (kr != KERN_SUCCESS)
1383 return kr;
1384 /* port is locked and active */
1385
1386 ipc_port_nsrequest(port, sync, notify, previousp);
1387 /* port is unlocked */
1388 break;
1389 }
1390
1391 case MACH_NOTIFY_DEAD_NAME:
1392
1393 if (!MACH_PORT_VALID(name)) {
1394 /*
1395 * Already dead.
1396 * Should do immediate delivery check -
1397 * will do that in the near future.
1398 */
1399 return KERN_INVALID_ARGUMENT;
1400 }
1401
1402 kr = ipc_right_dnrequest(space, name, sync != 0,
1403 notify, previousp);
1404 if (kr != KERN_SUCCESS)
1405 return kr;
1406 break;
1407
1408 default:
1409 return KERN_INVALID_VALUE;
1410 }
1411
1412 return KERN_SUCCESS;
1413}
1414
1415/*
1416 * Routine: mach_port_insert_right [kernel call]
1417 * Purpose:
1418 * Inserts a right into a space, as if the space
1419 * voluntarily received the right in a message,
1420 * except that the right gets the specified name.
1421 * Conditions:
1422 * Nothing locked.
1423 * Returns:
1424 * KERN_SUCCESS Inserted the right.
1425 * KERN_INVALID_TASK The space is null.
1426 * KERN_INVALID_TASK The space is dead.
1427 * KERN_INVALID_VALUE The name isn't a legal name.
1428 * KERN_NAME_EXISTS The name already denotes a right.
1429 * KERN_INVALID_VALUE Message doesn't carry a port right.
1430 * KERN_INVALID_CAPABILITY Port is null or dead.
1431 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1432 * KERN_RIGHT_EXISTS Space has rights under another name.
1433 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1434 */
1435
1436kern_return_t
1437mach_port_insert_right(
1438 ipc_space_t space,
1439 mach_port_name_t name,
1440 ipc_port_t poly,
1441 mach_msg_type_name_t polyPoly)
1442{
1443 if (space == IS_NULL)
1444 return KERN_INVALID_TASK;
1445
1446 if (!MACH_PORT_VALID(name) ||
1447 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1448 return KERN_INVALID_VALUE;
1449
1450 if (!IO_VALID((ipc_object_t) poly))
1451 return KERN_INVALID_CAPABILITY;
1452
1453 return ipc_object_copyout_name(space, (ipc_object_t) poly,
1454 polyPoly, FALSE, name);
1455}
1456
1457/*
1458 * Routine: mach_port_extract_right [kernel call]
1459 * Purpose:
1460 * Extracts a right from a space, as if the space
1461 * voluntarily sent the right to the caller.
1462 * Conditions:
1463 * Nothing locked.
1464 * Returns:
1465 * KERN_SUCCESS Extracted the right.
1466 * KERN_INVALID_TASK The space is null.
1467 * KERN_INVALID_TASK The space is dead.
1468 * KERN_INVALID_VALUE Requested type isn't a port right.
1469 * KERN_INVALID_NAME Name doesn't denote a right.
1470 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1471 */
1472
1473kern_return_t
1474mach_port_extract_right(
1475 ipc_space_t space,
1476 mach_port_name_t name,
1477 mach_msg_type_name_t msgt_name,
1478 ipc_port_t *poly,
1479 mach_msg_type_name_t *polyPoly)
1480{
1481 kern_return_t kr;
1482
1483 if (space == IS_NULL)
1484 return KERN_INVALID_TASK;
1485
1486 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1487 return KERN_INVALID_VALUE;
1488
1489 if (!MACH_PORT_VALID(name)) {
1490 /*
1491 * really should copy out a dead name, if it is a send or
1492 * send-once right being copied, but instead return an
1493 * error for now.
1494 */
1495 return KERN_INVALID_RIGHT;
1496 }
1497
1498 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1499
1500 if (kr == KERN_SUCCESS)
1501 *polyPoly = ipc_object_copyin_type(msgt_name);
1502 return kr;
1503}
1504
1505
1506kern_return_t
1507mach_port_get_attributes(
1508 ipc_space_t space,
1509 mach_port_name_t name,
1510 int flavor,
1511 mach_port_info_t info,
1512 mach_msg_type_number_t *count)
1513{
1514 ipc_port_t port;
1515 kern_return_t kr;
1516
1517 if (space == IS_NULL)
1518 return KERN_INVALID_TASK;
1519
1520 switch (flavor) {
1521 case MACH_PORT_LIMITS_INFO: {
1522 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1523
1524 if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1525 return KERN_FAILURE;
1526
1527 if (!MACH_PORT_VALID(name)) {
1528 *count = 0;
1529 break;
1530 }
1531
1532 kr = ipc_port_translate_receive(space, name, &port);
1533 if (kr != KERN_SUCCESS)
1534 return kr;
1535 /* port is locked and active */
1536
1537 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1538 *count = MACH_PORT_LIMITS_INFO_COUNT;
1539 ip_unlock(port);
1540 break;
1541 }
1542
1543 case MACH_PORT_RECEIVE_STATUS: {
1544 mach_port_status_t *statusp = (mach_port_status_t *)info;
1545 spl_t s;
1546
1547 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1548 return KERN_FAILURE;
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 statusp->mps_pset = port->ip_pset_count;
1559
1560 s = splsched();
1561 imq_lock(&port->ip_messages);
1562 statusp->mps_seqno = port->ip_messages.imq_seqno;
1563 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1564 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1565 imq_unlock(&port->ip_messages);
1566 splx(s);
1567
1568 statusp->mps_mscount = port->ip_mscount;
1569 statusp->mps_sorights = port->ip_sorights;
1570 statusp->mps_srights = port->ip_srights > 0;
1571 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1572 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1573 statusp->mps_flags = 0;
1574
1575 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1576 ip_unlock(port);
1577 break;
1578 }
1579
1580 case MACH_PORT_DNREQUESTS_SIZE: {
1581 ipc_port_request_t table;
1582
1583 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1584 return KERN_FAILURE;
1585
1586 if (!MACH_PORT_VALID(name)) {
1587 *(int *)info = 0;
1588 break;
1589 }
1590
1591 kr = ipc_port_translate_receive(space, name, &port);
1592 if (kr != KERN_SUCCESS)
1593 return kr;
1594 /* port is locked and active */
1595
1596 table = port->ip_dnrequests;
1597 if (table == IPR_NULL)
1598 *(int *)info = 0;
1599 else
1600 *(int *)info = table->ipr_size->its_size;
1601 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1602 ip_unlock(port);
1603 break;
1604 }
1605
1606 default:
1607 return KERN_INVALID_ARGUMENT;
1608 /*NOTREACHED*/
1609 }
1610
1611 return KERN_SUCCESS;
1612}
1613
1614kern_return_t
1615mach_port_set_attributes(
1616 ipc_space_t space,
1617 mach_port_name_t name,
1618 int flavor,
1619 mach_port_info_t info,
1620 mach_msg_type_number_t count)
1621{
1622 ipc_port_t port;
1623 kern_return_t kr;
1624
1625 if (space == IS_NULL)
1626 return KERN_INVALID_TASK;
1627
1628 switch (flavor) {
1629
1630 case MACH_PORT_LIMITS_INFO: {
1631 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1632
1633 if (count < MACH_PORT_LIMITS_INFO_COUNT)
1634 return KERN_FAILURE;
1635
1636 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1637 return KERN_INVALID_VALUE;
1638
1639 if (!MACH_PORT_VALID(name))
1640 return KERN_INVALID_RIGHT;
1641
1642 kr = ipc_port_translate_receive(space, name, &port);
1643 if (kr != KERN_SUCCESS)
1644 return kr;
1645 /* port is locked and active */
1646
1647 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1648 ip_unlock(port);
1649 break;
1650 }
1651 case MACH_PORT_DNREQUESTS_SIZE: {
1652 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1653 return KERN_FAILURE;
1654
1655 if (!MACH_PORT_VALID(name))
1656 return KERN_INVALID_RIGHT;
1657
1658 kr = ipc_port_translate_receive(space, name, &port);
1659 if (kr != KERN_SUCCESS)
1660 return kr;
1661 /* port is locked and active */
1662
1663 kr = ipc_port_dngrow(port, *(int *)info);
1664 if (kr != KERN_SUCCESS)
1665 return kr;
1666 break;
1667 }
1668 default:
1669 return KERN_INVALID_ARGUMENT;
1670 /*NOTREACHED*/
1671 }
1672 return KERN_SUCCESS;
1673}
1674
1675/*
1676 * Routine: mach_port_insert_member [kernel call]
1677 * Purpose:
1678 * Add the receive right, specified by name, to
1679 * a portset.
1680 * The port cannot already be a member of the set.
1681 * Conditions:
1682 * Nothing locked.
1683 * Returns:
1684 * KERN_SUCCESS Moved the port.
1685 * KERN_INVALID_TASK The space is null.
1686 * KERN_INVALID_TASK The space is dead.
1687 * KERN_INVALID_NAME name didn't denote a right.
1688 * KERN_INVALID_RIGHT name didn't denote a receive right.
1689 * KERN_INVALID_NAME pset_name didn't denote a right.
1690 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
1691 * KERN_ALREADY_IN_SET name was already a member of pset.
1692 */
1693
1694kern_return_t
1695mach_port_insert_member(
1696 ipc_space_t space,
1697 mach_port_name_t name,
1698 mach_port_name_t psname)
1699{
1700 ipc_object_t obj;
1701 ipc_object_t psobj;
1702 kern_return_t kr;
1703
1704 if (space == IS_NULL)
1705 return KERN_INVALID_TASK;
1706
1707 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1708 return KERN_INVALID_RIGHT;
1709
1710 kr = ipc_object_translate_two(space,
1711 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1712 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1713 if (kr != KERN_SUCCESS)
1714 return kr;
1715
1716 /* obj and psobj are locked (and were locked in that order) */
1717 assert(psobj != IO_NULL);
1718 assert(obj != IO_NULL);
1719
1720 kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj);
1721 io_unlock(psobj);
1722 io_unlock(obj);
1723 return kr;
1724}
1725
1726/*
1727 * Routine: mach_port_extract_member [kernel call]
1728 * Purpose:
1729 * Remove a port from one portset that it is a member of.
1730 * Conditions:
1731 * Nothing locked.
1732 * Returns:
1733 * KERN_SUCCESS Moved the port.
1734 * KERN_INVALID_TASK The space is null.
1735 * KERN_INVALID_TASK The space is dead.
1736 * KERN_INVALID_NAME Member didn't denote a right.
1737 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1738 * KERN_INVALID_NAME After didn't denote a right.
1739 * KERN_INVALID_RIGHT After didn't denote a port set right.
1740 * KERN_NOT_IN_SET
1741 * After is MACH_PORT_NULL and Member isn't in a port set.
1742 */
1743
1744kern_return_t
1745mach_port_extract_member(
1746 ipc_space_t space,
1747 mach_port_name_t name,
1748 mach_port_name_t psname)
1749{
1c79356b
A
1750 ipc_object_t psobj;
1751 ipc_object_t obj;
1752 kern_return_t kr;
1753
1754 if (space == IS_NULL)
1755 return KERN_INVALID_TASK;
1756
1757 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1758 return KERN_INVALID_RIGHT;
1759
1760 kr = ipc_object_translate_two(space,
1761 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1762 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1763 if (kr != KERN_SUCCESS)
1764 return kr;
1765
1766 /* obj and psobj are both locked (and were locked in that order) */
1767 assert(psobj != IO_NULL);
1768 assert(obj != IO_NULL);
1769
1770 kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj);
1771 io_unlock(psobj);
1772 io_unlock(obj);
1773 return kr;
1774}
1775
91447636
A
1776/*
1777 * task_set_port_space:
1778 *
1779 * Set port name space of task to specified size.
1780 */
1781kern_return_t
1782task_set_port_space(
1783 ipc_space_t space,
1784 int table_entries)
1785{
1786 kern_return_t kr;
1787
1788 is_write_lock(space);
1789 kr = ipc_entry_grow_table(space, table_entries);
1790 if (kr == KERN_SUCCESS)
1791 is_write_unlock(space);
1792 return kr;
1793}
1794
2d21ac55
A
1795/*
1796 * Get a (new) label handle representing the given port's port label.
1797 */
1798#if CONFIG_MACF_MACH
1799kern_return_t
1800mach_get_label(
1801 ipc_space_t space,
1802 mach_port_name_t name,
1803 mach_port_name_t *outlabel)
1804{
1805 ipc_entry_t entry;
1806 ipc_port_t port;
1807 struct label outl;
1808 kern_return_t kr;
1809 int dead;
1810
1811 if (!MACH_PORT_VALID(name))
1812 return KERN_INVALID_NAME;
1813
1814 /* Lookup the port name in the task's space. */
1815 kr = ipc_right_lookup_write(space, name, &entry);
1816 if (kr != KERN_SUCCESS)
1817 return kr;
1818
1819 port = (ipc_port_t) entry->ie_object;
1820 dead = ipc_right_check(space, port, name, entry);
1821 if (dead) {
1822 is_write_unlock(space);
1823 return KERN_INVALID_RIGHT;
1824 }
1825 /* port is now locked */
1826
1827 is_write_unlock(space);
1828 /* Make sure we are not dealing with a label handle. */
1829 if (ip_kotype(port) == IKOT_LABELH) {
1830 /* already is a label handle! */
1831 ip_unlock(port);
1832 return KERN_INVALID_ARGUMENT;
1833 }
1834
1835 /* Copy the port label and stash it in a new label handle. */
1836 mac_port_label_init(&outl);
1837 mac_port_label_copy(&port->ip_label, &outl);
1838 kr = labelh_new_user(space, &outl, outlabel);
1839 ip_unlock(port);
1840
1841 return KERN_SUCCESS;
1842}
1843#else
1844kern_return_t
1845mach_get_label(
1846 __unused ipc_space_t space,
1847 __unused mach_port_name_t name,
1848 __unused mach_port_name_t *outlabel)
1849{
1850 return KERN_INVALID_ARGUMENT;
1851}
1852#endif
1853
1854/*
1855 * also works on label handles
1856 */
1857#if CONFIG_MACF_MACH
1858kern_return_t
1859mach_get_label_text(
1860 ipc_space_t space,
1861 mach_port_name_t name,
1862 labelstr_t policies,
1863 labelstr_t outlabel)
1864{
1865 ipc_entry_t entry;
1866 kern_return_t kr;
1867 struct label *l;
1868 int dead;
1869
1870 if (space == IS_NULL || space->is_task == NULL)
1871 return KERN_INVALID_TASK;
1872
1873 if (!MACH_PORT_VALID(name))
1874 return KERN_INVALID_NAME;
1875
1876 kr = ipc_right_lookup_write(space, name, &entry);
1877 if (kr != KERN_SUCCESS)
1878 return kr;
1879
1880 dead = ipc_right_check(space, (ipc_port_t) entry->ie_object, name,
1881 entry);
1882 if (dead) {
1883 is_write_unlock(space);
1884 return KERN_INVALID_RIGHT;
1885 }
1886 /* object (port) is now locked */
1887
1888 is_write_unlock (space);
1889 l = io_getlabel(entry->ie_object);
1890
1891 mac_port_label_externalize(l, policies, outlabel, 512, 0);
1892
1893 io_unlocklabel(entry->ie_object);
1894 io_unlock(entry->ie_object);
1895 return KERN_SUCCESS;
1896}
1897#else
1898kern_return_t
1899mach_get_label_text(
1900 __unused ipc_space_t space,
1901 __unused mach_port_name_t name,
1902 __unused labelstr_t policies,
1903 __unused labelstr_t outlabel)
1904{
1905 return KERN_INVALID_ARGUMENT;
1906}
1907#endif
1908
1909
1910#if CONFIG_MACF_MACH
1911kern_return_t
1912mach_set_port_label(
1913 ipc_space_t space,
1914 mach_port_name_t name,
1915 labelstr_t labelstr)
1916{
1917 ipc_entry_t entry;
1918 kern_return_t kr;
1919 struct label inl;
1920 ipc_port_t port;
1921 int rc;
1922
1923 if (space == IS_NULL || space->is_task == NULL)
1924 return KERN_INVALID_TASK;
1925
1926 if (!MACH_PORT_VALID(name))
1927 return KERN_INVALID_NAME;
1928
1929 mac_port_label_init(&inl);
1930 rc = mac_port_label_internalize(&inl, labelstr);
1931 if (rc)
1932 return KERN_INVALID_ARGUMENT;
1933
1934 kr = ipc_right_lookup_write(space, name, &entry);
1935 if (kr != KERN_SUCCESS)
1936 return kr;
1937
1938 if (io_otype(entMACry->ie_object) != IOT_PORT) {
1939 is_write_unlock(space);
1940 return KERN_INVALID_RIGHT;
1941 }
1942
1943 port = (ipc_port_t) entry->ie_object;
1944 ip_lock(port);
1945
1946 tasklabel_lock(space->is_task);
1947 rc = mac_port_check_label_update(&space->is_task->maclabel,
1948 &port->ip_label, &inl);
1949 tasklabel_unlock(space->is_task);
1950 if (rc)
1951 kr = KERN_NO_ACCESS;
1952 else
1953 mac_port_label_copy(&inl, &port->ip_label);
1954
1955 ip_unlock(port);
1956 is_write_unlock(space);
1957 return kr;
1958}
1959#else
1960kern_return_t
1961mach_set_port_label(
1962 ipc_space_t space __unused,
1963 mach_port_name_t name __unused,
1964 labelstr_t labelstr __unused)
1965{
1966 return KERN_INVALID_ARGUMENT;
1967}
1968#endif