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 39extern 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 */ 52ipc_port_t 53fileport_alloc(struct fileglob *fg) 54{ 55 ipc_port_t fileport; 56 ipc_port_t sendport; 57 ipc_port_t notifyport; 58 59 fileport = ipc_port_alloc_kernel(); 60 if (fileport == IP_NULL) { 61 goto out; 62 } 63 64 ipc_kobject_set(fileport, (ipc_kobject_t)fg, IKOT_FILEPORT); 65 ip_lock(fileport); /* unlocked by ipc_port_nsrequest */ 66 notifyport = ipc_port_make_sonce_locked(fileport); 67 ipc_port_nsrequest(fileport, 1, notifyport, ¬ifyport); 68 69 sendport = ipc_port_make_send(fileport); 70 if (!IP_VALID(sendport)) { 71 panic("Couldn't allocate send right for fileport!\n"); 72 } 73 74out: 75 return fileport; 76} 77 78 79/* 80 * fileport_get_fileglob 81 * 82 * Description: Obtain the fileglob associated with a given port. 83 * 84 * Parameters: port A Mach port of type IKOT_FILEPORT. 85 * 86 * Returns: NULL The given Mach port did not reference a 87 * fileglob. 88 * !NULL The fileglob that is associated with the 89 * Mach port. 90 * 91 * Notes: The caller must have a reference on the fileport. 92 */ 93struct fileglob * 94fileport_port_to_fileglob(ipc_port_t port) 95{ 96 struct fileglob *fg = NULL; 97 98 if (!IP_VALID(port)) 99 return NULL; 100 101 ip_lock(port); 102 if (ip_active(port) && IKOT_FILEPORT == ip_kotype(port)) 103 fg = (void *)port->ip_kobject; 104 ip_unlock(port); 105 106 return fg; 107} 108 109 110/* 111 * fileport_notify 112 * 113 * Description: Handle a no-senders notification for a fileport. Unless 114 * the message is spoofed, destroys the port and releases 115 * its reference on the fileglob. 116 * 117 * Parameters: msg A Mach no-senders notification message. 118 */ 119void 120fileport_notify(mach_msg_header_t *msg) 121{ 122 mach_no_senders_notification_t *notification = (void *)msg; 123 ipc_port_t port = notification->not_header.msgh_remote_port; 124 struct fileglob *fg = NULL; 125 126 if (!IP_VALID(port)) 127 panic("Invalid port passed to fileport_notify()\n"); 128 129 ip_lock(port); 130 131 fg = (struct fileglob *)port->ip_kobject; 132 133 if (!ip_active(port)) 134 panic("Inactive port passed to fileport_notify()\n"); 135 if (ip_kotype(port) != IKOT_FILEPORT) 136 panic("Port of type other than IKOT_FILEPORT passed to fileport_notify()\n"); 137 if (fg == NULL) 138 panic("fileport without an assocated fileglob\n"); 139 140 if (port->ip_srights == 0) { 141 ip_unlock(port); 142 143 fileport_releasefg(fg); 144 ipc_port_dealloc_kernel(port); 145 } else { 146 ip_unlock(port); 147 } 148} 149 150/* 151 * fileport_invoke 152 * 153 * Description: Invoke a function with the fileglob underlying the fileport. 154 * Returns the error code related to the fileglob lookup. 155 * 156 * Parameters: task The target task 157 * action The function to invoke with the fileglob 158 * arg Anonymous pointer to caller state 159 * rval The value returned from calling 'action' 160 */ 161kern_return_t 162fileport_invoke(task_t task, mach_port_name_t name, 163 int (*action)(mach_port_name_t, struct fileglob *, void *), 164 void *arg, int *rval) 165{ 166 kern_return_t kr; 167 ipc_port_t fileport; 168 struct fileglob *fg; 169 170 kr = ipc_object_copyin(task->itk_space, name, 171 MACH_MSG_TYPE_COPY_SEND, (ipc_object_t *)&fileport); 172 if (kr != KERN_SUCCESS) 173 return (kr); 174 175 if ((fg = fileport_port_to_fileglob(fileport)) != NULL) 176 *rval = (*action)(name, fg, arg); 177 else 178 kr = KERN_FAILURE; 179 ipc_port_release_send(fileport); 180 return (kr); 181} 182 183/* 184 * fileport_walk 185 * 186 * Description: Invoke the action function on every fileport in the task. 187 * 188 * This could be more efficient if we refactored mach_port_names() 189 * so that (a) it didn't compute the type information unless asked 190 * and (b) it could be asked to -not- unwire/copyout the memory 191 * and (c) if we could ask for port names by kobject type. Not 192 * clear that it's worth all that complexity, though. 193 * 194 * Parameters: task The target task 195 * action The function to invoke on each fileport 196 * arg Anonymous pointer to caller state. 197 */ 198kern_return_t 199fileport_walk(task_t task, 200 int (*action)(mach_port_name_t, struct fileglob *, void *arg), 201 void *arg) 202{ 203 mach_port_name_t *names; 204 mach_msg_type_number_t ncnt, tcnt; 205 vm_map_copy_t map_copy_names, map_copy_types; 206 vm_map_address_t map_names; 207 kern_return_t kr; 208 uint_t i; 209 int rval; 210 211 /* 212 * mach_port_names returns the 'name' and 'types' in copied-in 213 * form. Discard 'types' immediately, then copyout 'names' 214 * back into the kernel before walking the array. 215 */ 216 217 kr = mach_port_names(task->itk_space, 218 (mach_port_name_t **)&map_copy_names, &ncnt, 219 (mach_port_type_t **)&map_copy_types, &tcnt); 220 if (kr != KERN_SUCCESS) 221 return (kr); 222 223 vm_map_copy_discard(map_copy_types); 224 225 kr = vm_map_copyout(ipc_kernel_map, &map_names, map_copy_names); 226 if (kr != KERN_SUCCESS) { 227 vm_map_copy_discard(map_copy_names); 228 return (kr); 229 } 230 names = (mach_port_name_t *)(uintptr_t)map_names; 231 232 for (rval = 0, i = 0; i < ncnt; i++) 233 if (fileport_invoke(task, names[i], action, arg, 234 &rval) == KERN_SUCCESS && -1 == rval) 235 break; /* early termination clause */ 236 237 vm_deallocate(ipc_kernel_map, 238 (vm_address_t)names, ncnt * sizeof (*names)); 239 return (KERN_SUCCESS); 240} 241