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