2  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  32  * Mach Operating System 
  33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University 
  34  * All Rights Reserved. 
  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. 
  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. 
  46  * Carnegie Mellon requests users of this software to return to 
  48  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU 
  49  *  School of Computer Science 
  50  *  Carnegie Mellon University 
  51  *  Pittsburgh PA 15213-3890 
  53  * any improvements or extensions that they make and grant Carnegie Mellon 
  54  * the rights to redistribute these changes. 
  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, 
  65  *      File:   ipc/ipc_space.c 
  69  *      Functions to manipulate IPC capability spaces. 
  72 #include <mach/boolean.h> 
  73 #include <mach/kern_return.h> 
  74 #include <mach/port.h> 
  75 #include <kern/assert.h> 
  76 #include <kern/sched_prim.h> 
  77 #include <kern/zalloc.h> 
  79 #include <ipc/ipc_entry.h> 
  80 #include <ipc/ipc_object.h> 
  81 #include <ipc/ipc_hash.h> 
  82 #include <ipc/ipc_table.h> 
  83 #include <ipc/ipc_port.h> 
  84 #include <ipc/ipc_space.h> 
  85 #include <ipc/ipc_right.h> 
  88 zone_t ipc_space_zone
; 
  89 ipc_space_t ipc_space_kernel
; 
  90 ipc_space_t ipc_space_reply
; 
  93  *      Routine:        ipc_space_reference 
  94  *      Routine:        ipc_space_release 
  96  *              Function versions of the IPC space inline reference. 
 114  *      Routine:        ipc_space_create 
 116  *              Creates a new IPC space. 
 118  *              The new space has two references, one for the caller 
 119  *              and one because it is active. 
 121  *              Nothing locked.  Allocates memory. 
 123  *              KERN_SUCCESS            Created a space. 
 124  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory. 
 129         ipc_table_size_t        initial
, 
 134         ipc_entry_num_t new_size
; 
 135         mach_port_index_t index
; 
 138         if (space 
== IS_NULL
) 
 139                 return KERN_RESOURCE_SHORTAGE
; 
 141         table 
