ipc_misc.c
1 /* 2 * Copyright (c) 2008, 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 #include <mach/mach_types.h> 29 #include <mach/notify.h> 30 #include <ipc/ipc_port.h> 31 #include <kern/ipc_kobject.h> 32 #include <kern/ipc_misc.h> 33 34 #include <mach/mach_port.h> 35 #include <mach/vm_map.h> 36 #include <vm/vm_map.h> 37 #include <vm/vm_kern.h> 38 39 extern void fileport_releasefg(struct fileglob *); 40 41 /* 42 * fileport_alloc 43 * 44 * Description: Obtain a send right for the given fileglob, which must be 45 * referenced. 46 * 47 * Parameters: fg A fileglob. 48 * 49 * Returns: Port of type IKOT_FILEPORT with fileglob set as its kobject. 50 * Port is returned with a send right. 51 */ 52 ipc_port_t 53 fileport_alloc(struct fileglob *fg) 54 { 55 return ipc_kobject_alloc_port((ipc_kobject_t)fg, IKOT_FILEPORT, 56 IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST); 57 } 58 59 60 /* 61 * fileport_get_fileglob 62 * 63 * Description: Obtain the fileglob associated with a given port. 64 * 65 * Parameters: port A Mach port of type IKOT_FILEPORT. 66 * 67 * Returns: NULL The given Mach port did not reference a 68 * fileglob. 69 * !NULL The fileglob that is associated with the 70 * Mach port. 71 * 72 * Notes: The caller must have a reference on the fileport. 73 */ 74 struct fileglob * 75 fileport_port_to_fileglob(ipc_port_t port) 76 { 77 struct fileglob *fg = NULL; 78 79 if (!IP_VALID(port)) { 80 return NULL; 81 } 82 83 ip_lock(port); 84 if (ip_active(port) && IKOT_FILEPORT == ip_kotype(port)) { 85 fg = (void *) ip_get_kobject(port); 86 } 87 ip_unlock(port); 88 89 return fg; 90 } 91 92 93 /* 94 * fileport_notify 95 * 96 * Description: Handle a no-senders notification for a fileport. Unless 97 * the message is spoofed, destroys the port and releases 98 * its reference on the fileglob. 99 * 100 * Parameters: msg A Mach no-senders notification message. 101 */ 102 void 103 fileport_notify(mach_msg_header_t *msg) 104 { 105 mach_no_senders_notification_t *notification = (void *)msg; 106 ipc_port_t port = notification->not_header.msgh_remote_port; 107 struct fileglob *fg = NULL; 108 109 if (!IP_VALID(port)) { 110 panic("Invalid port passed to fileport_notify()\n"); 111 } 112 113 ip_lock(port); 114 115 fg = (struct fileglob *) ip_get_kobject(port); 116 117 if (!ip_active(port)) { 118 panic("Inactive port passed to fileport_notify()\n"); 119 } 120 if (ip_kotype(port) != IKOT_FILEPORT) { 121 panic("Port of type other than IKOT_FILEPORT passed to fileport_notify()\n"); 122 } 123 if (fg == NULL) { 124 panic("fileport without an assocated fileglob\n"); 125 } 126 127 if (port->ip_srights == 0) { 128 ip_unlock(port); 129 130 fileport_releasefg(fg); 131 ipc_port_dealloc_kernel(port); 132 } else { 133 ip_unlock(port); 134 } 135 } 136 137 /* 138 * fileport_invoke 139 * 140 * Description: Invoke a function with the fileglob underlying the fileport. 141 * Returns the error code related to the fileglob lookup. 142 * 143 * Parameters: task The target task 144 * action The function to invoke with the fileglob 145 * arg Anonymous pointer to caller state 146 * rval The value returned from calling 'action' 147 */ 148 kern_return_t 149 fileport_invoke(task_t task, mach_port_name_t name, 150 int (*action)(mach_port_name_t, struct fileglob *, void *), 151 void *arg, int *rval) 152 { 153 kern_return_t kr; 154 ipc_port_t fileport; 155 struct fileglob *fg; 156 157 kr = ipc_object_copyin(task->itk_space, name, 158 MACH_MSG_TYPE_COPY_SEND, (ipc_object_t *)&fileport, 0, NULL, 159 IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND); 160 if (kr != KERN_SUCCESS) { 161 return kr; 162 } 163 164 if ((fg = fileport_port_to_fileglob(fileport)) != NULL) { 165 *rval = (*action)(name, fg, arg); 166 } else { 167 kr = KERN_FAILURE; 168 } 169 ipc_port_release_send(fileport); 170 return kr; 171 } 172 173 /* 174 * fileport_walk 175 * 176 * Description: Invoke the action function on every fileport in the task. 177 * 178 * This could be more efficient if we refactored mach_port_names() 179 * so that (a) it didn't compute the type information unless asked 180 * and (b) it could be asked to -not- unwire/copyout the memory 181 * and (c) if we could ask for port names by kobject type. Not 182 * clear that it's worth all that complexity, though. 183 * 184 * Parameters: task The target task 185 * action The function to invoke on each fileport 186 * arg Anonymous pointer to caller state. 187 */ 188 kern_return_t 189 fileport_walk(task_t task, 190 int (*action)(mach_port_name_t, struct fileglob *, void *arg), 191 void *arg) 192 { 193 mach_port_name_t *names; 194 mach_msg_type_number_t ncnt, tcnt; 195 vm_map_copy_t map_copy_names, map_copy_types; 196 vm_map_address_t map_names; 197 kern_return_t kr; 198 uint_t i; 199 int rval; 200 201 /* 202 * mach_port_names returns the 'name' and 'types' in copied-in 203 * form. Discard 'types' immediately, then copyout 'names' 204 * back into the kernel before walking the array. 205 */ 206 207 kr = mach_port_names(task->itk_space, 208 (mach_port_name_t **)&map_copy_names, &ncnt, 209 (mach_port_type_t **)&map_copy_types, &tcnt); 210 if (kr != KERN_SUCCESS) { 211 return kr; 212 } 213 214 vm_map_copy_discard(map_copy_types); 215 216 kr = vm_map_copyout(ipc_kernel_map, &map_names, map_copy_names); 217 if (kr != KERN_SUCCESS) { 218 vm_map_copy_discard(map_copy_names); 219 return kr; 220 } 221 names = (mach_port_name_t *)(uintptr_t)map_names; 222 223 for (rval = 0, i = 0; i < ncnt; i++) { 224 if (fileport_invoke(task, names[i], action, arg, 225 &rval) == KERN_SUCCESS && -1 == rval) { 226 break; /* early termination clause */ 227 } 228 } 229 vm_deallocate(ipc_kernel_map, 230 (vm_address_t)names, ncnt * sizeof(*names)); 231 return KERN_SUCCESS; 232 }