]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_entry.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_entry.c
index 80eb3d662d8d0f9d134fbf1b37ef75bd103203e1..facaf2af0d0bf61f3f74ca090f9372a556fe2a22 100644 (file)
@@ -79,6 +79,7 @@
 #include <ipc/ipc_table.h>
 #include <ipc/ipc_port.h>
 #include <string.h>
+#include <sys/kdebug.h>
 
 /*
  *     Routine:        ipc_entry_lookup
@@ -99,13 +100,13 @@ ipc_entry_lookup(
 
        assert(is_active(space));
 
-                       
        index = MACH_PORT_INDEX(name);
        if (index <  space->is_table_size) {
                 entry = &space->is_table[index];
                if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
-                   IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
+                   IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
                        entry = IE_NULL;                
+               }
        }
        else {
                entry = IE_NULL;
@@ -115,69 +116,131 @@ ipc_entry_lookup(
        return entry;
 }
 
+
 /*
- *     Routine:        ipc_entry_get
+ *     Routine:        ipc_entries_hold
  *     Purpose:
- *             Tries to allocate an entry out of the space.
+ *             Verifies that there are at least 'entries_needed'
+ *             free list members
  *     Conditions:
  *             The space is write-locked and active throughout.
  *             An object may be locked.  Will not allocate memory.
  *     Returns:
- *             KERN_SUCCESS            A free entry was found.
+ *             KERN_SUCCESS            Free entries were found.
  *             KERN_NO_SPACE           No entry allocated.
  */
 
 kern_return_t
