this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement mk_timer Mach traps in LKM

+465 -18
+1 -1
src/lkm/Makefile
··· 25 25 servers/thread_act.o \ 26 26 mig/duct.o proc_entry.o bsd_ioctl.o \ 27 27 psynch/psynch_mutex.o psynch/pthread_kill.o \ 28 - psynch/psynch_cv.o 28 + psynch/psynch_cv.o primitives/timer.o 29 29 30 30 # Otherwise we were called directly from the command 31 31 # line; invoke the kernel build system.
+31 -3
src/lkm/api.h
··· 1 1 /* 2 2 * Darling Mach Linux Kernel Module 3 - * Copyright (C) 2015 Lubos Dolezel 3 + * Copyright (C) 2015-2017 Lubos Dolezel 4 4 * 5 5 * This program is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License ··· 21 21 #define LKM_API_H 22 22 #include <stdint.h> 23 23 24 - #define DARLING_MACH_API_VERSION 1 25 - #define DARLING_MACH_API_VERSION_STR "1" 24 + #define darling_mach_xstr(a) darling_mach_str(a) 25 + #define darling_mach_str(a) #a 26 + 27 + #define DARLING_MACH_API_VERSION 2 28 + #define DARLING_MACH_API_VERSION_STR darling_mach_xstr(DARLING_MACH_API_VERSION) 26 29 27 30 #define DARLING_MACH_API_BASE 0x1000 28 31 ··· 52 55 NR_psynch_cvwait_trap, // 0x15 53 56 NR_psynch_cvsignal_trap, 54 57 NR_psynch_cvbroad_trap, 58 + NR_mk_timer_create_trap, 59 + NR_mk_timer_arm_trap, 60 + NR_mk_timer_cancel_trap, 61 + NR_mk_timer_destroy_trap, 55 62 }; 56 63 57 64 struct mach_port_mod_refs_args ··· 214 221 uint32_t ugen; 215 222 uint64_t tid; 216 223 uint32_t flags; 224 + }; 225 + 226 + struct mk_timer_arm_args 227 + { 228 + unsigned int timer_port; 229 + /* This is mach_absolute_time() based time */ 230 + uint64_t expire_time; 231 + }; 232 + 233 + struct mk_timer_cancel_args 234 + { 235 + unsigned int timer_port; 236 + uint64_t* result_time; 237 + #ifdef __i386__ 238 + uint32_t pad1; 239 + #endif 240 + }; 241 + 242 + struct mk_timer_destroy_args 243 + { 244 + unsigned int timer_port; 217 245 }; 218 246 219 247 #pragma pack (pop)
+11 -7
src/lkm/ipc_msg.c
··· 433 433 debug_msg("ipc_msg_deliver()\n"); 434 434 435 435 // MIG call handling 436 - if (kmsg->target->port->is_server_port) 436 + if (kmsg->target->port->is_server_port && kmsg->target->port->server_port.subsystem != NULL) 437 437 { 438 438 debug_msg("--> invoke_server\n"); 439 439 return ipc_msg_invoke_server(kmsg, timeout, options); ··· 453 453 list_add(&delivery->list, &port->messages); 454 454 port->queue_size++; 455 455 456 + debug_msg("-> msg enqueued (%d b), waking up queue %p, queue size %d\n", kmsg->msg->msgh_size, &port->queue_recv, port->queue_size); 457 + 456 458 // Wake up waiting receivers 457 - wake_up_interruptible(&port->queue_recv); 459 + wake_up(&port->queue_recv); 458 460 459 461 // Wait (unless target is send once) 460 462 if (kmsg->target->type != MACH_PORT_RIGHT_SEND_ONCE) ··· 525 527 } 526 528 else 527 529 { 530 + debug_msg("msg delivered\n"); 528 531 darling_mach_port_t* port; 529 532 530 533 ipc_right_lock_port(kmsg->target); ··· 904 907 ipc_port_unlock(right->port); 905 908 locked = false; 906 909 907 - debug_msg("\t-> going to wait with timeout %d\n", timeout); 910 + debug_msg("\t-> going to wait with timeout %d on queue %p (intr: %d)\n", timeout, &right->port->queue_recv, options & MACH_RCV_INTERRUPT); 908 911 909 - 910 912 // wait for ipc_msg_deliver() to be called somewhere 911 913 if (timeout) 912 914 { ··· 927 929 { 928 930 if (options & MACH_RCV_INTERRUPT) 929 931 { 930 - err = wait_event_interruptible(right->port->queue_send, 932 + err = wait_event_interruptible(right->port->queue_recv, 931 933 (right->port->queue_size != 0 || !PORT_IS_VALID(right->port))); 932 934 } 933 935 else 934 936 { 935 - err = wait_event_killable(right->port->queue_send, 937 + err = wait_event_killable(right->port->queue_recv, 936 938 (right->port->queue_size != 0 || !PORT_IS_VALID(right->port))); 937 939 if (err == 0) 938 940 err = 1; 939 941 } 940 942 } 943 + 944 + debug_msg("\t-> woken up from waiting, queue size: %d\n", right->port->queue_size); 941 945 942 946 if (err == -ERESTARTSYS) 943 947 { ··· 1045 1049 { 1046 1050 // Mark the message as delivered and wake up the sender. 1047 1051 delivery->delivered = true; 1048 - wake_up_interruptible(&right->port->queue_send); 1052 + wake_up(&right->port->queue_send); 1049 1053 } 1050 1054 1051 1055 break;
+1 -1
src/lkm/ipc_port.c
··· 95 95 if (port->server_port.cb_free != NULL) 96 96 port->server_port.cb_free(&port->server_port); 97 97 } 98 - else if (port->is_port_set) 98 + if (port->is_port_set) 99 99 { 100 100 // Iterate referenced ports 101 101 list_for_each(p, &port->members)
+3 -3
src/lkm/ipc_port.h
··· 50 50 /* Whether this port is associated with a Mach server */ 51 51 bool is_server_port : 1; 52 52 bool is_port_set : 1; 53 + 54 + /* If is_server_port is true */ 55 + server_port_t server_port; 53 56 54 57 union 55 58 { 56 - /* If is_server_port is true */ 57 - server_port_t server_port; 58 - 59 59 /* Members for message exchange */ 60 60 struct 61 61 {
+1
src/lkm/ipc_server.h
··· 24 24 #include "traps.h" 25 25 26 26 #define PORT_TYPE_SEMAPHORE 1 27 + #define PORT_TYPE_TIMER 2 27 28 28 29 /* 29 30 * The following functions associate a port with the named kernel server.
+219
src/lkm/primitives/timer.c
··· 1 + /* 2 + * Darling Mach Linux Kernel Module 3 + * Copyright (C) 2017 Lubos Dolezel 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation; either version 2 8 + * of the License, or (at your option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 + */ 19 + 20 + #include <mach/mk_timer.h> 21 + #include "../mach_includes.h" 22 + #include "timer.h" 23 + #include "../ipc_server.h" 24 + #include "../ipc_port.h" 25 + #include "../ipc_right.h" 26 + #include "../debug.h" 27 + #include <linux/timer.h> 28 + #include <linux/jiffies.h> 29 + #include <linux/workqueue.h> 30 + #include <linux/delay.h> 31 + 32 + struct mach_timer 33 + { 34 + darling_mach_port_t* port; 35 + 36 + bool armed; 37 + uint64_t expire_time, arm_time; 38 + 39 + struct timer_list timer; 40 + 41 + struct work_struct work; 42 + }; 43 + 44 + static struct workqueue_struct* _mach_timer_wq; 45 + 46 + static void 47 + mach_timer_destroy(server_port_t* port); 48 + 49 + static void 50 + mach_timer_expired(unsigned long data); 51 + 52 + static void 53 + mach_timer_expired_worker(struct work_struct* work); 54 + 55 + void 56 + mach_timer_setup(darling_mach_port_t* port) 57 + { 58 + struct mach_timer* mt; 59 + 60 + port->is_server_port = true; 61 + port->server_port.port_type = PORT_TYPE_TIMER; 62 + port->server_port.subsystem = NULL; 63 + port->server_port.cb_free = mach_timer_destroy; 64 + 65 + mt = (struct mach_timer*) kmalloc(sizeof(struct mach_timer), 66 + GFP_KERNEL); 67 + port->server_port.private_data = mt; 68 + 69 + mt->port = port; 70 + mt->armed = false; 71 + 72 + setup_timer(&mt->timer, mach_timer_expired, (unsigned long) mt); 73 + INIT_WORK(&mt->work, mach_timer_expired_worker); 74 + } 75 + 76 + // Arm the timer. Change the expire time if it is already armed. 77 + kern_return_t 78 + mach_timer_arm(darling_mach_port_t* port, uint64_t expire_time) 79 + { 80 + struct mach_timer* mt = (struct mach_timer*) port->server_port.private_data; 81 + struct timespec now; 82 + int64_t diffns; 83 + 84 + ktime_get_ts(&now); 85 + 86 + mt->arm_time = now.tv_nsec + now.tv_sec * NSEC_PER_SEC; 87 + mt->expire_time = expire_time; 88 + mt->armed = true; 89 + 90 + diffns = expire_time - mt->arm_time; 91 + 92 + mod_timer(&mt->timer, jiffies + nsecs_to_jiffies(diffns)); 93 + 94 + return KERN_SUCCESS; 95 + } 96 + 97 + // Disarm the timer. Do nothing if it isn't armed. 98 + kern_return_t 99 + mach_timer_cancel(darling_mach_port_t* port, uint64_t* expire_time) 100 + { 101 + struct mach_timer* mt = (struct mach_timer*) port->server_port.private_data; 102 + 103 + if (mt->armed) 104 + { 105 + *expire_time = mt->expire_time; 106 + 107 + mt->armed = false; 108 + while (!del_timer(&mt->timer)) 109 + usleep_range(1000, 20000); 110 + } 111 + else 112 + *expire_time = 0; 113 + 114 + return KERN_SUCCESS; 115 + } 116 + 117 + void 118 + mach_timer_destroy(server_port_t* port) 119 + { 120 + struct mach_timer* mt; 121 + 122 + mt = (struct mach_timer*) port->private_data; 123 + 124 + if (mt->armed) 125 + { 126 + mt->armed = false; 127 + while (!del_timer(&mt->timer)) 128 + usleep_range(1000, 20000); 129 + 130 + // Ensure this timer hasn't just recently fired, 131 + // because we are about to be destroyed. 132 + flush_workqueue(_mach_timer_wq); 133 + } 134 + } 135 + 136 + // Executed in a workqueue 137 + static void 138 + mach_timer_expired_worker(struct work_struct* work) 139 + { 140 + struct mach_timer* mt; 141 + mk_timer_expire_msg_t* msg; 142 + struct ipc_kmsg* kmsg; 143 + darling_mach_port_right_t* send_once; 144 + kern_return_t rv; 145 + 146 + msg = (mk_timer_expire_msg_t*) kzalloc(sizeof(mk_timer_expire_msg_t), 147 + GFP_KERNEL); 148 + 149 + mt = container_of(work, struct mach_timer, work); 150 + 151 + #if 0 // It seems XNU no longer fills these out 152 + struct timespec now; 153 + 154 + msg->unused[0] = mt->arm_time; 155 + msg->unused[1] = mt->expire_time; 156 + 157 + ktime_get_ts(&now); 158 + 159 + msg->unused[2] = now.tv_nsec + now.tv_sec * NSEC_PER_SEC; 160 + #endif 161 + 162 + msg->header.msgh_size = sizeof(*msg); 163 + msg->header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0, 0, 0); 164 + 165 + // Create a temporary send once right and call ipc_msg_deliver(). 166 + ipc_port_lock(mt->port); 167 + send_once = ipc_right_new(mt->port, MACH_PORT_RIGHT_SEND_ONCE); 168 + 169 + // Allocate a kernel message wrapper 170 + kmsg = (struct ipc_kmsg*) kmalloc(sizeof(struct ipc_kmsg), GFP_KERNEL); 171 + 172 + kmsg->msg = (mach_msg_header_t*) msg; 173 + kmsg->target = send_once; 174 + kmsg->reply = NULL; 175 + kmsg->complex_items = NULL; 176 + 177 + // We specify no timeout, but messages sent to send once rights 178 + // are delivered asynchronously. 179 + rv = ipc_msg_deliver(kmsg, MACH_MSG_TIMEOUT_NONE, 0); 180 + 181 + kfree(kmsg); 182 + 183 + if (rv != KERN_SUCCESS) 184 + { 185 + debug_msg("Timer notification delivery failed: %d\n", rv); 186 + 187 + kfree(msg); 188 + // ipc_right_put(send_once); 189 + ipc_port_unlock(mt->port); 190 + } 191 + else 192 + debug_msg("Timer notification posted\n"); 193 + } 194 + 195 + // Executed in atomic context 196 + static void 197 + mach_timer_expired(unsigned long data) 198 + { 199 + struct mach_timer* mt = (struct mach_timer*) data; 200 + 201 + if (mt->armed) 202 + { 203 + mt->armed = false; 204 + queue_work(_mach_timer_wq, &mt->work); 205 + } 206 + } 207 + 208 + void 209 + mach_timer_init(void) 210 + { 211 + _mach_timer_wq = create_singlethread_workqueue("mach_timer"); 212 + } 213 + 214 + void 215 + mach_timer_exit(void) 216 + { 217 + destroy_workqueue(_mach_timer_wq); 218 + } 219 +
+40
src/lkm/primitives/timer.h
··· 1 + /* 2 + * Darling Mach Linux Kernel Module 3 + * Copyright (C) 2017 Lubos Dolezel 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation; either version 2 8 + * of the License, or (at your option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program; if not, write to the Free Software 17 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 + */ 19 + 20 + #ifndef _PRIMITIVES_TIMER_H 21 + #define _PRIMITIVES_TIMER_H 22 + #include "../ipc_types.h" 23 + 24 + void 25 + mach_timer_init(void); 26 + 27 + void 28 + mach_timer_exit(void); 29 + 30 + void 31 + mach_timer_setup(darling_mach_port_t* port); 32 + 33 + kern_return_t 34 + mach_timer_arm(darling_mach_port_t* port, uint64_t expire_time); 35 + 36 + kern_return_t 37 + mach_timer_cancel(darling_mach_port_t* port, uint64_t* expire_time); 38 + 39 + #endif 40 +
+147 -3
src/lkm/traps.c
··· 1 1 /* 2 2 * Darling Mach Linux Kernel Module 3 - * Copyright (C) 2015 Lubos Dolezel 3 + * Copyright (C) 2015-2017 Lubos Dolezel 4 4 * 5 5 * This program is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License ··· 42 42 #include "servers/mach_host.h" 43 43 #include "servers/thread_act.h" 44 44 #include "primitives/semaphore.h" 45 + #include "primitives/timer.h" 45 46 #include "psynch/psynch_mutex.h" 46 47 #include "psynch/pthread_kill.h" 47 48 #include "psynch/psynch_cv.h" ··· 60 61 61 62 #define TRAP(num, impl) [num - DARLING_MACH_API_BASE] = (trap_handler) impl 62 63 63 - static const trap_handler mach_traps[30] = { 64 + static const trap_handler mach_traps[40] = { 64 65 TRAP(NR_get_api_version, mach_get_api_version), 65 66 TRAP(NR_mach_reply_port, mach_reply_port_trap), 66 67 TRAP(NR__kernelrpc_mach_port_mod_refs, _kernelrpc_mach_port_mod_refs_trap), ··· 85 86 TRAP(NR_psynch_cvwait_trap, psynch_cvwait_trap), 86 87 TRAP(NR_psynch_cvsignal_trap, psynch_cvsignal_trap), 87 88 TRAP(NR_psynch_cvbroad_trap, psynch_cvbroad_trap), 89 + TRAP(NR_mk_timer_create_trap, mk_timer_create_trap), 90 + TRAP(NR_mk_timer_arm_trap, mk_timer_arm_trap), 91 + TRAP(NR_mk_timer_cancel_trap, mk_timer_cancel_trap), 92 + TRAP(NR_mk_timer_destroy_trap, mk_timer_destroy_trap), 88 93 }; 89 94 #undef TRAP 90 95 ··· 107 112 goto fail; 108 113 109 114 darling_task_init(); 115 + mach_timer_init(); 110 116 setup_proc_entry(); 111 117 ipc_space_init(&kernel_namespace); 112 118 ··· 118 124 ipc_port_make_host(host_port); 119 125 // ipc_space_make_receive(&kernel_namespace, host_port, &name); 120 126 121 - printk(KERN_INFO "Darling Mach kernel emulation loaded\n"); 127 + printk(KERN_INFO "Darling Mach kernel emulation loaded, API version " DARLING_MACH_API_VERSION_STR "\n"); 122 128 return 0; 123 129 124 130 fail: ··· 127 133 } 128 134 static void mach_exit(void) 129 135 { 136 + mach_timer_exit(); 130 137 ipc_port_put(host_port); 131 138 ipc_space_put(&kernel_namespace); 132 139 cleanup_proc_entry(); ··· 511 518 return KERN_INVALID_ADDRESS; 512 519 } 513 520 521 + // This call is always interruptible. 522 + // Non-interruptibility is emulated by mach_msg() wrapper in userspace. 523 + args.option |= MACH_SEND_INTERRUPT | MACH_RCV_INTERRUPT; 514 524 if (args.option & MACH_SEND_MSG) 515 525 { 516 526 mach_msg_header_t* msg; ··· 814 824 darling_task_deregister_thread(task, thread_self); 815 825 816 826 do_exit(0); 827 + } 828 + 829 + mach_port_name_t mk_timer_create_trap(mach_task_t* task) 830 + { 831 + mach_msg_return_t ret; 832 + mach_port_name_t name; 833 + darling_mach_port_t* port; 834 + 835 + ret = ipc_port_new(&port); 836 + if (ret != KERN_SUCCESS) 837 + return 0; 838 + 839 + mach_timer_setup(port); 840 + 841 + ret = ipc_space_make_receive(&task->namespace, port, &name); 842 + if (ret != KERN_SUCCESS) 843 + { 844 + ipc_port_put(port); 845 + return 0; 846 + } 847 + 848 + return name; 849 + } 850 + 851 + kern_return_t mk_timer_arm_trap(mach_task_t* task, 852 + struct mk_timer_arm_args* in_args) 853 + { 854 + struct mk_timer_arm_args args; 855 + kern_return_t ret = KERN_SUCCESS; 856 + darling_mach_port_right_t* right; 857 + 858 + if (copy_from_user(&args, in_args, sizeof(args))) 859 + return KERN_INVALID_ADDRESS; 860 + 861 + ipc_space_lock(&task->namespace); 862 + 863 + right = ipc_space_lookup(&task->namespace, args.timer_port); 864 + if (right == NULL || !PORT_IS_VALID(right->port)) 865 + { 866 + ret = KERN_INVALID_ARGUMENT; 867 + goto err; 868 + } 869 + 870 + if (!right->port->is_server_port || right->port->server_port.port_type != PORT_TYPE_TIMER) 871 + { 872 + ret = KERN_INVALID_ARGUMENT; 873 + ipc_port_unlock(right->port); 874 + goto err; 875 + } 876 + 877 + ret = mach_timer_arm(right->port, args.expire_time); 878 + 879 + ipc_port_unlock(right->port); 880 + 881 + err: 882 + ipc_space_unlock(&task->namespace); 883 + 884 + return ret; 885 + } 886 + 887 + kern_return_t mk_timer_cancel_trap(mach_task_t* task, 888 + struct mk_timer_cancel_args* in_args) 889 + { 890 + struct mk_timer_cancel_args args; 891 + kern_return_t ret = KERN_SUCCESS; 892 + darling_mach_port_right_t* right; 893 + uint64_t expire_time; 894 + 895 + if (copy_from_user(&args, in_args, sizeof(args))) 896 + return KERN_INVALID_ADDRESS; 897 + 898 + ipc_space_lock(&task->namespace); 899 + 900 + right = ipc_space_lookup(&task->namespace, args.timer_port); 901 + if (right == NULL || !PORT_IS_VALID(right->port)) 902 + { 903 + ret = KERN_INVALID_ARGUMENT; 904 + goto err; 905 + } 906 + 907 + if (!right->port->is_server_port || right->port->server_port.port_type != PORT_TYPE_TIMER) 908 + { 909 + ret = KERN_INVALID_ARGUMENT; 910 + ipc_port_unlock(right->port); 911 + goto err; 912 + } 913 + 914 + ret = mach_timer_cancel(right->port, &expire_time); 915 + if (copy_to_user(&expire_time, args.result_time, sizeof(expire_time))) 916 + ret = KERN_INVALID_ADDRESS; 917 + 918 + ipc_port_unlock(right->port); 919 + 920 + err: 921 + ipc_space_unlock(&task->namespace); 922 + 923 + return ret; 924 + } 925 + 926 + kern_return_t mk_timer_destroy_trap(mach_task_t* task, 927 + struct mk_timer_destroy_args* in_args) 928 + { 929 + struct mk_timer_destroy_args args; 930 + kern_return_t ret = KERN_SUCCESS; 931 + darling_mach_port_right_t* right; 932 + 933 + if (copy_from_user(&args, in_args, sizeof(args))) 934 + return KERN_INVALID_ADDRESS; 935 + 936 + ipc_space_lock(&task->namespace); 937 + 938 + right = ipc_space_lookup(&task->namespace, args.timer_port); 939 + if (right == NULL || !PORT_IS_VALID(right->port)) 940 + { 941 + ret = KERN_INVALID_ARGUMENT; 942 + goto err; 943 + } 944 + 945 + if (!right->port->is_server_port || right->port->server_port.port_type != PORT_TYPE_TIMER) 946 + { 947 + ret = KERN_INVALID_ARGUMENT; 948 + ipc_port_unlock(right->port); 949 + goto err; 950 + } 951 + 952 + ipc_port_unlock(right->port); 953 + 954 + ipc_space_unlock(&task->namespace); 955 + ret = ipc_space_right_put(&task->namespace, right); 956 + 957 + return ret; 958 + err: 959 + ipc_space_unlock(&task->namespace); 960 + return ret; 817 961 } 818 962 819 963 module_init(mach_init);
+11
src/lkm/traps.h
··· 60 60 kern_return_t bsdthread_terminate_trap(mach_task_t* task, 61 61 struct bsdthread_terminate_args* args); 62 62 63 + mach_port_name_t mk_timer_create_trap(mach_task_t* task); 64 + 65 + kern_return_t mk_timer_arm_trap(mach_task_t* task, 66 + struct mk_timer_arm_args* args); 67 + 68 + kern_return_t mk_timer_cancel_trap(mach_task_t* task, 69 + struct mk_timer_cancel_args* args); 70 + 71 + kern_return_t mk_timer_destroy_trap(mach_task_t* task, 72 + struct mk_timer_destroy_args* args); 73 + 63 74 // Internal 64 75 kern_return_t _kernelrpc_mach_port_destroy(mach_task_t* task, 65 76 mach_port_name_t task_name, mach_port_name_t right_name);