xref: /NextBSD/sys/compat/mach/ipc/ipc_right.c (revision 73cc658e2427945fb30119abc79de39b89a86f80)
1 /*
2  * Copyright 1991-1998 by Open Software Foundation, Inc.
3  *              All Rights Reserved
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby granted,
7  * provided that the above copyright notice appears in all copies and
8  * that both the copyright notice and this permission notice appear in
9  * supporting documentation.
10  *
11  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13  * FOR A PARTICULAR PURPOSE.
14  *
15  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 /*
22  * MkLinux
23  */
24 /* CMU_HIST */
25 /*
26  * Revision 2.6  91/05/14  16:36:12  mrt
27  * 	Correcting copyright
28  *
29  * Revision 2.5  91/02/14  14:08:29  mrt
30  * 	Fixed bug in ipc_right_copyin_check, following rchen's report.
31  * 	[91/01/26            rpd]
32  *
33  * Revision 2.4  91/02/05  17:23:26  mrt
34  * 	Changed to new Mach copyright
35  * 	[91/02/01  15:50:46  mrt]
36  *
37  * Revision 2.3  90/11/05  14:30:05  rpd
38  * 	Changed io_release to ipc_object_release.
39  * 	Changed ip_release to ipc_port_release.
40  * 	Use new ip_reference and ip_release.
41  * 	[90/10/29            rpd]
42  *
43  * Revision 2.2  90/06/02  14:51:28  rpd
44  * 	Created for new IPC.
45  * 	[90/03/26  21:02:31  rpd]
46  *
47  */
48 /* CMU_ENDHIST */
49 /*
50  * Mach Operating System
51  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
52  * All Rights Reserved.
53  *
54  * Permission to use, copy, modify and distribute this software and its
55  * documentation is hereby granted, provided that both the copyright
56  * notice and this permission notice appear in all copies of the
57  * software, derivative works or modified versions, and any portions
58  * thereof, and that both notices appear in supporting documentation.
59  *
60  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
61  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
62  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
63  *
64  * Carnegie Mellon requests users of this software to return to
65  *
66  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
67  *  School of Computer Science
68  *  Carnegie Mellon University
69  *  Pittsburgh PA 15213-3890
70  *
71  * any improvements or extensions that they make and grant Carnegie Mellon
72  * the rights to redistribute these changes.
73  */
74 /*
75  */
76 /*
77  *	File:	ipc/ipc_right.c
78  *	Author:	Rich Draves
79  *	Date:	1989
80  *
81  *	Functions to manipulate IPC capabilities.
82  */
83 
84 
85 #include <sys/cdefs.h>
86 #include <sys/types.h>
87 #include <sys/param.h>
88 
89 #include <sys/mach/kern_return.h>
90 #include <sys/mach/port.h>
91 #include <sys/mach/message.h>
92 #if 0
93 #include <kern/assert.h>
94 #include <kern/misc_protos.h>
95 #include <kern/ipc_subsystem.h>
96 #endif
97 #include <sys/mach/ipc/port.h>
98 #include <sys/mach/ipc/ipc_entry.h>
99 #include <sys/mach/ipc/ipc_space.h>
100 #include <sys/mach/ipc/ipc_object.h>
101 #include <sys/mach/ipc/ipc_hash.h>
102 #include <sys/mach/ipc/ipc_port.h>
103 #include <sys/mach/ipc/ipc_pset.h>
104 #include <sys/mach/ipc/ipc_right.h>
105 #include <sys/mach/ipc/ipc_notify.h>
106 #include <sys/mach/ipc/ipc_table.h>
107 
108 #include <sys/mach/task.h>
109 
110 #ifdef INVARIANTS
111 #define OBJECT_CLEAR(entry, name) do {									\
112 		/* printf("clearing object %p name: %d %s:%d\n", entry->ie_object, name, __FILE__, __LINE__); */ \
113 		(entry)->ie_object = IO_NULL;									\
114 } while (0)
115 #else
116 #define OBJECT_CLEAR(entry, name) (entry)->ie_object = IO_NULL
117 #endif
118 
119 /*
120  *	Routine:	ipc_right_lookup_write
121  *	Purpose:
122  *		Finds an entry in a space, given the name.
123  *	Conditions:
124  *		Nothing locked.  If successful, the space is write-locked.
125  *	Returns:
126  *		KERN_SUCCESS		Found an entry.
127  *		KERN_INVALID_TASK	The space is dead.
128  *		KERN_INVALID_NAME	Name doesn't exist in space.
129  */
130 
131 kern_return_t
ipc_right_lookup(ipc_space_t space,mach_port_name_t name,ipc_entry_t * entryp,int xlock)132 ipc_right_lookup(
133 	ipc_space_t	space,
134 	mach_port_name_t	name,
135 	ipc_entry_t	*entryp,
136 	int xlock)
137 {
138 	ipc_entry_t entry;
139 
140 
141 	assert(space != IS_NULL);
142 
143 
144 	if (!space->is_active)
145 		return KERN_INVALID_TASK;
146 	if ((entry = ipc_entry_lookup(space, name)) == IE_NULL)
147 		return KERN_INVALID_NAME;
148 
149 	if (xlock)
150 		is_write_lock(space);
151 	else
152 		is_read_lock(space);
153 	*entryp = entry;
154 	return KERN_SUCCESS;
155 }
156 
157 /*
158  *	Routine:	ipc_right_reverse
159  *	Purpose:
160  *		Translate (space, object) -> (name, entry).
161  *		Only finds send/receive rights.
162  *		Returns TRUE if an entry is found; if so,
163  *		the object is locked and active.
164  *	Conditions:
165  *		The space must be locked (read or write) and active.
166  *		Nothing else locked.
167  */
168 
169 boolean_t
ipc_right_reverse(ipc_space_t space,ipc_object_t object,mach_port_name_t * namep,ipc_entry_t * entryp)170 ipc_right_reverse(
171 	ipc_space_t	space,
172 	ipc_object_t	object,
173 	mach_port_name_t	*namep,
174 	ipc_entry_t	*entryp)
175 {
176 	ipc_port_t port;
177 	mach_port_name_t name;
178 	ipc_entry_t entry;
179 
180 	/* would switch on io_otype to handle multiple types of object */
181 
182 	assert(space->is_active);
183 	assert(io_otype(object) == IOT_PORT);
184 
185 	port = (ipc_port_t) object;
186 
187 	ip_lock(port);
188 	if (!ip_active(port)) {
189 		ip_unlock(port);
190 
191 		return FALSE;
192 	}
193 
194 	if (port->ip_receiver == space) {
195 		name = port->ip_receiver_name;
196 		assert(name != MACH_PORT_NAME_NULL);
197 
198 		entry = ipc_entry_lookup(space, name);
199 
200 		KASSERT(entry != IE_NULL, ("no entry found for port: %p name: %d space: %p", port, name, space));
201 		assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
202 		assert(port == (ipc_port_t) entry->ie_object);
203 
204 		*namep = name;
205 		*entryp = entry;
206 		return TRUE;
207 	}
208 
209 	if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
210 		assert((entry = *entryp) != IE_NULL);
211 		assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
212 		assert(port == (ipc_port_t) entry->ie_object);
213 
214 		return TRUE;
215 	}
216 
217 	ip_unlock(port);
218 	return FALSE;
219 }
220 
221 /*
222  *	Routine:	ipc_right_dnrequest
223  *	Purpose:
224  *		Make a dead-name request, returning the previously
225  *		registered send-once right.  If notify is IP_NULL,
226  *		just cancels the previously registered request.
227  *
228  *		This interacts with the IE_BITS_COMPAT, because they
229  *		both use ie_request.  If this is a compat entry, then
230  *		previous always gets IP_NULL.  If notify is IP_NULL,
231  *		then the entry remains a compat entry.  Otherwise
232  *		the real dead-name request is registered and the entry
233  *		is no longer a compat entry.
234  *	Conditions:
235  *		Nothing locked.  May allocate memory.
236  *		Only consumes/returns refs if successful.
237  *	Returns:
238  *		KERN_SUCCESS		Made/canceled dead-name request.
239  *		KERN_INVALID_TASK	The space is dead.
240  *		KERN_INVALID_NAME	Name doesn't exist in space.
241  *		KERN_INVALID_RIGHT	Name doesn't denote port/dead rights.
242  *		KERN_INVALID_ARGUMENT	Name denotes dead name, but
243  *			immediate is FALSE or notify is IP_NULL.
244  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
245  */
246 
247 kern_return_t
ipc_right_dnrequest(ipc_space_t space,mach_port_name_t name,boolean_t immediate,ipc_port_t notify,ipc_port_t * previousp)248 ipc_right_dnrequest(
249 	ipc_space_t	space,
250 	mach_port_name_t	name,
251 	boolean_t	immediate,
252 	ipc_port_t	notify,
253 	ipc_port_t	*previousp)
254 {
255 	ipc_port_t previous;
256 	ipc_port_t port = NULL;
257 
258 	for (;;) {
259 		ipc_entry_t entry;
260 		ipc_entry_bits_t bits;
261 		kern_return_t kr;
262 
263 		kr = ipc_right_lookup_write(space, name, &entry);
264 		ip_unlock_assert(port);
265 		if (kr != KERN_SUCCESS)
266 			return kr;
267 		/* space is write-locked and active */
268 
269 		bits = entry->ie_bits;
270 		if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
271 
272 			ipc_port_request_index_t request;
273 
274 			port = (ipc_port_t) entry->ie_object;
275 			assert(port != IP_NULL);
276 
277 			if (!ipc_right_check(space, port, name, entry)) {
278 				/* port is locked and active */
279 
280 				if (notify == IP_NULL) {
281 					previous = ipc_right_dncancel_macro(
282 						space, port, name, entry);
283 
284 					ip_unlock(port);
285 					is_write_unlock(space);
286 					break;
287 				}
288 
289 				/*
290 				 *	If a registered soright exists,
291 				 *	want to atomically switch with it.
292 				 *	If ipc_port_dncancel finds us a
293 				 *	soright, then the following
294 				 *	ipc_port_dnrequest will reuse
295 				 *	that slot, so we are guaranteed
296 				 *	not to unlock and retry.
297 				 */
298 
299 				previous = ipc_right_dncancel_macro(space,
300 							port, name, entry);
301 
302 				kr = ipc_port_dnrequest(port, name, notify,
303 							&request);
304 				if (kr != KERN_SUCCESS) {
305 					assert(previous == IP_NULL);
306 					is_write_unlock(space);
307 
308 					kr = ipc_port_dngrow(port,
309 							     ITS_SIZE_NONE);
310 					ip_unlock_assert(port);
311 					/* port is unlocked */
312 					if (kr != KERN_SUCCESS)
313 						return kr;
314 
315 					continue;
316 				}
317 
318 				assert(request != 0);
319 				ip_unlock(port);
320 
321 				entry->ie_request = request;
322 				is_write_unlock(space);
323 				break;
324 			}
325 
326 			bits = entry->ie_bits;
327 			assert(bits & MACH_PORT_TYPE_DEAD_NAME);
328 		}
329 
330 		if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
331 		    immediate && (notify != IP_NULL)) {
332 
333 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
334 			assert(ipc_entry_refs(entry) > 0);
335 
336 			ipc_entry_hold(entry); /* increment urefs */
337 			is_write_unlock(space);
338 
339 			ipc_notify_dead_name(notify, name);
340 			previous = IP_NULL;
341 			break;
342 		}
343 
344 		is_write_unlock(space);
345 		if (port)
346 			ip_unlock_assert(port);
347 		if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
348 			return KERN_INVALID_ARGUMENT;
349 		else
350 			return KERN_INVALID_RIGHT;
351 	}
352 	if (port)
353 		ip_unlock_assert(port);
354 	*previousp = previous;
355 	return KERN_SUCCESS;
356 }
357 
358 /*
359  *	Routine:	ipc_right_dncancel
360  *	Purpose:
361  *		Cancel a dead-name request and return the send-once right.
362  *		Afterwards, entry->ie_request == 0.
363  *	Conditions:
364  *		The space must be write-locked; the port must be locked.
365  *		The port must be active; the space doesn't have to be.
366  */
367 
368 ipc_port_t
ipc_right_dncancel(ipc_space_t space,ipc_port_t port,mach_port_name_t name,ipc_entry_t entry)369 ipc_right_dncancel(
370 	ipc_space_t	space,
371 	ipc_port_t	port,
372 	mach_port_name_t	name,
373 	ipc_entry_t	entry)
374 {
375 	ipc_port_t dnrequest;
376 
377 	assert(ip_active(port));
378 	assert(port == (ipc_port_t) entry->ie_object);
379 
380 	dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
381 	entry->ie_request = 0;
382 
383 	return dnrequest;
384 }
385 
386 /*
387  *	Routine:	ipc_right_inuse
388  *	Purpose:
389  *		Check if an entry is being used.
390  *		Returns TRUE if it is.
391  *	Conditions:
392  *		The space is write-locked and active.
393  *		It is unlocked if the entry is inuse.
394  */
395 
396 boolean_t
ipc_right_inuse(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)397 ipc_right_inuse(
398 	ipc_space_t	space,
399 	mach_port_name_t	name,
400 	ipc_entry_t	entry)
401 {
402 	ipc_entry_bits_t bits = entry->ie_bits;
403 
404 	if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
405 		is_write_unlock(space);
406 		return TRUE;
407 	}
408 
409 	return FALSE;
410 }
411 
412 /*
413  *	Routine:	ipc_right_check
414  *	Purpose:
415  *		Check if the port has died.  If it has,
416  *		clean up the entry and return TRUE.
417  *	Conditions:
418  *		The space is write-locked; the port is not locked.
419  *		If returns FALSE, the port is also locked and active.
420  *		Otherwise, entry is converted to a dead name, freeing
421  *		a reference to port.
422  *
423  */
424 
425 boolean_t
ipc_right_check(ipc_space_t space,ipc_port_t port,mach_port_name_t name,ipc_entry_t entry)426 ipc_right_check(
427 	ipc_space_t	space,
428 	ipc_port_t	port,
429 	mach_port_name_t	name,
430 	ipc_entry_t	entry)
431 {
432 	ipc_entry_bits_t bits;
433 
434 	assert(space->is_active);
435 	assert(port == (ipc_port_t) entry->ie_object);
436 
437 	ip_lock(port);
438 	if (ip_active(port)) {
439 		return FALSE;
440 	}
441 	ip_unlock(port);
442 
443 	/* this was either a pure send right or a send-once right */
444 
445 	bits = entry->ie_bits;
446 	assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
447 	assert(ipc_entry_refs(entry) > 0);
448 
449 	if (bits & MACH_PORT_TYPE_SEND) {
450 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
451 		ipc_hash_delete(space, (ipc_object_t) port, name, entry);
452 	} else {
453 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
454 		MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
455 	}
456 
457 	ipc_port_release(port);
458 
459 	/* convert entry to dead name */
460 
461 	bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
462 
463 	if (entry->ie_request != 0) {
464 		entry->ie_request = 0;
465 		ipc_entry_hold(entry); /* increment urefs */
466 	}
467 
468 	entry->ie_bits = bits;
469 	OBJECT_CLEAR(entry, name);
470 	return TRUE;
471 }
472 
473 /*
474  *	Routine:	ipc_right_clean
475  *	Purpose:
476  *		Cleans up an entry in a dead space.
477  *		The entry isn't deallocated or removed
478  *		from reverse hash tables.
479  *	Conditions:
480  *		The space is dead and unlocked.
481  */
482 
483 void
ipc_right_clean(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)484 ipc_right_clean(
485 	ipc_space_t	space,
486 	mach_port_name_t	name,
487 	ipc_entry_t	entry)
488 {
489 	ipc_entry_bits_t bits = entry->ie_bits;
490 	mach_port_type_t type = IE_BITS_TYPE(bits);
491 
492 	assert(!space->is_active);
493 
494 	/*
495 	 *	IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
496 	 *	problem, because we check that the port is active.  If
497 	 *	we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
498 	 *	would still work, but dead space refs would accumulate
499 	 *	in ip_dnrequests.  They would use up slots in
500 	 *	ip_dnrequests and keep the spaces from being freed.
501 	 */
502 
503 	switch (type) {
504 	    case MACH_PORT_TYPE_DEAD_NAME:
505 		assert(entry->ie_request == 0);
506 		assert(entry->ie_object == IO_NULL);
507 		break;
508 
509 	    case MACH_PORT_TYPE_PORT_SET: {
510 		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
511 
512 		assert(entry->ie_request == 0);
513 		assert(pset != IPS_NULL);
514 		assert(ips_active(pset));
515 
516 		sx_slock(&pset->ips_note_lock);
517 		KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
518 		sx_sunlock(&pset->ips_note_lock);
519 		ipc_entry_close(space, name);
520 		break;
521 	    }
522 
523 	    case MACH_PORT_TYPE_SEND:
524 	    case MACH_PORT_TYPE_RECEIVE:
525 	    case MACH_PORT_TYPE_SEND_RECEIVE:
526 	    case MACH_PORT_TYPE_SEND_ONCE: {
527 		ipc_port_t port = (ipc_port_t) entry->ie_object;
528 		ipc_port_t dnrequest;
529 		ipc_port_t nsrequest = IP_NULL;
530 		mach_port_mscount_t mscount;
531 
532 		assert(port != IP_NULL);
533 		ip_lock(port);
534 
535 		if (!ip_active(port)) {
536 			ip_unlock(port);
537 			ip_release(port);
538 			break;
539 		}
540 
541 		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
542 
543 		if (type & MACH_PORT_TYPE_SEND) {
544 			assert(port->ip_srights > 0);
545 			if (--port->ip_srights == 0
546 			    ) {
547 				nsrequest = port->ip_nsrequest;
548 				if (nsrequest != IP_NULL) {
549 					port->ip_nsrequest = IP_NULL;
550 					mscount = port->ip_mscount;
551 				}
552 			}
553 		}
554 
555 		if (type & MACH_PORT_TYPE_RECEIVE) {
556 			assert(port->ip_receiver_name == name);
557 			assert(port->ip_receiver == space);
558 
559 			ipc_port_clear_receiver(port);
560 			ipc_port_destroy(port); /* consumes our ref, unlocks */
561 		} else if (type & MACH_PORT_TYPE_SEND_ONCE) {
562 			assert(port->ip_sorights > 0);
563 			ip_unlock(port);
564 
565 			ipc_notify_send_once(port); /* consumes our ref */
566 		} else {
567 			assert(port->ip_receiver != space);
568 
569 			ip_unlock(port); /* port is active */
570 			ip_release(port);
571 		}
572 
573 		if (nsrequest != IP_NULL)
574 			ipc_notify_no_senders(nsrequest, mscount);
575 
576 		if (dnrequest != IP_NULL)
577 			ipc_notify_port_deleted(dnrequest, name);
578 		break;
579 	    }
580 
581 	    default:
582 		panic("ipc_right_clean: strange type");
583 	}
584 }
585 
586 /*
587  *	Routine:	ipc_right_destroy
588  *	Purpose:
589  *		Destroys an entry in a space.
590  *	Conditions:
591  *		The space is write-locked, and is unlocked upon return.
592  *		The space must be active.
593  *	Returns:
594  *		KERN_SUCCESS		The entry was destroyed.
595  */
596 
597 kern_return_t
ipc_right_destroy(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)598 ipc_right_destroy(
599 	ipc_space_t	space,
600 	mach_port_name_t	name,
601 	ipc_entry_t	entry)
602 {
603 	ipc_entry_bits_t bits = entry->ie_bits;
604 	mach_port_type_t type = IE_BITS_TYPE(bits);
605 
606 	assert(space->is_active);
607 
608 	switch (type) {
609 	    case MACH_PORT_TYPE_DEAD_NAME:
610 		assert(entry->ie_request == 0);
611 		assert(entry->ie_object == IO_NULL);
612 
613 		ipc_entry_dealloc(space, name, entry);
614 		is_write_unlock(space);
615 		break;
616 
617 	    case MACH_PORT_TYPE_PORT_SET: {
618 		ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
619 
620 		assert(entry->ie_request == 0);
621 		assert(pset != IPS_NULL);
622 
623 
624 		is_write_unlock(space);
625 
626 		assert(ips_active(pset));
627 		sx_slock(&pset->ips_note_lock);
628 		KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
629 		sx_sunlock(&pset->ips_note_lock);
630 		ipc_entry_close(space, name);
631 
632 		break;
633 	    }
634 
635 	    case MACH_PORT_TYPE_SEND:
636 	    case MACH_PORT_TYPE_RECEIVE:
637 	    case MACH_PORT_TYPE_SEND_RECEIVE:
638 	    case MACH_PORT_TYPE_SEND_ONCE: {
639 		ipc_port_t port = (ipc_port_t) entry->ie_object;
640 		ipc_port_t nsrequest = IP_NULL;
641 		mach_port_mscount_t mscount;
642 		ipc_port_t dnrequest;
643 
644 		assert(port != IP_NULL);
645 
646 		if (type == MACH_PORT_TYPE_SEND)
647 			ipc_hash_delete(space, (ipc_object_t) port,
648 					name, entry);
649 
650 		ip_lock(port);
651 
652 		if (!ip_active(port)) {
653 			assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
654 			ip_unlock(port);
655 			ip_release(port);
656 
657 			entry->ie_request = 0;
658 			OBJECT_CLEAR(entry, name);
659 			ipc_entry_dealloc(space, name, entry);
660 			is_write_unlock(space);
661 			break;
662 		}
663 
664 		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
665 
666 		OBJECT_CLEAR(entry, name);
667 		ipc_entry_dealloc(space, name, entry);
668 		is_write_unlock(space);
669 
670 		if (type & MACH_PORT_TYPE_SEND) {
671 			assert(port->ip_srights > 0);
672 			if (--port->ip_srights == 0
673 			    ) {
674 				nsrequest = port->ip_nsrequest;
675 				if (nsrequest != IP_NULL) {
676 					port->ip_nsrequest = IP_NULL;
677 					mscount = port->ip_mscount;
678 				}
679 			}
680 		}
681 
682 		if (type & MACH_PORT_TYPE_RECEIVE) {
683 			assert(ip_active(port));
684 			assert(port->ip_receiver == space);
685 
686 			ipc_port_clear_receiver(port);
687 			ipc_port_destroy(port); /* consumes our ref, unlocks */
688 		} else if (type & MACH_PORT_TYPE_SEND_ONCE) {
689 			assert(port->ip_sorights > 0);
690 			ip_unlock(port);
691 
692 			ipc_notify_send_once(port); /* consumes our ref */
693 		} else {
694 			assert(port->ip_receiver != space);
695 
696 			ip_unlock(port);
697 			ip_release(port);
698 		}
699 
700 		if (nsrequest != IP_NULL)
701 			ipc_notify_no_senders(nsrequest, mscount);
702 
703 		if (dnrequest != IP_NULL)
704 			ipc_notify_port_deleted(dnrequest, name);
705 		break;
706 	    }
707 
708 	    default:
709 		panic("ipc_right_destroy: strange type");
710 	}
711 
712 	return KERN_SUCCESS;
713 }
714 
715 /*
716  *	Routine:	ipc_right_dealloc
717  *	Purpose:
718  *		Releases a send/send-once/dead-name user ref.
719  *		Like ipc_right_delta with a delta of -1,
720  *		but looks at the entry to determine the right.
721  *	Conditions:
722  *		The space is write-locked, and is unlocked upon return.
723  *		The space must be active.
724  *	Returns:
725  *		KERN_SUCCESS		A user ref was released.
726  *		KERN_INVALID_RIGHT	Entry has wrong type.
727  */
728 
729 kern_return_t
ipc_right_dealloc(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry)730 ipc_right_dealloc(
731 	ipc_space_t	space,
732 	mach_port_name_t	name,
733 	ipc_entry_t	entry)
734 {
735 	ipc_entry_bits_t bits = entry->ie_bits;
736 	mach_port_type_t type = IE_BITS_TYPE(bits);
737 
738 	assert(space->is_active);
739 
740 	switch (type) {
741 	case MACH_PORT_TYPE_DEAD_NAME: {
742 	    dead_name:
743 
744 		assert(ipc_entry_refs(entry) > 0);
745 		assert(entry->ie_request == 0);
746 		assert(entry->ie_object == IO_NULL);
747 
748 		if (ipc_entry_refs(entry) > 1) {
749 			ipc_entry_release(entry);
750 			is_write_unlock(space);
751 		} else
752 			ipc_entry_dealloc(space, name, entry);
753 
754 		break;
755 	    }
756 
757 	    case MACH_PORT_TYPE_SEND_ONCE: {
758 		ipc_port_t port, dnrequest;
759 
760 		MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
761 		port = (ipc_port_t) entry->ie_object;
762 		assert(port != IP_NULL);
763 
764 		if (ipc_right_check(space, port, name, entry)) {
765 
766 			bits = entry->ie_bits;
767 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
768 			goto dead_name;
769 		}
770 		/* port is locked and active */
771 
772 		assert(port->ip_sorights > 0);
773 
774 		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
775 		ip_unlock(port);
776 
777 		OBJECT_CLEAR(entry, name);
778 		/* drops the lock */
779 		ipc_entry_dealloc(space, name, entry);
780 
781 		ipc_notify_send_once(port);
782 
783 		if (dnrequest != IP_NULL)
784 			ipc_notify_port_deleted(dnrequest, name);
785 		break;
786 	    }
787 
788 	    case MACH_PORT_TYPE_SEND: {
789 		ipc_port_t port;
790 		ipc_port_t dnrequest = IP_NULL;
791 		ipc_port_t nsrequest = IP_NULL;
792 		mach_port_mscount_t mscount;
793 
794 
795 		assert(ipc_entry_refs(entry) > 0);
796 
797 		port = (ipc_port_t) entry->ie_object;
798 		assert(port != IP_NULL);
799 
800 		if (ipc_right_check(space, port, name, entry)) {
801 			bits = entry->ie_bits;
802 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
803 			goto dead_name;
804 		}
805 		/* port is locked and active */
806 
807 		assert(port->ip_srights > 0);
808 
809 		if (ipc_entry_refs(entry) > 1) {
810 			ip_unlock(port);
811 			ipc_entry_release(entry); /* decrement urefs */
812 			is_write_unlock(space);
813 		} else {
814 			if (--port->ip_srights == 0
815 			    ) {
816 				nsrequest = port->ip_nsrequest;
817 				if (nsrequest != IP_NULL) {
818 					port->ip_nsrequest = IP_NULL;
819 					mscount = port->ip_mscount;
820 				}
821 
822 			}
823 
824 			dnrequest = ipc_right_dncancel_macro(space, port,
825 							     name, entry);
826 
827 			ipc_hash_delete(space, (ipc_object_t) port,
828 					name, entry);
829 			ip_unlock(port);
830 			ip_release(port);
831 			OBJECT_CLEAR(entry, name);
832 			/* drops the space lock */
833 			ipc_entry_dealloc(space, name, entry);
834 		}
835 		/* even if dropped a ref, port is active */
836 
837 
838 		if (nsrequest != IP_NULL)
839 			ipc_notify_no_senders(nsrequest, mscount);
840 
841 		if (dnrequest != IP_NULL)
842 			ipc_notify_port_deleted(dnrequest, name);
843 		break;
844 	    }
845 
846 	    case MACH_PORT_TYPE_SEND_RECEIVE: {
847 		ipc_port_t port;
848 		ipc_port_t nsrequest = IP_NULL;
849 		mach_port_mscount_t mscount;
850 
851 		assert(ipc_entry_refs(entry) > 0);
852 
853 		port = (ipc_port_t) entry->ie_object;
854 		assert(port != IP_NULL);
855 
856 		ip_lock(port);
857 		assert(ip_active(port));
858 		assert(port->ip_receiver_name == name);
859 		assert(port->ip_receiver == space);
860 		assert(port->ip_srights > 0);
861 
862 		if (ipc_entry_refs(entry) > 1) {
863 			ipc_entry_release(entry);
864 		} else {
865 			if (--port->ip_srights == 0
866 			    ) {
867 				nsrequest = port->ip_nsrequest;
868 				if (nsrequest != IP_NULL) {
869 					port->ip_nsrequest = IP_NULL;
870 					mscount = port->ip_mscount;
871 				}
872 			}
873 
874 			entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
875 						  MACH_PORT_TYPE_SEND);
876 		}
877 
878 		ip_unlock(port);
879 		is_write_unlock(space);
880 
881 		if (nsrequest != IP_NULL)
882 			ipc_notify_no_senders(nsrequest, mscount);
883 		break;
884 	    }
885 
886 	    default:
887 		is_write_unlock(space);
888 		return KERN_INVALID_RIGHT;
889 	}
890 
891 	return KERN_SUCCESS;
892 }
893 
894 /*
895  *	Routine:	ipc_right_delta
896  *	Purpose:
897  *		Modifies the user-reference count for a right.
898  *		May deallocate the right, if the count goes to zero.
899  *	Conditions:
900  *		The space is write-locked, and is unlocked upon return.
901  *		The space must be active.
902  *	Returns:
903  *		KERN_SUCCESS		Count was modified.
904  *		KERN_INVALID_RIGHT	Entry has wrong type.
905  *		KERN_INVALID_VALUE	Bad delta for the right.
906  */
907 
908 kern_return_t
ipc_right_delta(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_port_right_t right,mach_port_delta_t delta)909 ipc_right_delta(
910 	ipc_space_t		space,
911 	mach_port_name_t		name,
912 	ipc_entry_t		entry,
913 	mach_port_right_t	right,
914 	mach_port_delta_t	delta)
915 {
916 	ipc_entry_bits_t bits = entry->ie_bits;
917 
918 /*
919  *	The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
920  *	switch below. It is used to keep track of those cases (in DIPC)
921  *	where we have postponed the dropping of a port reference. Since
922  *	the dropping of the reference could cause the port to disappear
923  *	we postpone doing so when we are holding the space lock.
924  */
925 
926 
927 	assert(space->is_active);
928 	assert(right < MACH_PORT_RIGHT_NUMBER);
929 
930 	/* Rights-specific restrictions and operations. */
931 
932 	switch (right) {
933 	    case MACH_PORT_RIGHT_PORT_SET: {
934 		ipc_pset_t pset;
935 
936 		if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
937 			goto invalid_right;
938 
939 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
940 		assert(IE_BITS_UREFS(bits) == 0);
941 		assert(entry->ie_request == 0);
942 
943 		if (delta == 0)
944 			goto success;
945 
946 		if (delta != -1)
947 			goto invalid_value;
948 
949 		pset = (ipc_pset_t) entry->ie_object;
950 		assert(pset != IPS_NULL);
951 		assert(ips_active(pset));
952 
953 		/* space must be unlocked when calling KNOTE & close */
954 		is_write_unlock(space);
955 
956 		sx_slock(&pset->ips_note_lock);
957 		KNOTE(&pset->ips_note, EV_EOF, KNF_LISTLOCKED);
958 		sx_sunlock(&pset->ips_note_lock);
959 
960 		ipc_entry_close(space, name);
961 
962 		break;
963 	    }
964 
965 	    case MACH_PORT_RIGHT_RECEIVE: {
966 		ipc_port_t port;
967 		ipc_port_t dnrequest = IP_NULL;
968 
969 		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
970 			goto invalid_right;
971 
972 		if (delta == 0)
973 			goto success;
974 
975 		if (delta != -1)
976 			goto invalid_value;
977 
978 		port = (ipc_port_t) entry->ie_object;
979 		assert(port != IP_NULL);
980 
981 		/*
982 		 *	The port lock is needed for ipc_right_dncancel;
983 		 *	otherwise, we wouldn't have to take the lock
984 		 *	until just before dropping the space lock.
985 		 */
986 
987 		ip_lock(port);
988 		assert(ip_active(port));
989 		assert(port->ip_receiver_name == name);
990 		assert(port->ip_receiver == space);
991 
992 		if (bits & MACH_PORT_TYPE_SEND) {
993 			assert(IE_BITS_TYPE(bits) ==
994 					MACH_PORT_TYPE_SEND_RECEIVE);
995 			assert(ipc_entry_refs(entry) > 0);
996 			assert(port->ip_srights > 0);
997 
998 			/*
999 			 *	The remaining send right turns into a
1000 			 *	dead name.  Notice we don't decrement
1001 			 *	ip_srights, generate a no-senders notif,
1002 			 *	or use ipc_right_dncancel, because the
1003 			 *	port is destroyed "first".
1004 			 */
1005 
1006 			bits &= ~IE_BITS_TYPE_MASK;
1007 			bits |= MACH_PORT_TYPE_DEAD_NAME;
1008 
1009 			if (entry->ie_request != 0) {
1010 				entry->ie_request = 0;
1011 				ipc_entry_hold(entry); /* increment urefs */
1012 			}
1013 
1014 			entry->ie_bits = bits;
1015 			OBJECT_CLEAR(entry, name);
1016 			is_write_unlock(space);
1017 		} else {
1018 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1019 
1020 			dnrequest = ipc_right_dncancel_macro(space, port,
1021 							     name, entry);
1022 			OBJECT_CLEAR(entry, name);
1023 			/* drops the space lock */
1024 			ipc_entry_dealloc(space, name, entry);
1025 		}
1026 
1027 
1028 		ipc_port_clear_receiver(port);
1029 		ipc_port_destroy(port);	/* consumes ref, unlocks */
1030 
1031 		if (dnrequest != IP_NULL)
1032 			ipc_notify_port_deleted(dnrequest, name);
1033 		break;
1034 	    }
1035 
1036 	    case MACH_PORT_RIGHT_SEND_ONCE: {
1037 		ipc_port_t port, dnrequest;
1038 
1039 		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1040 			goto invalid_right;
1041 
1042 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1043 		MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
1044 
1045 		port = (ipc_port_t) entry->ie_object;
1046 		assert(port != IP_NULL);
1047 
1048 		if (ipc_right_check(space, port, name, entry)) {
1049 			assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1050 			goto invalid_right;
1051 		}
1052 		/* port is locked and active */
1053 
1054 		assert(port->ip_sorights > 0);
1055 
1056 		if ((delta > 0) || (delta < -1)) {
1057 			ip_unlock(port);
1058 			goto invalid_value;
1059 		}
1060 
1061 		if (delta == 0) {
1062 			ip_unlock(port);
1063 			goto success;
1064 		}
1065 
1066 		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1067 		ip_unlock(port);
1068 
1069 		OBJECT_CLEAR(entry, name);
1070 		/* drops the space lock */
1071 		ipc_entry_dealloc(space, name, entry);
1072 
1073 		ipc_notify_send_once(port);
1074 
1075 		if (dnrequest != IP_NULL)
1076 			ipc_notify_port_deleted(dnrequest, name);
1077 		break;
1078 	    }
1079 
1080 	    case MACH_PORT_RIGHT_DEAD_NAME: {
1081 		mach_port_urefs_t urefs;
1082 
1083 		if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1084 			ipc_port_t port;
1085 
1086 			port = (ipc_port_t) entry->ie_object;
1087 			assert(port != IP_NULL);
1088 			if (!ipc_right_check(space, port, name, entry)) {
1089 				/* port is locked and active */
1090 				ip_unlock(port);
1091 				goto invalid_right;
1092 			}
1093 			bits = entry->ie_bits;
1094 		} else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1095 			goto invalid_right;
1096 
1097 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1098 		assert(ipc_entry_refs(entry) > 0);
1099 		assert(entry->ie_object == IO_NULL);
1100 		assert(entry->ie_request == 0);
1101 
1102 		urefs = ipc_entry_refs(entry);
1103 		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1104 			goto invalid_value;
1105 
1106 		if ((urefs + delta) == 0) {
1107 			/* drops the space lock */
1108 			ipc_entry_dealloc(space, name, entry);
1109 		} else {
1110 			ipc_entry_add_refs(entry, delta);
1111 			is_write_unlock(space);
1112 		}
1113 		break;
1114 	    }
1115 
1116 	    case MACH_PORT_RIGHT_SEND: {
1117 		mach_port_urefs_t urefs;
1118 		ipc_port_t port;
1119 		ipc_port_t dnrequest = IP_NULL;
1120 		ipc_port_t nsrequest = IP_NULL;
1121 		mach_port_mscount_t mscount;
1122 
1123 		if ((bits & MACH_PORT_TYPE_SEND) == 0)
1124 			goto invalid_right;
1125 
1126 		/* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1127 
1128 		port = (ipc_port_t) entry->ie_object;
1129 		assert(port != IP_NULL);
1130 
1131 		if (ipc_right_check(space, port, name, entry)) {
1132 			assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1133 			goto invalid_right;
1134 		}
1135 		/* port is locked and active */
1136 
1137 		assert(port->ip_srights > 0);
1138 
1139 		urefs = ipc_entry_refs(entry);
1140 		if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1141 			ip_unlock(port);
1142 			goto invalid_value;
1143 		}
1144 
1145 		if ((urefs + delta) == 0) {
1146 			if (--port->ip_srights == 0
1147 			    ) {
1148 				nsrequest = port->ip_nsrequest;
1149 				if (nsrequest != IP_NULL) {
1150 					port->ip_nsrequest = IP_NULL;
1151 					mscount = port->ip_mscount;
1152 				}
1153 			}
1154 
1155 			if (bits & MACH_PORT_TYPE_RECEIVE) {
1156 				assert(port->ip_receiver_name == name);
1157 				assert(port->ip_receiver == space);
1158 				assert(IE_BITS_TYPE(bits) ==
1159 						MACH_PORT_TYPE_SEND_RECEIVE);
1160 
1161 				entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1162 										  MACH_PORT_TYPE_SEND);
1163 				ip_unlock(port);
1164 				is_write_unlock(space);
1165 
1166 			} else {
1167 				assert(IE_BITS_TYPE(bits) ==
1168 						MACH_PORT_TYPE_SEND);
1169 
1170 				dnrequest = ipc_right_dncancel_macro(
1171 						space, port, name, entry);
1172 
1173 				ipc_hash_delete(space, (ipc_object_t) port,
1174 						name, entry);
1175 				ip_unlock(port);
1176 				ip_release(port);
1177 				OBJECT_CLEAR(entry, name);
1178 				/* drops the space lock */
1179 				ipc_entry_dealloc(space, name, entry);
1180 			}
1181 		} else {
1182 			is_write_unlock(space);
1183 			ip_unlock(port);
1184 			ipc_entry_add_refs(entry, delta);
1185 		}
1186 		/* even if dropped a ref, port is active */
1187 
1188 
1189 		if (nsrequest != IP_NULL)
1190 			ipc_notify_no_senders(nsrequest, mscount);
1191 
1192 		if (dnrequest != IP_NULL)
1193 			ipc_notify_port_deleted(dnrequest, name);
1194 		break;
1195 	    }
1196 
1197 	    default:
1198 		panic("ipc_right_delta: strange right");
1199 	}
1200 
1201 	return KERN_SUCCESS;
1202 
1203     success:
1204 	is_write_unlock(space);
1205 	return KERN_SUCCESS;
1206 
1207     invalid_right:
1208 	is_write_unlock(space);
1209 	return KERN_INVALID_RIGHT;
1210 
1211     invalid_value:
1212 	is_write_unlock(space);
1213 	return KERN_INVALID_VALUE;
1214 }
1215 
1216 /*
1217  *	Routine:	ipc_right_info
1218  *	Purpose:
1219  *		Retrieves information about the right.
1220  *	Conditions:
1221  *		The space is write-locked, and is unlocked upon return
1222  *		if the call is unsuccessful.  The space must be active.
1223  *	Returns:
1224  *		KERN_SUCCESS		Retrieved info; space still locked.
1225  */
1226 
1227 kern_return_t
ipc_right_info(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_port_type_t * typep,mach_port_urefs_t * urefsp)1228 ipc_right_info(
1229 	ipc_space_t		space,
1230 	mach_port_name_t		name,
1231 	ipc_entry_t		entry,
1232 	mach_port_type_t	*typep,
1233 	mach_port_urefs_t	*urefsp)
1234 {
1235 	ipc_entry_bits_t bits = entry->ie_bits;
1236 	ipc_port_request_index_t request;
1237 	mach_port_type_t type;
1238 
1239 	if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1240 		ipc_port_t port = (ipc_port_t) entry->ie_object;
1241 
1242 		if (ipc_right_check(space, port, name, entry)) {
1243 			bits = entry->ie_bits;
1244 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1245 		} else
1246 			ip_unlock(port);
1247 	}
1248 
1249 	type = IE_BITS_TYPE(bits);
1250 	request = entry->ie_request;
1251 
1252 	if (request != 0)
1253 		type |= MACH_PORT_TYPE_DNREQUEST;
1254 
1255 	*typep = type;
1256 	*urefsp = ipc_entry_refs(entry);
1257 	return KERN_SUCCESS;
1258 }
1259 
1260 /*
1261  *	Routine:	ipc_right_copyin_check
1262  *	Purpose:
1263  *		Check if a subsequent ipc_right_copyin (for receiver) would succeed.
1264  *	Conditions:
1265  *		The space is locked (read or write) and active.
1266  */
1267 
1268 boolean_t
ipc_right_copyin_check(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name)1269 ipc_right_copyin_check(
1270 	ipc_space_t		space,
1271 	mach_port_name_t		name,
1272 	ipc_entry_t		entry,
1273 	mach_msg_type_name_t	msgt_name)
1274 {
1275 	ipc_port_t port = (ipc_port_t) entry->ie_object;
1276 	ipc_entry_bits_t bits = entry->ie_bits;
1277 
1278 	assert(space->is_active);
1279 
1280 	switch (msgt_name) {
1281 	    case MACH_MSG_TYPE_MAKE_SEND:
1282 	    case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1283 	    case MACH_MSG_TYPE_MOVE_RECEIVE:
1284 		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1285 			return FALSE;
1286 		if (port == NULL)
1287 			return (FALSE);
1288 		if (port->ip_receiver != space)
1289 			return (FALSE);
1290 		break;
1291 
1292 	    case MACH_MSG_TYPE_COPY_SEND:
1293 	    case MACH_MSG_TYPE_MOVE_SEND:
1294 	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1295 		boolean_t active;
1296 
1297 		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1298 			break;
1299 
1300 		if (port == NULL)
1301 			return (FALSE);
1302 		if (port->ip_receiver != space)
1303 			return (FALSE);
1304 
1305 		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1306 			return FALSE;
1307 
1308 		ip_lock(port);
1309 		active = ip_active(port);
1310 		ip_unlock(port);
1311 
1312 		if (!active) {
1313 			break;
1314 		}
1315 
1316 		if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1317 			if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1318 				return FALSE;
1319 		} else {
1320 			if ((bits & MACH_PORT_TYPE_SEND) == 0)
1321 				return FALSE;
1322 		}
1323 
1324 		break;
1325 	    }
1326 
1327 	    default:
1328 		panic("ipc_right_copyin_check: strange rights");
1329 	}
1330 
1331 	return TRUE;
1332 }
1333 
1334 /*
1335  *	Routine:	ipc_right_copyin
1336  *	Purpose:
1337  *		Copyin a capability from a space.
1338  *		If successful, the caller gets a ref
1339  *		for the resulting object, unless it is IO_DEAD,
1340  *		and possibly a send-once right which should
1341  *		be used in a port-deleted notification.
1342  *
1343  *		If deadok is not TRUE, the copyin operation
1344  *		will fail instead of producing IO_DEAD.
1345  *
1346  *		The entry is never deallocated (except
1347  *		when KERN_INVALID_NAME), so the caller
1348  *		should deallocate the entry if its type
1349  *		is MACH_PORT_TYPE_NONE.
1350  *	Conditions:
1351  *		The space is write-locked and active.
1352  *	Returns:
1353  *		KERN_SUCCESS		Acquired an object, possibly IO_DEAD.
1354  *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
1355  */
1356 
1357 #define ELOG printf("%s:%d bits: %08x\n", __FILE__, __LINE__, bits)
1358 
1359 kern_return_t
ipc_right_copyin(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,boolean_t deadok,ipc_object_t * objectp,ipc_port_t * sorightp)1360 ipc_right_copyin(
1361 	ipc_space_t		space,
1362 	mach_port_name_t		name,
1363 	ipc_entry_t		entry,
1364 	mach_msg_type_name_t	msgt_name,
1365 	boolean_t		deadok,
1366 	ipc_object_t		*objectp,
1367 	ipc_port_t		*sorightp)
1368 {
1369 	ipc_entry_bits_t bits = entry->ie_bits;
1370 
1371 	assert(space->is_active);
1372 
1373 	switch (msgt_name) {
1374 	    case MACH_MSG_TYPE_MAKE_SEND: {
1375 		ipc_port_t port;
1376 
1377 		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1378 			ELOG;
1379 			goto invalid_right;
1380 		}
1381 		port = (ipc_port_t) entry->ie_object;
1382 		assert(port != IP_NULL);
1383 
1384 		ip_lock(port);
1385 		assert(ip_active(port));
1386 		assert(port->ip_receiver_name == name);
1387 		assert(port->ip_receiver == space);
1388 
1389 		port->ip_mscount++;
1390 		port->ip_srights++;
1391 		ip_reference(port);
1392 		ip_unlock(port);
1393 
1394 		*objectp = (ipc_object_t) port;
1395 		*sorightp = IP_NULL;
1396 		break;
1397 	    }
1398 
1399 	    case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1400 		ipc_port_t port;
1401 
1402 		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1403 			ELOG;
1404 			goto invalid_right;
1405 		}
1406 		port = (ipc_port_t) entry->ie_object;
1407 		assert(port != IP_NULL);
1408 
1409 		ip_lock(port);
1410 		assert(ip_active(port));
1411 		assert(port->ip_receiver_name == name);
1412 		assert(port->ip_receiver == space);
1413 
1414 		port->ip_sorights++;
1415 		ip_reference(port);
1416 		ip_unlock(port);
1417 
1418 		*objectp = (ipc_object_t) port;
1419 		*sorightp = IP_NULL;
1420 		break;
1421 	    }
1422 
1423 	    case MACH_MSG_TYPE_MOVE_RECEIVE: {
1424 		ipc_port_t port;
1425 		ipc_port_t dnrequest = IP_NULL;
1426 
1427 		if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1428 			ELOG;
1429 			goto invalid_right;
1430 		}
1431 		port = (ipc_port_t) entry->ie_object;
1432 		assert(port != IP_NULL);
1433 
1434 		ip_lock(port);
1435 		assert(ip_active(port));
1436 		assert(port->ip_receiver_name == name);
1437 		assert(port->ip_receiver == space);
1438 
1439 		if (bits & MACH_PORT_TYPE_SEND) {
1440 			assert(IE_BITS_TYPE(bits) ==
1441 					MACH_PORT_TYPE_SEND_RECEIVE);
1442 			assert(ipc_entry_refs(entry) > 0);
1443 			assert(port->ip_srights > 0);
1444 
1445 			ipc_hash_insert(space, (ipc_object_t) port,
1446 					name, entry);
1447 
1448 			ip_reference(port);
1449 		} else {
1450 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1451 			assert(IE_BITS_UREFS(bits) == 0);
1452 
1453 			dnrequest = ipc_right_dncancel_macro(space, port,
1454 							     name, entry);
1455 
1456 			OBJECT_CLEAR(entry, name);
1457 		}
1458 		entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1459 
1460 		ipc_port_clear_receiver(port);
1461 
1462 		port->ip_receiver_name = MACH_PORT_NAME_NULL;
1463 		port->ip_destination = IP_NULL;
1464 		ip_unlock(port);
1465 
1466 		*objectp = (ipc_object_t) port;
1467 		*sorightp = dnrequest;
1468 		break;
1469 	    }
1470 
1471 	    case MACH_MSG_TYPE_COPY_SEND: {
1472 		ipc_port_t port;
1473 
1474 		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1475 			goto copy_dead;
1476 
1477 		/* allow for dead send-once rights */
1478 
1479 		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1480 			goto invalid_right;
1481 		}
1482 		assert(ipc_entry_refs(entry) > 0);
1483 
1484 		port = (ipc_port_t) entry->ie_object;
1485 		assert(port != IP_NULL);
1486 
1487 		if (ipc_right_check(space, port, name, entry)) {
1488 			bits = entry->ie_bits;
1489 			goto copy_dead;
1490 		}
1491 		/* port is locked and active */
1492 
1493 		if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1494 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1495 			assert(port->ip_sorights > 0);
1496 
1497 			ip_unlock(port);
1498 			ELOG;
1499 			goto invalid_right;
1500 		}
1501 
1502 		assert(port->ip_srights > 0);
1503 
1504 		port->ip_srights++;
1505 		ip_reference(port);
1506 		ip_unlock(port);
1507 
1508 		*objectp = (ipc_object_t) port;
1509 		*sorightp = IP_NULL;
1510 		break;
1511 	    }
1512 
1513 	    case MACH_MSG_TYPE_MOVE_SEND: {
1514 		ipc_port_t port;
1515 		ipc_port_t dnrequest = IP_NULL;
1516 
1517 		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1518 			goto move_dead;
1519 
1520 		/* allow for dead send-once rights */
1521 
1522 		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1523 			ELOG;
1524 			goto invalid_right;
1525 		}
1526 		assert(ipc_entry_refs(entry) > 0);
1527 
1528 		port = (ipc_port_t) entry->ie_object;
1529 		assert(port != IP_NULL);
1530 
1531 		if (ipc_right_check(space, port, name, entry)) {
1532 			bits = entry->ie_bits;
1533 			goto move_dead;
1534 		}
1535 		/* port is locked and active */
1536 
1537 		if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1538 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1539 			assert(port->ip_sorights > 0);
1540 
1541 			ip_unlock(port);
1542 			ELOG;
1543 			goto invalid_right;
1544 		}
1545 
1546 		assert(port->ip_srights > 0);
1547 
1548 		if (ipc_entry_refs(entry) == 1) {
1549 			if (bits & MACH_PORT_TYPE_RECEIVE) {
1550 				assert(port->ip_receiver_name == name);
1551 				assert(port->ip_receiver == space);
1552 				assert(IE_BITS_TYPE(bits) ==
1553 						MACH_PORT_TYPE_SEND_RECEIVE);
1554 
1555 				ip_reference(port);
1556 			} else {
1557 				assert(IE_BITS_TYPE(bits) ==
1558 						MACH_PORT_TYPE_SEND);
1559 
1560 				dnrequest = ipc_right_dncancel_macro(
1561 						space, port, name, entry);
1562 
1563 				ipc_hash_delete(space, (ipc_object_t) port,
1564 								name, entry);
1565 				OBJECT_CLEAR(entry, name);
1566 			}
1567 			entry->ie_bits = bits &~
1568 				(IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1569 		} else {
1570 			MPASS(ipc_entry_refs(entry) > 1);
1571 			port->ip_srights++;
1572 			ip_reference(port);
1573 			ipc_entry_release(entry); /* decrement urefs */
1574 		}
1575 
1576 		ip_unlock(port);
1577 
1578 		*objectp = (ipc_object_t) port;
1579 		*sorightp = dnrequest;
1580 		break;
1581 	    }
1582 
1583 	    case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1584 		ipc_port_t port;
1585 		ipc_port_t dnrequest;
1586 
1587 		if (bits & MACH_PORT_TYPE_DEAD_NAME)
1588 			goto move_dead;
1589 
1590 		/* allow for dead send rights */
1591 
1592 		if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1593 			ELOG;
1594 			goto invalid_right;
1595 		}
1596 		assert(ipc_entry_refs(entry) > 0);
1597 
1598 		port = (ipc_port_t) entry->ie_object;
1599 		assert(port != IP_NULL);
1600 
1601 		if (ipc_right_check(space, port, name, entry)) {
1602 			bits = entry->ie_bits;
1603 			ELOG;
1604 			goto move_dead;
1605 		}
1606 		/* port is locked and active */
1607 
1608 		if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1609 			assert(bits & MACH_PORT_TYPE_SEND);
1610 			assert(port->ip_srights > 0);
1611 
1612 			ip_unlock(port);
1613 			ELOG;
1614 			goto invalid_right;
1615 		}
1616 
1617 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1618 		MACH_VERIFY(ipc_entry_refs(entry) == 1, ("urefs expected 1 got %d", ipc_entry_refs(entry)));
1619 		assert(port->ip_sorights > 0);
1620 
1621 		dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1622 		ip_unlock(port);
1623 
1624 		OBJECT_CLEAR(entry, name);
1625 		entry->ie_bits = bits &~ MACH_PORT_TYPE_SEND_ONCE;
1626 
1627 		*objectp = (ipc_object_t) port;
1628 		*sorightp = dnrequest;
1629 		break;
1630 	    }
1631 
1632 	    default:
1633 		panic("ipc_right_copyin: strange rights");
1634 	}
1635 
1636 	return KERN_SUCCESS;
1637 
1638     copy_dead:
1639 	assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1640 	assert(ipc_entry_refs(entry) > 0);
1641 	assert(entry->ie_request == 0);
1642 	assert(entry->ie_object == 0);
1643 
1644 	if (!deadok) {
1645 		ELOG;
1646 		goto invalid_right;
1647 	}
1648 	*objectp = IO_DEAD;
1649 	*sorightp = IP_NULL;
1650 	return KERN_SUCCESS;
1651 
1652     move_dead:
1653 	assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1654 	assert(ipc_entry_refs(entry) > 0);
1655 	assert(entry->ie_request == 0);
1656 	assert(entry->ie_object == 0);
1657 
1658 	if (!deadok) {
1659 		ELOG;
1660 		goto invalid_right;
1661 	}
1662 	if (ipc_entry_refs(entry) > 1)
1663 		ipc_entry_release(entry); /* decrement urefs */
1664 	else
1665 		entry->ie_bits = bits &~ MACH_PORT_TYPE_DEAD_NAME;
1666 
1667 	*objectp = IO_DEAD;
1668 	*sorightp = IP_NULL;
1669 	return KERN_SUCCESS;
1670 
1671     invalid_right:
1672 	return KERN_INVALID_RIGHT;
1673 }
1674 
1675 /*
1676  *	Routine:	ipc_right_copyin_undo
1677  *	Purpose:
1678  *		Undoes the effects of an ipc_right_copyin
1679  *		of a send/send-once right that is dead.
1680  *		(Object is either IO_DEAD or a dead port.)
1681  *	Conditions:
1682  *		The space is write-locked and active.
1683  */
1684 
1685 void
ipc_right_copyin_undo(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,ipc_object_t object,ipc_port_t soright)1686 ipc_right_copyin_undo(
1687 	ipc_space_t		space,
1688 	mach_port_name_t		name,
1689 	ipc_entry_t		entry,
1690 	mach_msg_type_name_t	msgt_name,
1691 	ipc_object_t		object,
1692 	ipc_port_t		soright)
1693 {
1694 	ipc_entry_bits_t bits = entry->ie_bits;
1695 
1696 	assert(space->is_active);
1697 
1698 	assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1699 	       (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1700 	       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1701 
1702 	if (soright != IP_NULL) {
1703 		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1704 		       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1705 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1706 		assert(entry->ie_object == IO_NULL);
1707 		assert(object != IO_DEAD);
1708 
1709 		entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1710 				  MACH_PORT_TYPE_DEAD_NAME | 2);
1711 	} else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1712 		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1713 		       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1714 		assert(entry->ie_object == IO_NULL);
1715 
1716 		entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1717 				  MACH_PORT_TYPE_DEAD_NAME | 1);
1718 	} else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1719 		assert(entry->ie_object == IO_NULL);
1720 		assert(object == IO_DEAD);
1721 		assert(ipc_entry_refs(entry) > 0);
1722 
1723 		if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1724 			ipc_entry_hold(entry);/* increment urefs */
1725 		}
1726 	} else {
1727 		assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1728 		       (msgt_name == MACH_MSG_TYPE_COPY_SEND));
1729 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1730 		assert(object != IO_DEAD);
1731 		assert(entry->ie_object == object);
1732 		assert(ipc_entry_refs(entry) > 0);
1733 
1734 		if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1735 			ipc_entry_hold(entry); /* increment urefs */
1736 		}
1737 
1738 		/*
1739 		 *	May as well convert the entry to a dead name.
1740 		 *	(Or if it is a compat entry, destroy it.)
1741 		 */
1742 
1743 		if (!ipc_right_check(space, (ipc_port_t) object,
1744 							 name, entry))
1745 			ip_unlock((ipc_port_t) object);
1746 		/* object is dead so it is not locked */
1747 	}
1748 
1749 	/* release the reference acquired by copyin */
1750 
1751 	if (object != IO_DEAD)
1752 		ipc_object_release(object);
1753 }
1754 
1755 /*
1756  *	Routine:	ipc_right_copyin_two
1757  *	Purpose:
1758  *		Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1759  *		and deadok == FALSE, except that this moves two
1760  *		send rights at once.
1761  *	Conditions:
1762  *		The space is write-locked and active.
1763  *		The object is returned with two refs/send rights.
1764  *	Returns:
1765  *		KERN_SUCCESS		Acquired an object.
1766  *		KERN_INVALID_RIGHT	Name doesn't denote correct right.
1767  */
1768 
1769 kern_return_t
ipc_right_copyin_two(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,ipc_object_t * objectp,ipc_port_t * sorightp)1770 ipc_right_copyin_two(
1771 	ipc_space_t	space,
1772 	mach_port_name_t	name,
1773 	ipc_entry_t	entry,
1774 	ipc_object_t	*objectp,
1775 	ipc_port_t	*sorightp)
1776 {
1777 	ipc_entry_bits_t bits = entry->ie_bits;
1778 	mach_port_urefs_t urefs;
1779 	ipc_port_t port;
1780 	ipc_port_t dnrequest = IP_NULL;
1781 
1782 	assert(space->is_active);
1783 
1784 	if ((bits & MACH_PORT_TYPE_SEND) == 0)
1785 		goto invalid_right;
1786 
1787 	urefs = ipc_entry_refs(entry);
1788 	if (urefs < 2)
1789 		goto invalid_right;
1790 
1791 	port = (ipc_port_t) entry->ie_object;
1792 	assert(port != IP_NULL);
1793 
1794 	if (ipc_right_check(space, port, name, entry)) {
1795 		goto invalid_right;
1796 	}
1797 	/* port is locked and active */
1798 
1799 	assert(port->ip_srights > 0);
1800 
1801 	if (urefs == 2) {
1802 		if (bits & MACH_PORT_TYPE_RECEIVE) {
1803 			assert(port->ip_receiver_name == name);
1804 			assert(port->ip_receiver == space);
1805 			assert(IE_BITS_TYPE(bits) ==
1806 					MACH_PORT_TYPE_SEND_RECEIVE);
1807 
1808 			port->ip_srights++;
1809 			ip_reference(port);
1810 			ip_reference(port);
1811 		} else {
1812 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1813 
1814 			dnrequest = ipc_right_dncancel_macro(space, port,
1815 							     name, entry);
1816 			ipc_hash_delete(space, (ipc_object_t) port,
1817 							name, entry);
1818 			port->ip_srights++;
1819 			ip_reference(port);
1820 			OBJECT_CLEAR(entry, name);
1821 		}
1822 		entry->ie_bits = bits &~
1823 			(IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1824 	} else {
1825 		port->ip_srights += 2;
1826 		ip_reference(port);
1827 		ip_reference(port);
1828 		entry->ie_bits = bits-2; /* decrement urefs */
1829 	}
1830 	ip_unlock(port);
1831 
1832 	*objectp = (ipc_object_t) port;
1833 	*sorightp = dnrequest;
1834 	return KERN_SUCCESS;
1835 
1836     invalid_right:
1837 	return KERN_INVALID_RIGHT;
1838 }
1839 
1840 /*
1841  *	Routine:	ipc_right_copyout
1842  *	Purpose:
1843  *		Copyout a capability to a space.
1844  *		If successful, consumes a ref for the object.
1845  *
1846  *		Always succeeds when given a newly-allocated entry,
1847  *		because user-reference overflow isn't a possibility.
1848  *
1849  *	Conditions:
1850  *		The space is write-locked and active.
1851  *		The object is locked and active.
1852  *		The object is unlocked; the space isn't.
1853  *	Returns:
1854  *		KERN_SUCCESS		Copied out capability.
1855   */
1856 
1857 kern_return_t
ipc_right_copyout(ipc_space_t space,mach_port_name_t name,ipc_entry_t entry,mach_msg_type_name_t msgt_name,ipc_object_t object)1858 ipc_right_copyout(
1859 	ipc_space_t		space,
1860 	mach_port_name_t		name,
1861 	ipc_entry_t		entry,
1862 	mach_msg_type_name_t	msgt_name,
1863 	ipc_object_t		object)
1864 {
1865 	ipc_entry_bits_t bits = entry->ie_bits;
1866 	ipc_port_t port;
1867 
1868 	assert(IO_VALID(object));
1869 	assert(io_otype(object) == IOT_PORT);
1870 	assert(io_active(object));
1871 	assert(entry->ie_object == object);
1872 
1873 	port = (ipc_port_t) object;
1874 
1875 	switch (msgt_name) {
1876 	    case MACH_MSG_TYPE_PORT_SEND_ONCE:
1877 		assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1878 		assert(port->ip_sorights > 0);
1879 
1880 		/* transfer send-once right and ref to entry */
1881 		ip_unlock(port);
1882 
1883 		entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE);
1884 		break;
1885 
1886 	    case MACH_MSG_TYPE_PORT_SEND:
1887 		assert(port->ip_srights > 0);
1888 
1889 		if (bits & MACH_PORT_TYPE_SEND) {
1890 
1891 			assert(port->ip_srights > 1);
1892 			assert(ipc_entry_refs(entry) > 0);
1893 
1894 			port->ip_srights--;
1895 			ip_unlock(port);
1896 			ip_release(port);
1897 		} else if (bits & MACH_PORT_TYPE_RECEIVE) {
1898 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1899 
1900 			/* transfer send right to entry */
1901 			ip_unlock(port);
1902 			ip_release(port);
1903 		} else {
1904 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1905 
1906 			/* transfer send right and ref to entry */
1907 			ip_unlock(port);
1908 
1909 			/* entry is locked holding ref, so can use port */
1910 
1911 			ipc_hash_insert(space, (ipc_object_t) port,
1912 					name, entry);
1913 		}
1914 		ipc_entry_hold(entry);
1915 		entry->ie_bits = (bits | MACH_PORT_TYPE_SEND);
1916 		break;
1917 
1918 	    case MACH_MSG_TYPE_PORT_RECEIVE: {
1919 		ipc_port_t dest;
1920 
1921 		assert(port->ip_mscount == 0);
1922 		assert(port->ip_receiver_name == MACH_PORT_NAME_NULL);
1923 		dest = port->ip_destination;
1924 
1925 		port->ip_receiver_name = name;
1926 		port->ip_receiver = space;
1927 
1928 		assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
1929 
1930 		if (bits & MACH_PORT_TYPE_SEND) {
1931 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1932 			assert(ipc_entry_refs(entry) > 0);
1933 			assert(port->ip_srights > 0);
1934 
1935 			ip_unlock(port);
1936 			ip_release(port);
1937 
1938 			/* entry is locked holding ref, so can use port */
1939 
1940 			ipc_hash_delete(space, (ipc_object_t) port,
1941 					name, entry);
1942 		} else {
1943 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1944 
1945 			/* transfer ref to entry */
1946 			ip_unlock(port);
1947 		}
1948 
1949 		entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
1950 
1951 		if (dest != IP_NULL)
1952 			ipc_port_release(dest);
1953 		break;
1954 	    }
1955 
1956 	    default:
1957 		panic("ipc_right_copyout: strange rights");
1958 	}
1959 
1960 	return KERN_SUCCESS;
1961 }
1962 
1963 /*
1964  *	Routine:	ipc_right_rename
1965  *	Purpose:
1966  *		Transfer an entry from one name to another.
1967  *		The old entry is deallocated.
1968  *	Conditions:
1969  *		The space is write-locked and active.
1970  *		The new entry is unused.  Upon return,
1971  *		the space is unlocked.
1972  *	Returns:
1973  *		KERN_SUCCESS		Moved entry to new name.
1974  */
1975 
1976 kern_return_t
ipc_right_rename(ipc_space_t space,mach_port_name_t oname,ipc_entry_t oentry,mach_port_name_t nname,ipc_entry_t nentry)1977 ipc_right_rename(
1978 	ipc_space_t	space,
1979 	mach_port_name_t	oname,
1980 	ipc_entry_t	oentry,
1981 	mach_port_name_t	nname,
1982 	ipc_entry_t	nentry)
1983 {
1984 	ipc_entry_bits_t bits = oentry->ie_bits;
1985 	ipc_port_request_index_t request = oentry->ie_request;
1986 	ipc_object_t object = oentry->ie_object;
1987 
1988 	assert(space->is_active);
1989 	assert(oname != nname);
1990 
1991 	/*
1992 	 *	If IE_BITS_COMPAT, we can't allow the entry to be renamed
1993 	 *	if the port is dead.  (This would foil ipc_port_destroy.)
1994 	 *	Instead we should fail because oentry shouldn't exist.
1995 	 *	Note IE_BITS_COMPAT implies ie_request != 0.
1996 	 */
1997 
1998 	if (request != 0) {
1999 		ipc_port_t port;
2000 
2001 		assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2002 		port = (ipc_port_t) object;
2003 		assert(port != IP_NULL);
2004 
2005 		if (ipc_right_check(space, port, oname, oentry)) {
2006 			bits = oentry->ie_bits;
2007 			assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2008 			assert(oentry->ie_request == 0);
2009 			request = 0;
2010 			assert(oentry->ie_object == IO_NULL);
2011 			object = IO_NULL;
2012 		} else {
2013 			/* port is locked and active */
2014 
2015 			ipc_port_dnrename(port, request, oname, nname);
2016 			ip_unlock(port);
2017 			oentry->ie_request = 0;
2018 		}
2019 	}
2020 
2021 	/* initialize nentry before letting ipc_hash_insert see it */
2022 
2023 	assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2024 	nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2025 	nentry->ie_request = request;
2026 	nentry->ie_object = object;
2027 
2028 	switch (IE_BITS_TYPE(bits)) {
2029 	    case MACH_PORT_TYPE_SEND: {
2030 		ipc_port_t port;
2031 
2032 		port = (ipc_port_t) object;
2033 		assert(port != IP_NULL);
2034 
2035 		ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2036 		ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2037 		break;
2038 	    }
2039 
2040 	    case MACH_PORT_TYPE_RECEIVE:
2041 	    case MACH_PORT_TYPE_SEND_RECEIVE: {
2042 		ipc_port_t port;
2043 
2044 		port = (ipc_port_t) object;
2045 		assert(port != IP_NULL);
2046 
2047 		ip_lock(port);
2048 		assert(ip_active(port));
2049 		assert(port->ip_receiver_name == oname);
2050 		assert(port->ip_receiver == space);
2051 
2052 		port->ip_receiver_name = nname;
2053 		ip_unlock(port);
2054 		break;
2055 	    }
2056 
2057 	    case MACH_PORT_TYPE_PORT_SET: {
2058 		ipc_pset_t pset;
2059 
2060 		pset = (ipc_pset_t) object;
2061 		assert(pset != IPS_NULL);
2062 
2063 		ips_lock(pset);
2064 		assert(ips_active(pset));
2065 		assert(pset->ips_local_name == oname);
2066 
2067 		pset->ips_local_name = nname;
2068 		ips_unlock(pset);
2069 		break;
2070 	    }
2071 
2072 	    case MACH_PORT_TYPE_SEND_ONCE:
2073 	    case MACH_PORT_TYPE_DEAD_NAME:
2074 		break;
2075 
2076 	    default:
2077 		panic("ipc_right_rename: strange rights");
2078 	}
2079 
2080 	assert(oentry->ie_request == 0);
2081 	OBJECT_CLEAR(oentry, oname);
2082 	/* drops the space lock */
2083 	ipc_entry_dealloc(space, oname, oentry);
2084 
2085 	return KERN_SUCCESS;
2086 }
2087