= it_entries_alloc(initial
); 
 142         if (table 
== IE_NULL
) { 
 144                 return KERN_RESOURCE_SHORTAGE
; 
 147         new_size 
= initial
->its_size
; 
 148         memset((void *) table
, 0, new_size 
* sizeof(struct ipc_entry
)); 
 151          *      Initialize the free list in the table. 
 152          *      Add the entries in reverse order, and 
 153          *      set the generation number to -1, so that 
 154          *      initial allocations produce "natural" names. 
 156         for (index 
= 0; index 
< new_size
; index
++) { 
 157                 ipc_entry_t entry 
= &table
[index
]; 
 159                 entry
->ie_bits 
= IE_BITS_GEN_MASK
; 
 160                 entry
->ie_next 
= index
+1; 
 162         table
[new_size
-1].ie_next 
= 0; 
 165         space
->is_bits 
= 2; /* 2 refs, active, not growing */ 
 166         space
->is_table_size 
= new_size
; 
 167         space
->is_table_free 
= new_size 
- 1; 
 168         space
->is_table 
= table
; 
 169         space
->is_table_next 
= initial
+1; 
 170         space
->is_task 
= NULL
; 
 171         space
->is_low_mod 
= new_size
; 
 172         space
->is_high_mod 
= 0; 
 173         space
->is_node_id 
= HOST_LOCAL_NODE
; /* HOST_LOCAL_NODE, except proxy spaces */ 
 180  *      Routine:        ipc_space_create_special 
 182  *              Create a special space.  A special space 
 183  *              doesn't hold rights in the normal way. 
 184  *              Instead it is place-holder for holding 
 185  *              disembodied (naked) receive rights. 
 186  *              See ipc_port_alloc_special/ipc_port_dealloc_special. 
 190  *              KERN_SUCCESS            Created a space. 
 191  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory. 
 195 ipc_space_create_special( 
 201         if (space 
== IS_NULL
) 
 202                 return KERN_RESOURCE_SHORTAGE
; 
 206         space
->is_bits       
= IS_INACTIVE 
| 1; /* 1 ref, not active, not growing */ 
 207         space
->is_table      
= IE_NULL
; 
 208         space
->is_task       
= TASK_NULL
; 
 209         space
->is_table_next 
= 0; 
 210         space
->is_low_mod    
= 0; 
 211         space
->is_high_mod   
= 0; 
 212         space
->is_node_id 
= HOST_LOCAL_NODE
; /* HOST_LOCAL_NODE, except proxy spaces */ 
 219  * ipc_space_clean - remove all port references from an ipc space. 
 221  * In order to follow the traditional semantic, ipc_space_destroy 
 222  * will not destroy the entire port table of a shared space.  Instead 
 223  * it will simply clear its own sub-space. 
 230         ipc_entry_num_t size
; 
 231         mach_port_index_t index
; 
 234          *      If somebody is trying to grow the table, 
 235          *      we must wait until they finish and figure 
 236          *      out the space died. 
 239         is_write_lock(space
); 
 240         while (is_growing(space
)) 
 241                 is_write_sleep(space
); 
 243         if (!is_active(space
)) { 
 244                 is_write_unlock(space
); 
 249          *      Now we can futz with it since we have the write lock. 
 252         table 
= space
->is_table
; 
 253         size 
= space
->is_table_size
; 
 255         for (index 
= 0; index 
< size
; index
++) { 
 256                 ipc_entry_t entry 
= &table
[index
]; 
 257                 mach_port_type_t type
; 
 259                 type 
= IE_BITS_TYPE(entry
->ie_bits
); 
 260                 if (type 
!= MACH_PORT_TYPE_NONE
) { 
 261                         mach_port_name_t name 
= MACH_PORT_MAKE(index
, 
 262                                                 IE_BITS_GEN(entry
->ie_bits
)); 
 263                         ipc_right_destroy(space
, name
, entry
, FALSE
, 0); /* unlocks space */ 
 269          * JMM - Now the table is cleaned out.  We don't bother shrinking the 
 270          * size of the table at this point, but we probably should if it is 
 274         is_write_unlock(space
); 
 279  *      Routine:        ipc_space_terminate 
 281  *              Marks the space as dead and cleans up the entries. 
 282  *              Does nothing if the space is already dead. 
 292         ipc_entry_num_t size
; 
 293         mach_port_index_t index
; 
 295         assert(space 
!= IS_NULL
); 
 297         is_write_lock(space
); 
 298         if (!is_active(space
)) { 
 299                 is_write_unlock(space
); 
 302         is_mark_inactive(space
); 
 305          *      If somebody is trying to grow the table, 
 306          *      we must wait until they finish and figure 
 307          *      out the space died. 
 309         while (is_growing(space
)) 
 310                 is_write_sleep(space
); 
 312         is_write_unlock(space
); 
 316          *      Now we can futz with it unlocked. 
 319         table 
= space
->is_table
; 
 320         size 
= space
->is_table_size
; 
 322         for (index 
= 0; index 
< size
; index
++) { 
 323                 ipc_entry_t entry 
= &table
[index
]; 
 324                 mach_port_type_t type
; 
 326                 type 
= IE_BITS_TYPE(entry
->ie_bits
); 
 327                 if (type 
!= MACH_PORT_TYPE_NONE
) { 
 328                         mach_port_name_t name
; 
 330                         name 
= MACH_PORT_MAKE(index
, 
 331                                               IE_BITS_GEN(entry
->ie_bits
)); 
 332                         ipc_right_terminate(space
, name
, entry
); 
 336         it_entries_free(space
->is_table_next
-1, table
); 
 337         space
->is_table_size 
= 0; 
 338         space
->is_table_free 
= 0; 
 341          *      Because the space is now dead, 
 342          *      we must release the "active" reference for it. 
 343          *      Our caller still has his reference.