-ipc_entry_get(
+ipc_entries_hold(
+       ipc_space_t             space,
+       uint32_t                entries_needed)
+{
+
+       ipc_entry_t table;
+       mach_port_index_t next_free = 0;
+       uint32_t i;
+
+       assert(is_active(space));
+
+       table = &space->is_table[0];
+
+       for (i = 0; i < entries_needed; i++) {
+               next_free = table[next_free].ie_next;
+               if (next_free == 0) {
+                       return KERN_NO_SPACE;
+               }
+               assert(next_free < space->is_table_size);
+               assert(table[next_free].ie_object == IO_NULL);
+       }
+       return KERN_SUCCESS;
+}
+
+/*
+ *     Routine:        ipc_entry_claim
+ *     Purpose:
+ *             Take formal ownership of a held entry.
+ *     Conditions:
+ *             The space is write-locked and active throughout.
+ *             An object may be locked.  Will not allocate memory.
+ *
+ *     Note: The returned entry must be marked as modified before
+ *           releasing the space lock
+ */
+
+kern_return_t
+ipc_entry_claim(
        ipc_space_t             space,
        mach_port_name_t        *namep,
        ipc_entry_t             *entryp)
 {
+       ipc_entry_t entry;
        ipc_entry_t table;
        mach_port_index_t first_free;
-       ipc_entry_t free_entry;
+       mach_port_gen_t gen;
+       mach_port_name_t new_name;
 
-       assert(is_active(space));
+       table = &space->is_table[0];
 
-       {
-               table = space->is_table;
-               first_free = table->ie_next;
+       first_free = table->ie_next;
+       assert(first_free != 0);
 
-               if (first_free == 0)
-                       return KERN_NO_SPACE;
+       entry = &table[first_free];
+       table->ie_next = entry->ie_next;
+       space->is_table_free--;
+
+       assert(table->ie_next < space->is_table_size);
 
-               assert(first_free < space->is_table_size);
-               free_entry = &table[first_free];
-               table->ie_next = free_entry->ie_next;
+       /*
+        *      Initialize the new entry: increment gencount and reset
+        *      rollover point if it rolled over, and clear ie_request.
+        */
+       gen = ipc_entry_new_gen(entry->ie_bits);
+       if (__improbable(ipc_entry_gen_rolled(entry->ie_bits, gen))) {
+               ipc_entry_bits_t roll = ipc_space_get_rollpoint(space);
+               gen = ipc_entry_new_rollpoint(roll);
        }
+       entry->ie_bits = gen;
+       entry->ie_request = IE_REQ_NONE;
 
        /*
-        *      Initialize the new entry.  We need only
-        *      increment the generation number and clear ie_request.
+        *      The new name can't be MACH_PORT_NULL because index
+        *      is non-zero.  It can't be MACH_PORT_DEAD because
+        *      the table isn't allowed to grow big enough.
+        *      (See comment in ipc/ipc_table.h.)
         */
-       {
-               mach_port_name_t new_name;
-               mach_port_gen_t gen;
+       new_name = MACH_PORT_MAKE(first_free, gen);
+       assert(MACH_PORT_VALID(new_name));
+       *namep = new_name;
+       *entryp = entry;
+
+       return KERN_SUCCESS;
+}
 
-               gen = IE_BITS_NEW_GEN(free_entry->ie_bits);
-               free_entry->ie_bits = gen;
-               free_entry->ie_request = IE_REQ_NONE;
+/*
+ *     Routine:        ipc_entry_get
+ *     Purpose:
+ *             Tries to allocate an entry out of the space.
+ *     Conditions:
+ *             The space is write-locked and active throughout.
+ *             An object may be locked.  Will not allocate memory.
+ *     Returns:
+ *             KERN_SUCCESS            A free entry was found.
+ *             KERN_NO_SPACE           No entry allocated.
+ */
 
-               /*
-                *      The new name can't be MACH_PORT_NULL because index
-                *      is non-zero.  It can't be MACH_PORT_DEAD because
-                *      the table isn't allowed to grow big enough.
-                *      (See comment in ipc/ipc_table.h.)
-                */
-               new_name = MACH_PORT_MAKE(first_free, gen);
-               assert(MACH_PORT_VALID(new_name));
-               *namep = new_name;
-       }
+kern_return_t
+ipc_entry_get(
+       ipc_space_t             space,
+       mach_port_name_t        *namep,
+       ipc_entry_t             *entryp)
+{
+       kern_return_t kr;
 
-       assert(free_entry->ie_object == IO_NULL);
+       kr = ipc_entries_hold(space, 1);
+       if (KERN_SUCCESS != kr)
+               return kr;
 
-       *entryp = free_entry;
-       return KERN_SUCCESS;
+       return ipc_entry_claim(space, namep, entryp);
 }
 
 /*
@@ -245,6 +308,9 @@ ipc_entry_alloc_name(
        mach_port_index_t index = MACH_PORT_INDEX(name);
        mach_port_gen_t gen = MACH_PORT_GEN(name);
 
+       if (index > ipc_table_max_entries())
+               return KERN_NO_SPACE;
+
        assert(MACH_PORT_VALID(name));
 
 
@@ -306,7 +372,8 @@ ipc_entry_alloc_name(
 
                                table[free_index].ie_next =
                                        table[next_index].ie_next;
-                               
+                               space->is_table_free--;
+
                                /* mark the previous entry modified - reconstructing the name */
                                ipc_entry_modified(space, 
                                                   MACH_PORT_MAKE(free_index, 
@@ -373,9 +440,10 @@ ipc_entry_dealloc(
 
        if ((index < size) && (entry == &table[index])) {
                assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
-               entry->ie_bits &= IE_BITS_GEN_MASK;
+               entry->ie_bits &= (IE_BITS_GEN_MASK | IE_BITS_ROLL_MASK);
                entry->ie_next = table->ie_next;
                table->ie_next = index;
+               space->is_table_free++;
        } else {
                /*
                 * Nothing to do.  The entry does not match
@@ -422,6 +490,14 @@ ipc_entry_modified(
                space->is_low_mod = index;
        if (index > space->is_high_mod)
                space->is_high_mod = index;
+
+       KERNEL_DEBUG_CONSTANT(
+               MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_PORT_ENTRY_MODIFY) | DBG_FUNC_NONE,
+               space->is_task ? task_pid(space->is_task) : 0,
+               name,
+               entry->ie_bits,
+               0,
+               0);
 }
 
 #define IPC_ENTRY_GROW_STATS 1
@@ -549,14 +625,7 @@ ipc_entry_grow_table(
                return KERN_RESOURCE_SHORTAGE;
        }
 
-       /* initialize new entries (free chain in backwards order) */
-       for (i = osize; i < size; i++) {
-               table[i].ie_object = IO_NULL;
-               table[i].ie_bits = IE_BITS_GEN_MASK;
-               table[i].ie_index = 0;
-               table[i].ie_next = i + 1;
-       }
-       table[size-1].ie_next = 0;
+       ipc_space_rand_freelist(space, table, osize, size);
 
        /* clear out old entries in new table */
        memset((void *)table, 0, osize * sizeof(*table));
@@ -675,6 +744,7 @@ ipc_entry_grow_table(
        space->is_table = table;
        space->is_table_size = size;
        space->is_table_next = nits;
+       space->is_table_free += size - osize;
 
        is_done_growing(space);
        is_write_unlock(space);
@@ -689,3 +759,29 @@ ipc_entry_grow_table(
 
        return KERN_SUCCESS;
 }
+
+
+/*
+ *     Routine:        ipc_entry_name_mask
+ *     Purpose:
+ *             Ensure a mach port name has the default ipc entry
+ *             generation bits set. This can be used to ensure that
+ *             a name passed in by user space matches names generated
+ *             by the kernel.
+ *     Conditions:
+ *             None.
+ *     Returns:
+ *             'name' input with default generation bits masked or added
+ *             as appropriate.
+ */
+mach_port_name_t
+ipc_entry_name_mask(mach_port_name_t name)
+{
+#ifndef NO_PORT_GEN
+       static mach_port_name_t null_name = MACH_PORT_MAKE(0, IE_BITS_GEN_MASK + IE_BITS_GEN_ONE);
+       return name | null_name;
+#else
+       static mach_port_name_t null_name = MACH_PORT_MAKE(0, ~(IE_BITS_GEN_MASK + IE_BITS_GEN_ONE));
+       return name & ~null_name;
+#endif
+}