···2626#include <linux/uaccess.h>
2727#include <linux/jiffies.h>
2828#include <linux/atomic.h>
2929+#include <linux/flex_array.h>
2930#include "darling_task.h"
30313132extern ipc_namespace_t kernel_namespace;
···3435static
3536mach_msg_return_t ipc_msg_complex_copyin(ipc_namespace_t* space,
3637 struct ipc_kmsg* kmsg);
3838+static
3939+mach_msg_return_t ipc_msg_copyout_complex(ipc_namespace_t* space,
4040+ struct ipc_kmsg* kmsg,
4141+ struct flex_array* ool_ports);
4242+static
4343+bool walk_complex_msg(mach_msg_base_t* base,
4444+ bool (*cb)(mach_msg_type_descriptor_t*,int,void*),
4545+ void* private);
37463847int ipc_msg_count(void)
3948{
···313322}
314323315324static
325325+bool _copy_to_move(mach_msg_type_descriptor_t* desc, int index, void* priv)
326326+{
327327+ if (desc->type == MACH_MSG_PORT_DESCRIPTOR)
328328+ {
329329+ mach_msg_port_descriptor_t* pdesc = (mach_msg_port_descriptor_t*) desc;
330330+ if (pdesc->disposition == MACH_MSG_TYPE_COPY_SEND)
331331+ pdesc->disposition = MACH_MSG_TYPE_MOVE_SEND;
332332+ }
333333+ return true;
334334+}
335335+336336+static
316337mach_msg_return_t ipc_msg_invoke_server(struct ipc_kmsg* kmsg,
317338 int options, mach_msg_timeout_t timeout)
318339{
···321342 mach_msg_header_t* reply_msg;
322343 mach_msg_return_t ret;
323344 mach_port_t tmp;
345345+ struct flex_array* ool = NULL;
346346+347347+ if (kmsg->msg->msgh_bits & MACH_MSGH_BITS_CIRCULAR)
348348+ {
349349+ debug_msg("Prevented a circular message delivery\n");
350350+ ret = KERN_FAILURE;
351351+ goto err;
352352+ }
324353325354 subsystem = kmsg->target->port->server_port.subsystem;
326355···365394 */
366395 // Insert reply port from kmsg into kernel_namespace
367396 // and put the right name into reply_msg
397397+ ipc_space_lock(&kernel_namespace);
368398 if (kmsg->reply != NULL)
369399 {
370400 ipc_space_right_insert(&kernel_namespace, kmsg->reply,
···376406 reply_msg->msgh_remote_port = 0;
377407 }
378408409409+ if (MACH_MSGH_BITS_IS_COMPLEX(kmsg->msg->msgh_bits))
410410+ {
411411+ // Handle OOL rights, memory regions etc.
412412+ ool = flex_array_alloc(sizeof(mach_port_t), 1024, GFP_KERNEL);
413413+ ipc_msg_copyout_complex(&kernel_namespace, kmsg, ool);
414414+ }
415415+ ipc_space_unlock(&kernel_namespace);
416416+379417 reply_msg->msgh_id = kmsg->msg->msgh_id + 100;
380418 // reply_msg->msgh_voucher_port = kmsg->msg->msgh_voucher_port;
381419···395433 kmsg->msg->msgh_remote_port = kmsg->msg->msgh_local_port;
396434 kmsg->msg->msgh_local_port = tmp;
397435436436+ if (ool != NULL)
437437+ {
438438+ // Destroy all ports sent to us
439439+ int i = 0;
440440+ mach_port_t* pport;
441441+442442+ while ((pport = (mach_port_t*) flex_array_get(ool, i++)) != NULL)
443443+ {
444444+ ipc_space_right_put(&kernel_namespace, *pport);
445445+ }
446446+447447+ flex_array_free(ool);
448448+ }
449449+398450 debug_msg("ipc_msg_deliver(): reply size: %d, ret = 0x%x\n",
399451 reply_msg->msgh_size,
400452 ((mig_reply_error_t*)reply_msg)->RetCode);
401453402454 // The right used to call us is now consumed.
403455 ipc_right_put_unlock(kmsg->target);
456456+457457+ /*
458458+ if (MACH_MSGH_BITS_IS_COMPLEX(reply_msg->msgh_bits))
459459+ {
460460+ // MIG uses "copy_send" for output arguments,
461461+ // but we want to get rid of the copy in kernel namespace.
462462+ // Change the disposition to "move_send".
463463+ walk_complex_msg((mach_msg_base_t*) reply_msg, _copy_to_move, NULL);
464464+ }
465465+ */
404466405405- // TODO: prevent circular loops
467467+ // prevent circular loops
468468+ reply_msg->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
406469 ret = ipc_msg_send(&kernel_namespace, reply_msg, timeout, options);
407470408471 if (ret != MACH_MSG_SUCCESS)
···799862 ipc_namespace_t* space;
800863 struct ipc_kmsg* kmsg;
801864 mach_msg_return_t ret;
865865+ struct flex_array* ool_ports;
866866+ unsigned int ool_ports_count;
802867};
803868804869static
···824889 ret = ipc_space_right_insert(args->space,
825890 args->kmsg->complex_items[index].port,
826891 &port_desc->name);
892892+893893+ if (ret == KERN_SUCCESS && args->ool_ports)
894894+ {
895895+ flex_array_put(args->ool_ports, args->ool_ports_count++,
896896+ &port_desc->name, GFP_KERNEL);
897897+ }
827898 }
828899 else
829900 {
···840911841912static
842913mach_msg_return_t ipc_msg_copyout_complex(ipc_namespace_t* space,
843843- struct ipc_kmsg* kmsg)
914914+ struct ipc_kmsg* kmsg, struct flex_array* ool_ports)
844915{
845916 struct ipc_msg_copyout_complex_args args = {
846917 .space = space,
847918 .kmsg = kmsg,
848848- .ret = KERN_SUCCESS
919919+ .ret = KERN_SUCCESS,
920920+ .ool_ports_count = 0,
921921+ .ool_ports = ool_ports,
849922 };
850923 if (kmsg->complex_items == NULL)
851924 return KERN_SUCCESS;
···10371110 {
10381111 // Handle OOL rights, memory regions etc.
10391112 ipc_msg_copyout_complex(&task->namespace,
10401040- &delivery->kmsg);
11131113+ &delivery->kmsg, NULL);
10411114 }
1042111510431116 // Copy over the message to recipient's buffer.
+6-1
src/lkm/ipc_right.c
···8585 {
8686 if (PORT_IS_VALID(port))
8787 {
8888- debug_msg("\tChanging num of rights\n");
8988 if (right->type == MACH_PORT_RIGHT_SEND)
8989+ {
9090 port->num_srights--;
9191+ debug_msg("\tChanging num of rights (s) -> %d\n", port->num_srights);
9292+ }
9193 else if (right->type == MACH_PORT_RIGHT_SEND_ONCE)
9494+ {
9295 port->num_sorights--;
9696+ debug_msg("\tChanging num of rights (so) -> %d\n", port->num_sorights);
9797+ }
93989499 list_del(&right->reflist);
95100
+3-1
src/lkm/ipc_server.c
···32323333 task = (mach_task_t*) kport->private_data;
34343535- darling_task_free_threads(task);
3535+ darling_task_destruct(task);
36363737 /* Deallocate the port right space. Deletes all references. */
3838 ipc_space_put(&task->namespace);
···6363 port->server_port.subsystem = &task_subsystem;
6464 port->server_port.private_data = task;
6565 port->server_port.cb_free = task_free;
6666+6767+ INIT_LIST_HEAD(&task->semaphores);
66686769 return task;
6870}
···8383 *
8484 * Automatically deallocates port on last reference
8585 * or marks port as dead if name refers to a receive right.
8686+ *
8787+ * Expects the space to be unlocked.
8688 */
8789mach_msg_return_t ipc_space_right_put(ipc_namespace_t* space, mach_port_name_t name);
9090+9191+/*
9292+ * Same as above, but caller has already locked the port
9393+ */
9494+mach_msg_return_t ipc_space_right_put_unlocked(ipc_namespace_t* space, mach_port_name_t name);
88958996/*
9097 * Deallocate a port name. Does not delete the associated right.
···295295 mach_port_name_t name;
296296 kern_return_t ret;
297297298298- ipc_port_lock(task->task_self);
298298+ // No reason to lock task_self, this task is not going away
299299+ // while we are running. (Avoid an ABBA lock problem).
300300+ // ipc_port_lock(task->task_self);
299301300302 ret = ipc_space_make_send(&task->namespace, task->task_self, false, &name);
301303302302- ipc_port_unlock(task->task_self);
304304+ // ipc_port_unlock(task->task_self);
303305304306 if (ret == KERN_SUCCESS)
305307 return name;