···5959 NR_mk_timer_arm_trap,
6060 NR_mk_timer_cancel_trap,
6161 NR_mk_timer_destroy_trap,
6262+ NR__kernelrpc_mach_port_move_member_trap,
6363+ NR__kernelrpc_mach_port_insert_member_trap,
6464+ NR__kernelrpc_mach_port_extract_member_trap,
6265};
63666467struct mach_port_mod_refs_args
···109112{
110113 unsigned int task_right_name;
111114 unsigned int port_right_name;
115115+};
116116+117117+struct mach_port_move_member_args
118118+{
119119+ unsigned int task_right_name;
120120+ unsigned int port_right_name;
121121+ unsigned int pset_right_name;
122122+};
123123+124124+struct mach_port_insert_member_args
125125+{
126126+ unsigned int task_right_name;
127127+ unsigned int port_right_name;
128128+ unsigned int pset_right_name;
129129+};
130130+131131+struct mach_port_extract_member_args
132132+{
133133+ unsigned int task_right_name;
134134+ unsigned int port_right_name;
135135+ unsigned int pset_right_name;
112136};
113137114138struct semaphore_signal_args
+35-16
src/lkm/ipc_msg.c
···429429 mach_msg_return_t ret = MACH_MSG_SUCCESS;
430430 struct ipc_delivered_msg* delivery = NULL;
431431 darling_mach_port_t* port;
432432+ bool was_in_set;
432433433434 debug_msg("ipc_msg_deliver()\n");
434435···448449 INIT_LIST_HEAD(&delivery->list);
449450 memcpy(&delivery->kmsg, kmsg, sizeof(*kmsg));
450451 delivery->delivered = false;
452452+ delivery->recipient_died = false;
451453 delivery->recipient_freed = kmsg->target->type == MACH_PORT_RIGHT_SEND_ONCE;
452454453455 list_add(&delivery->list, &port->messages);
···456458 debug_msg("-> msg enqueued (%d b), waking up queue %p, queue size %d\n", kmsg->msg->msgh_size, &port->queue_recv, port->queue_size);
457459458460 // Wake up waiting receivers
459459- wake_up(&port->queue_recv);
461461+ was_in_set = !hash_empty(port->sets);
462462+ if (was_in_set)
463463+ {
464464+ struct darling_mach_port_le* item;
465465+ int bkt;
466466+467467+ hash_for_each(port->sets, bkt, item, node)
468468+ {
469469+ wake_up_interruptible(&item->port->queue_recv);
470470+ }
471471+ }
472472+ else
473473+ wake_up(&port->queue_recv);
460474461475 // Wait (unless target is send once)
462476 if (kmsg->target->type != MACH_PORT_RIGHT_SEND_ONCE)
···467481468482 ipc_port_unlock(port);
469483470470- if (timeout)
484484+ // TODO: handle cases when port has died
485485+ if (timeout > 0)
471486 {
472487 if (options & MACH_SEND_INTERRUPT)
473488 {
474489 err = wait_event_interruptible_timeout(port->queue_send,
475475- delivery->delivered, msecs_to_jiffies(timeout));
490490+ delivery->delivered || delivery->recipient_died,
491491+ msecs_to_jiffies(timeout));
476492 }
477493 else
478494 {
479495 err = wait_event_timeout(port->queue_send,
480480- delivery->delivered, msecs_to_jiffies(timeout));
496496+ delivery->delivered || delivery->recipient_died,
497497+ msecs_to_jiffies(timeout));
481498 }
482499 }
483500 else
···485502 if (options & MACH_SEND_INTERRUPT)
486503 {
487504 err = wait_event_interruptible(port->queue_send,
488488- delivery->delivered);
505505+ delivery->delivered || delivery->recipient_died);
506506+ if (err == 0)
507507+ err = 1;
489508 }
490509 else
491510 {
492492- err = wait_event_killable(port->queue_send, delivery->delivered);
511511+ err = wait_event_killable(port->queue_send,
512512+ delivery->delivered || delivery->recipient_died);
493513 if (err == 0)
494514 err = 1;
495515 }
496516 }
497517 if (err == -ERESTARTSYS)
498518 ret = MACH_SEND_INTERRUPTED;
499499- else if (err == 0)
519519+ else if (err == 0 && timeout > 0)
500520 ret = MACH_RCV_TIMED_OUT;
501501-502502- debug_msg("\t-> kfree(delivery) #1\n");
503503- kfree(delivery);
521521+ else if (delivery->recipient_died)
522522+ ret = MACH_SEND_INVALID_DEST;
504523 }
505524 else
506525 {
···515534 ipc_right_lock_port(kmsg->target);
516535517536 // Port may have died
518518- if (PORT_IS_VALID(kmsg->target->port) && delivery != NULL)
537537+ if (PORT_IS_VALID(kmsg->target->port))
519538 {
520539 if (!delivery->delivered)
521540 {
···527546 }
528547 else
529548 {
530530- debug_msg("msg delivered\n");
531549 darling_mach_port_t* port;
550550+ debug_msg("msg delivered\n");
532551533552 ipc_right_lock_port(kmsg->target);
534534-553553+535554 port = kmsg->target->port;
536555 ipc_right_put(kmsg->target);
537556···874893 ipc_space_unlock(&task->namespace);
875894 goto err;
876895 }
877877- if (right->type == MACH_PORT_RIGHT_RECEIVE && right->port->set != NULL)
896896+ if (right->type == MACH_PORT_RIGHT_RECEIVE && !hash_empty(right->port->sets))
878897 {
879898 ret = MACH_RCV_IN_SET;
880899 ipc_space_unlock(&task->namespace);
···910929 debug_msg("\t-> going to wait with timeout %d on queue %p (intr: %d)\n", timeout, &right->port->queue_recv, options & MACH_RCV_INTERRUPT);
911930912931 // wait for ipc_msg_deliver() to be called somewhere
913913- if (timeout)
932932+ if (timeout > 0)
914933 {
915934 if (options & MACH_RCV_INTERRUPT)
916935 {
···948967 ret = MACH_RCV_INTERRUPTED;
949968 goto err;
950969 }
951951- else if (err == 0)
970970+ else if (err == 0 && timeout > 0)
952971 {
953972 ret = MACH_RCV_TIMED_OUT;
954973 goto err;
+133-15
src/lkm/ipc_port.c
···2222#include <linux/slab.h>
2323#include <linux/list.h>
2424#include <linux/atomic.h>
2525+#include <linux/sched.h>
2526#include "debug.h"
2627#include "darling_task.h"
2728#include "ipc_right.h"
···4647 port->is_server_port = false;
4748 port->is_port_set = false;
4849 port->queue_size = 0;
4949- port->set = NULL;
50505151 INIT_LIST_HEAD(&port->refs);
5252 INIT_LIST_HEAD(&port->messages);
5353- INIT_LIST_HEAD(&port->set_head);
5353+ hash_init(port->sets);
5454 init_waitqueue_head(&port->queue_send);
5555 init_waitqueue_head(&port->queue_recv);
5656···7878 port->is_port_set = true;
79798080 INIT_LIST_HEAD(&port->refs);
8181- INIT_LIST_HEAD(&port->members);
8181+ hash_init(port->members);
82828383 atomic_inc(&port_count);
8484 *port_out = port;
8585 return KERN_SUCCESS;
8686}
87878888+static void ipc_portset_delete_member(darling_mach_port_t* pset, darling_mach_port_t* member)
8989+{
9090+ struct hlist_node *tmp2;
9191+ struct darling_mach_port_le* ref2;
9292+9393+ hash_for_each_possible_safe(pset->members, ref2, tmp2, node, (long)member)
9494+ {
9595+ if (ref2->port != member)
9696+ continue;
9797+ hash_del(&ref2->node);
9898+ kfree(ref2);
9999+ }
100100+}
101101+102102+static void ipc_port_delete_set(darling_mach_port_t* pset, darling_mach_port_t* member)
103103+{
104104+ struct hlist_node *tmp2;
105105+ struct darling_mach_port_le* ref2;
106106+107107+ hash_for_each_possible_safe(member->sets, ref2, tmp2, node, (long)pset)
108108+ {
109109+ if (ref2->port != pset)
110110+ continue;
111111+ hash_del(&ref2->node);
112112+ kfree(ref2);
113113+ }
114114+}
115115+88116mach_msg_return_t ipc_port_put(darling_mach_port_t* port)
89117{
90118 struct list_head* p;
···97125 }
98126 if (port->is_port_set)
99127 {
128128+ int bkt;
129129+ struct hlist_node *tmp;
130130+ struct darling_mach_port_le* ref;
131131+100132 // Iterate referenced ports
101101- list_for_each(p, &port->members)
133133+ hash_for_each_safe(port->members, bkt, tmp, ref, node)
102134 {
103103- darling_mach_port_t* ref;
135135+ ipc_port_lock(ref->port);
104136105105- ref = list_entry(p, darling_mach_port_t, set_head);
106106-107107- ipc_port_lock(ref);
108108- ref->set = NULL;
109109- ipc_port_unlock(ref);
137137+ // Find ref to self in port's list of sets
138138+ ipc_port_delete_set(port, ref->port);
139139+140140+ ipc_port_unlock(ref->port);
141141+142142+ kfree(ref);
110143 }
111144 }
112145 else // ordinary port
113146 {
114114- if (port->set != NULL)
147147+ int bkt;
148148+ struct hlist_node *tmp;
149149+ struct darling_mach_port_le* ref;
150150+ struct ipc_delivered_msg* msg;
151151+152152+ // Remove itself from all port sets we're in
153153+ hash_for_each_safe(port->sets, bkt, tmp, ref, node)
115154 {
116116- list_del(&port->set_head);
117117- port->set = NULL;
155155+ ipc_port_lock(ref->port);
156156+157157+ // Find ref to self in port sets's list of ports
158158+ ipc_portset_delete_member(ref->port, port);
159159+160160+ ipc_port_unlock(ref->port);
161161+162162+ kfree(ref);
118163 }
164164+165165+ // set recipient_died to true for all pending msgs
166166+ list_for_each_entry(msg, &port->messages, list)
167167+ {
168168+ msg->recipient_died = true;
169169+ }
170170+ wake_up_all(&port->queue_send);
171171+ wake_up_all(&port->queue_recv);
119172 }
120173121174 // mark all references as dead ports
···134187 }
135188 debug_msg("All refs to port %p are now dead\n", port);
136189137137- // TODO: Wake up any pending senders etc.
138138-139190 atomic_dec(&port_count);
140191 kfree(port);
192192+ return KERN_SUCCESS;
193193+}
194194+195195+kern_return_t ipc_portset_insert(darling_mach_port_t* pset, darling_mach_port_t* port)
196196+{
197197+ struct darling_mach_port_le *pset_member, *port_member;
198198+199199+ if (!pset->is_port_set || port->is_port_set)
200200+ return KERN_INVALID_RIGHT;
201201+202202+ pset_member = (struct darling_mach_port_le*) kmalloc(sizeof(*pset_member), GFP_KERNEL);
203203+ if (pset_member == NULL)
204204+ return KERN_RESOURCE_SHORTAGE;
205205+206206+ port_member = (struct darling_mach_port_le*) kmalloc(sizeof(*pset_member), GFP_KERNEL);
207207+ if (port_member == NULL)
208208+ {
209209+ kfree(pset_member);
210210+ return KERN_RESOURCE_SHORTAGE;
211211+ }
212212+213213+ pset_member->port = port;
214214+ port_member->port = pset;
215215+216216+ hash_add(pset->members, &pset_member->node, (long)port);
217217+ hash_add(port->sets, &port_member->node, (long)pset);
218218+219219+ return KERN_SUCCESS;
220220+}
221221+222222+kern_return_t ipc_portset_move(darling_mach_port_t* pset, darling_mach_port_t* port)
223223+{
224224+ int bkt;
225225+ struct hlist_node *tmp;
226226+ struct darling_mach_port_le* ref;
227227+228228+ if (port->is_port_set)
229229+ return KERN_INVALID_RIGHT;
230230+ if (pset != NULL && !pset->is_port_set)
231231+ return KERN_INVALID_RIGHT;
232232+233233+ // Remove port from all port sets it is in
234234+ hash_for_each_safe(port->sets, bkt, tmp, ref, node)
235235+ {
236236+ // Delete ref on the pset side
237237+ ipc_portset_delete_member(pset, port);
238238+239239+ kfree(ref);
240240+ }
241241+242242+ // Kill all entries
243243+ hash_init(port->sets);
244244+245245+ if (pset != NULL)
246246+ return ipc_portset_insert(pset, port);
247247+248248+ return KERN_SUCCESS;
249249+}
250250+251251+kern_return_t ipc_portset_extract(darling_mach_port_t* pset, darling_mach_port_t* port)
252252+{
253253+ if (!pset->is_port_set || port->is_port_set)
254254+ return KERN_INVALID_RIGHT;
255255+256256+ ipc_port_delete_set(pset, port);
257257+ ipc_portset_delete_member(pset, port);
258258+141259 return KERN_SUCCESS;
142260}
143261
+23-5
src/lkm/ipc_port.h
···2424#include <linux/mutex.h>
2525#include <linux/atomic.h>
2626#include <linux/wait.h>
2727+#include <linux/hashtable.h>
2728#include "ipc_msg.h"
28292930typedef struct server_port server_port_t;
···6263 struct list_head messages;
6364 unsigned int queue_size;
6465 wait_queue_head_t queue_send, queue_recv;
6565- darling_mach_port_t* set;
6666- struct list_head set_head;
6666+ DECLARE_HASHTABLE(sets, 8);
6767 };
6868-6969- /* Port set vars */
6868+ // Port sets
7069 struct
7170 {
7272- struct list_head members; // refers via set_head
7171+ DECLARE_HASHTABLE(members, 8);
7372 };
7473 };
7574};
76757676+// Special type for darling_mach_port list entries
7777+// because ports may be in multiple port sets
7878+struct darling_mach_port_le
7979+{
8080+ struct hlist_node node;
8181+ struct darling_mach_port* port;
8282+};
8383+7784struct mach_port_right;
78857986struct ipc_delivered_msg
···8592 unsigned char delivered : 1;
8693 // Set to 1 if this struct is to be deleted by recipient
8794 unsigned char recipient_freed : 1;
9595+ // When set to 1, the receiving port has died and says goodbye
9696+ unsigned char recipient_died : 1;
8897};
89989099mach_msg_return_t ipc_port_new(darling_mach_port_t** port);
91100mach_msg_return_t ipc_port_set_new(darling_mach_port_t** port);
101101+102102+// in/out: pset and port are locked
103103+kern_return_t ipc_portset_insert(darling_mach_port_t* pset, darling_mach_port_t* port);
104104+105105+// in/out: pset and port are locked
106106+kern_return_t ipc_portset_extract(darling_mach_port_t* pset, darling_mach_port_t* port);
107107+108108+// in/out: pset and port are locked, pset may be null
109109+kern_return_t ipc_portset_move(darling_mach_port_t* pset, darling_mach_port_t* port);
9211093111/**
94112 * Deallocates the port. Marks all refering rights as PORT_DEAD.