]>
Commit | Line | Data |
---|---|---|
316670eb A |
1 | /* |
2 | * Copyright (c) 2011 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
316670eb A |
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. | |
0a7de745 | 14 | * |
316670eb A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
316670eb A |
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. | |
0a7de745 | 25 | * |
316670eb A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | ||
29 | #include <mach/mach_types.h> | |
30 | #include <mach/mach_traps.h> | |
31 | #include <mach/mach_vm_server.h> | |
32 | #include <mach/mach_port_server.h> | |
39037602 A |
33 | #include <mach/mach_host_server.h> |
34 | #include <mach/mach_voucher_server.h> | |
316670eb A |
35 | #include <mach/vm_map.h> |
36 | #include <kern/task.h> | |
37 | #include <kern/ipc_tt.h> | |
39037602 | 38 | #include <kern/kalloc.h> |
316670eb | 39 | #include <vm/vm_protos.h> |
c3c9b80d | 40 | #include <kdp/kdp_dyld.h> |
316670eb | 41 | |
f427ee49 A |
42 | kern_return_t |
43 | mach_port_get_attributes( | |
44 | ipc_space_t space, | |
45 | mach_port_name_t name, | |
46 | int flavor, | |
47 | mach_port_info_t info, | |
48 | mach_msg_type_number_t *count); | |
49 | ||
c3c9b80d A |
50 | extern lck_mtx_t g_dyldinfo_mtx; |
51 | ||
316670eb A |
52 | int |
53 | _kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args *args) | |
54 | { | |
55 | mach_vm_offset_t addr; | |
56 | task_t task = port_name_to_task(args->target); | |
57 | int rv = MACH_SEND_INVALID_DEST; | |
58 | ||
0a7de745 | 59 | if (task != current_task()) { |
316670eb | 60 | goto done; |
0a7de745 | 61 | } |
316670eb | 62 | |
0a7de745 | 63 | if (copyin(args->addr, (char *)&addr, sizeof(addr))) { |
316670eb | 64 | goto done; |
0a7de745 | 65 | } |
316670eb | 66 | |
5ba3f43e | 67 | rv = mach_vm_allocate_external(task->map, &addr, args->size, args->flags); |
0a7de745 A |
68 | if (rv == KERN_SUCCESS) { |
69 | rv = copyout(&addr, args->addr, sizeof(addr)); | |
70 | } | |
71 | ||
316670eb | 72 | done: |
0a7de745 | 73 | if (task) { |
316670eb | 74 | task_deallocate(task); |
0a7de745 A |
75 | } |
76 | return rv; | |
316670eb A |
77 | } |
78 | ||
79 | int | |
80 | _kernelrpc_mach_vm_deallocate_trap(struct _kernelrpc_mach_vm_deallocate_args *args) | |
81 | { | |
82 | task_t task = port_name_to_task(args->target); | |
83 | int rv = MACH_SEND_INVALID_DEST; | |
84 | ||
0a7de745 | 85 | if (task != current_task()) { |
316670eb | 86 | goto done; |
0a7de745 | 87 | } |
316670eb A |
88 | |
89 | rv = mach_vm_deallocate(task->map, args->address, args->size); | |
0a7de745 | 90 | |
316670eb | 91 | done: |
0a7de745 | 92 | if (task) { |
316670eb | 93 | task_deallocate(task); |
0a7de745 A |
94 | } |
95 | return rv; | |
316670eb A |
96 | } |
97 | ||
98 | int | |
99 | _kernelrpc_mach_vm_protect_trap(struct _kernelrpc_mach_vm_protect_args *args) | |
100 | { | |
101 | task_t task = port_name_to_task(args->target); | |
102 | int rv = MACH_SEND_INVALID_DEST; | |
103 | ||
0a7de745 | 104 | if (task != current_task()) { |
316670eb | 105 | goto done; |
0a7de745 | 106 | } |
316670eb A |
107 | |
108 | rv = mach_vm_protect(task->map, args->address, args->size, | |
109 | args->set_maximum, args->new_protection); | |
0a7de745 | 110 | |
316670eb | 111 | done: |
0a7de745 | 112 | if (task) { |
316670eb | 113 | task_deallocate(task); |
0a7de745 A |
114 | } |
115 | return rv; | |
316670eb A |
116 | } |
117 | ||
39236c6e A |
118 | int |
119 | _kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args *args) | |
120 | { | |
121 | mach_vm_offset_t addr; | |
122 | task_t task = port_name_to_task(args->target); | |
123 | int rv = MACH_SEND_INVALID_DEST; | |
124 | ||
0a7de745 | 125 | if (task != current_task()) { |
39236c6e | 126 | goto done; |
0a7de745 | 127 | } |
39236c6e | 128 | |
0a7de745 | 129 | if (copyin(args->addr, (char *)&addr, sizeof(addr))) { |
39236c6e | 130 | goto done; |
0a7de745 | 131 | } |
39236c6e | 132 | |
5ba3f43e | 133 | rv = mach_vm_map_external(task->map, &addr, args->size, args->mask, args->flags, |
0a7de745 A |
134 | IPC_PORT_NULL, 0, FALSE, args->cur_protection, VM_PROT_ALL, |
135 | VM_INHERIT_DEFAULT); | |
136 | if (rv == KERN_SUCCESS) { | |
137 | rv = copyout(&addr, args->addr, sizeof(addr)); | |
138 | } | |
39236c6e A |
139 | |
140 | done: | |
0a7de745 | 141 | if (task) { |
39236c6e | 142 | task_deallocate(task); |
0a7de745 A |
143 | } |
144 | return rv; | |
39236c6e A |
145 | } |
146 | ||
39037602 A |
147 | int |
148 | _kernelrpc_mach_vm_purgable_control_trap( | |
149 | struct _kernelrpc_mach_vm_purgable_control_trap_args *args) | |
150 | { | |
151 | int state; | |
152 | task_t task = port_name_to_task(args->target); | |
153 | int rv = MACH_SEND_INVALID_DEST; | |
154 | ||
0a7de745 | 155 | if (task != current_task()) { |
39037602 | 156 | goto done; |
0a7de745 | 157 | } |
39037602 | 158 | |
0a7de745 | 159 | if (copyin(args->state, (char *)&state, sizeof(state))) { |
39037602 | 160 | goto done; |
0a7de745 | 161 | } |
39037602 A |
162 | |
163 | rv = mach_vm_purgable_control(task->map, | |
0a7de745 A |
164 | args->address, |
165 | args->control, | |
166 | &state); | |
167 | if (rv == KERN_SUCCESS) { | |
168 | rv = copyout(&state, args->state, sizeof(state)); | |
169 | } | |
170 | ||
39037602 | 171 | done: |
0a7de745 | 172 | if (task) { |
39037602 | 173 | task_deallocate(task); |
0a7de745 A |
174 | } |
175 | return rv; | |
39037602 A |
176 | } |
177 | ||
316670eb A |
178 | int |
179 | _kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args *args) | |
180 | { | |
181 | task_t task = port_name_to_task(args->target); | |
182 | mach_port_name_t name; | |
183 | int rv = MACH_SEND_INVALID_DEST; | |
184 | ||
0a7de745 | 185 | if (task != current_task()) { |
316670eb | 186 | goto done; |
0a7de745 | 187 | } |
316670eb A |
188 | |
189 | rv = mach_port_allocate(task->itk_space, args->right, &name); | |
0a7de745 A |
190 | if (rv == KERN_SUCCESS) { |
191 | rv = copyout(&name, args->name, sizeof(name)); | |
192 | } | |
193 | ||
316670eb | 194 | |
316670eb | 195 | done: |
0a7de745 | 196 | if (task) { |
316670eb | 197 | task_deallocate(task); |
0a7de745 A |
198 | } |
199 | return rv; | |
316670eb A |
200 | } |
201 | ||
316670eb A |
202 | int |
203 | _kernelrpc_mach_port_deallocate_trap(struct _kernelrpc_mach_port_deallocate_args *args) | |
204 | { | |
205 | task_t task = port_name_to_task(args->target); | |
206 | int rv = MACH_SEND_INVALID_DEST; | |
207 | ||
0a7de745 | 208 | if (task != current_task()) { |
316670eb | 209 | goto done; |
0a7de745 | 210 | } |
316670eb A |
211 | |
212 | rv = mach_port_deallocate(task->itk_space, args->name); | |
0a7de745 | 213 | |
316670eb | 214 | done: |
0a7de745 | 215 | if (task) { |
316670eb | 216 | task_deallocate(task); |
0a7de745 A |
217 | } |
218 | return rv; | |
316670eb A |
219 | } |
220 | ||
221 | int | |
222 | _kernelrpc_mach_port_mod_refs_trap(struct _kernelrpc_mach_port_mod_refs_args *args) | |
223 | { | |
224 | task_t task = port_name_to_task(args->target); | |
225 | int rv = MACH_SEND_INVALID_DEST; | |
226 | ||
0a7de745 | 227 | if (task != current_task()) { |
316670eb | 228 | goto done; |
0a7de745 | 229 | } |
316670eb A |
230 | |
231 | rv = mach_port_mod_refs(task->itk_space, args->name, args->right, args->delta); | |
0a7de745 | 232 | |
316670eb | 233 | done: |
0a7de745 | 234 | if (task) { |
316670eb | 235 | task_deallocate(task); |
0a7de745 A |
236 | } |
237 | return rv; | |
316670eb A |
238 | } |
239 | ||
240 | ||
241 | int | |
242 | _kernelrpc_mach_port_move_member_trap(struct _kernelrpc_mach_port_move_member_args *args) | |
243 | { | |
244 | task_t task = port_name_to_task(args->target); | |
245 | int rv = MACH_SEND_INVALID_DEST; | |
246 | ||
0a7de745 | 247 | if (task != current_task()) { |
316670eb | 248 | goto done; |
0a7de745 | 249 | } |
316670eb A |
250 | |
251 | rv = mach_port_move_member(task->itk_space, args->member, args->after); | |
0a7de745 | 252 | |
316670eb | 253 | done: |
0a7de745 | 254 | if (task) { |
316670eb | 255 | task_deallocate(task); |
0a7de745 A |
256 | } |
257 | return rv; | |
316670eb A |
258 | } |
259 | ||
260 | int | |
261 | _kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args *args) | |
262 | { | |
263 | task_t task = port_name_to_task(args->target); | |
264 | ipc_port_t port; | |
265 | mach_msg_type_name_t disp; | |
266 | int rv = MACH_SEND_INVALID_DEST; | |
267 | ||
0a7de745 | 268 | if (task != current_task()) { |
316670eb | 269 | goto done; |
0a7de745 | 270 | } |
316670eb | 271 | |
cb323159 A |
272 | if (args->name == args->poly) { |
273 | switch (args->polyPoly) { | |
274 | case MACH_MSG_TYPE_MAKE_SEND: | |
275 | case MACH_MSG_TYPE_COPY_SEND: | |
276 | /* fastpath MAKE_SEND / COPY_SEND which is the most common case */ | |
277 | rv = ipc_object_insert_send_right(task->itk_space, args->poly, | |
278 | args->polyPoly); | |
279 | goto done; | |
280 | ||
281 | default: | |
282 | break; | |
283 | } | |
284 | } | |
285 | ||
316670eb | 286 | rv = ipc_object_copyin(task->itk_space, args->poly, args->polyPoly, |
c3c9b80d | 287 | (ipc_object_t *)&port, 0, NULL, IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND); |
0a7de745 | 288 | if (rv != KERN_SUCCESS) { |
316670eb | 289 | goto done; |
0a7de745 | 290 | } |
316670eb A |
291 | disp = ipc_object_copyin_type(args->polyPoly); |
292 | ||
293 | rv = mach_port_insert_right(task->itk_space, args->name, port, disp); | |
cb323159 A |
294 | if (rv != KERN_SUCCESS && IP_VALID(port)) { |
295 | ipc_object_destroy(ip_to_object(port), disp); | |
d190cdc3 | 296 | } |
0a7de745 | 297 | |
316670eb | 298 | done: |
0a7de745 | 299 | if (task) { |
316670eb | 300 | task_deallocate(task); |
0a7de745 A |
301 | } |
302 | return rv; | |
316670eb A |
303 | } |
304 | ||
d9a64523 A |
305 | int |
306 | _kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args *args) | |
307 | { | |
c3c9b80d | 308 | task_read_t task = port_name_to_task_read_no_eval(args->target); |
d9a64523 A |
309 | int rv = MACH_SEND_INVALID_DEST; |
310 | mach_msg_type_number_t count; | |
311 | ||
0a7de745 | 312 | if (task != current_task()) { |
d9a64523 | 313 | goto done; |
0a7de745 | 314 | } |
d9a64523 A |
315 | |
316 | // MIG does not define the type or size of the mach_port_info_t out array | |
317 | // anywhere, so derive them from the field in the generated reply struct | |
f427ee49 | 318 | #define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_from_user_t*)NULL)->port_info_out) |
d9a64523 A |
319 | #define MACH_PORT_INFO_STACK_LIMIT 80 // current size is 68 == 17 * sizeof(integer_t) |
320 | _Static_assert(sizeof(MACH_PORT_INFO_OUT) < MACH_PORT_INFO_STACK_LIMIT, | |
0a7de745 A |
321 | "mach_port_info_t has grown significantly, reevaluate stack usage"); |
322 | const mach_msg_type_number_t max_count = (sizeof(MACH_PORT_INFO_OUT) / sizeof(MACH_PORT_INFO_OUT[0])); | |
d9a64523 A |
323 | typeof(MACH_PORT_INFO_OUT[0]) info[max_count]; |
324 | ||
b226f5e5 A |
325 | /* |
326 | * zero out our stack buffer because not all flavors of | |
327 | * port_get_attributes initialize the whole struct | |
328 | */ | |
329 | bzero(info, sizeof(MACH_PORT_INFO_OUT)); | |
330 | ||
d9a64523 A |
331 | if (copyin(CAST_USER_ADDR_T(args->count), &count, sizeof(count))) { |
332 | rv = MACH_SEND_INVALID_DATA; | |
333 | goto done; | |
334 | } | |
0a7de745 | 335 | if (count > max_count) { |
d9a64523 | 336 | count = max_count; |
0a7de745 | 337 | } |
d9a64523 A |
338 | |
339 | rv = mach_port_get_attributes(task->itk_space, args->name, args->flavor, info, &count); | |
0a7de745 | 340 | if (rv == KERN_SUCCESS) { |
d9a64523 | 341 | rv = copyout(&count, CAST_USER_ADDR_T(args->count), sizeof(count)); |
0a7de745 A |
342 | } |
343 | if (rv == KERN_SUCCESS && count > 0) { | |
d9a64523 | 344 | rv = copyout(info, CAST_USER_ADDR_T(args->info), count * sizeof(info[0])); |
0a7de745 | 345 | } |
d9a64523 A |
346 | |
347 | done: | |
0a7de745 | 348 | if (task) { |
d9a64523 | 349 | task_deallocate(task); |
0a7de745 A |
350 | } |
351 | return rv; | |
d9a64523 A |
352 | } |
353 | ||
316670eb A |
354 | int |
355 | _kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args *args) | |
356 | { | |
357 | task_t task = port_name_to_task(args->target); | |
358 | int rv = MACH_SEND_INVALID_DEST; | |
359 | ||
0a7de745 | 360 | if (task != current_task()) { |
316670eb | 361 | goto done; |
0a7de745 | 362 | } |
316670eb A |
363 | |
364 | rv = mach_port_insert_member(task->itk_space, args->name, args->pset); | |
0a7de745 | 365 | |
316670eb | 366 | done: |
0a7de745 | 367 | if (task) { |
316670eb | 368 | task_deallocate(task); |
0a7de745 A |
369 | } |
370 | return rv; | |
316670eb A |
371 | } |
372 | ||
373 | ||
374 | int | |
375 | _kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_args *args) | |
376 | { | |
377 | task_t task = port_name_to_task(args->target); | |
378 | int rv = MACH_SEND_INVALID_DEST; | |
379 | ||
0a7de745 | 380 | if (task != current_task()) { |
316670eb | 381 | goto done; |
0a7de745 | 382 | } |
316670eb A |
383 | |
384 | rv = mach_port_extract_member(task->itk_space, args->name, args->pset); | |
0a7de745 | 385 | |
316670eb | 386 | done: |
0a7de745 | 387 | if (task) { |
316670eb | 388 | task_deallocate(task); |
0a7de745 A |
389 | } |
390 | return rv; | |
316670eb | 391 | } |
39236c6e A |
392 | |
393 | int | |
394 | _kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args *args) | |
395 | { | |
396 | task_t task = port_name_to_task(args->target); | |
397 | mach_port_name_t name; | |
398 | int rv = MACH_SEND_INVALID_DEST; | |
399 | mach_port_options_t options; | |
400 | ||
0a7de745 | 401 | if (copyin(args->options, (char *)&options, sizeof(options))) { |
39236c6e A |
402 | rv = MACH_SEND_INVALID_DATA; |
403 | goto done; | |
404 | } | |
405 | ||
0a7de745 | 406 | if (task != current_task()) { |
39236c6e | 407 | goto done; |
0a7de745 | 408 | } |
39236c6e A |
409 | |
410 | rv = mach_port_construct(task->itk_space, &options, args->context, &name); | |
0a7de745 A |
411 | if (rv == KERN_SUCCESS) { |
412 | rv = copyout(&name, args->name, sizeof(name)); | |
413 | } | |
39236c6e A |
414 | |
415 | done: | |
0a7de745 | 416 | if (task) { |
39236c6e | 417 | task_deallocate(task); |
0a7de745 A |
418 | } |
419 | return rv; | |
39236c6e A |
420 | } |
421 | ||
422 | int | |
423 | _kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args *args) | |
424 | { | |
425 | task_t task = port_name_to_task(args->target); | |
426 | int rv = MACH_SEND_INVALID_DEST; | |
427 | ||
0a7de745 | 428 | if (task != current_task()) { |
39236c6e | 429 | goto done; |
0a7de745 | 430 | } |
39236c6e A |
431 | |
432 | rv = mach_port_destruct(task->itk_space, args->name, args->srdelta, args->guard); | |
0a7de745 | 433 | |
39236c6e | 434 | done: |
0a7de745 | 435 | if (task) { |
39236c6e | 436 | task_deallocate(task); |
0a7de745 A |
437 | } |
438 | return rv; | |
39236c6e A |
439 | } |
440 | ||
441 | int | |
442 | _kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args *args) | |
443 | { | |
444 | task_t task = port_name_to_task(args->target); | |
445 | int rv = MACH_SEND_INVALID_DEST; | |
446 | ||
0a7de745 | 447 | if (task != current_task()) { |
39236c6e | 448 | goto done; |
0a7de745 | 449 | } |
39236c6e A |
450 | |
451 | rv = mach_port_guard(task->itk_space, args->name, args->guard, args->strict); | |
0a7de745 | 452 | |
39236c6e | 453 | done: |
0a7de745 | 454 | if (task) { |
39236c6e | 455 | task_deallocate(task); |
0a7de745 A |
456 | } |
457 | return rv; | |
39236c6e A |
458 | } |
459 | ||
460 | int | |
461 | _kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args *args) | |
462 | { | |
463 | task_t task = port_name_to_task(args->target); | |
464 | int rv = MACH_SEND_INVALID_DEST; | |
465 | ||
0a7de745 | 466 | if (task != current_task()) { |
39236c6e | 467 | goto done; |
0a7de745 | 468 | } |
39236c6e A |
469 | |
470 | rv = mach_port_unguard(task->itk_space, args->name, args->guard); | |
0a7de745 | 471 | |
39236c6e | 472 | done: |
0a7de745 | 473 | if (task) { |
39236c6e | 474 | task_deallocate(task); |
0a7de745 A |
475 | } |
476 | return rv; | |
39236c6e A |
477 | } |
478 | ||
cb323159 A |
479 | int |
480 | _kernelrpc_mach_port_type_trap(struct _kernelrpc_mach_port_type_args *args) | |
481 | { | |
482 | task_t task = port_name_to_task(args->target); | |
483 | int rv = MACH_SEND_INVALID_DEST; | |
484 | mach_port_type_t type; | |
485 | ||
486 | if (task != current_task()) { | |
487 | goto done; | |
488 | } | |
489 | ||
490 | rv = mach_port_type(task->itk_space, args->name, &type); | |
491 | if (rv == KERN_SUCCESS) { | |
492 | rv = copyout(&type, args->ptype, sizeof(type)); | |
493 | } | |
494 | ||
495 | done: | |
496 | if (task) { | |
497 | task_deallocate(task); | |
498 | } | |
499 | return rv; | |
500 | } | |
501 | ||
502 | int | |
503 | _kernelrpc_mach_port_request_notification_trap( | |
504 | struct _kernelrpc_mach_port_request_notification_args *args) | |
505 | { | |
506 | task_t task = port_name_to_task(args->target); | |
507 | int rv = MACH_SEND_INVALID_DEST; | |
508 | ipc_port_t notify, previous; | |
509 | mach_msg_type_name_t disp; | |
510 | mach_port_name_t previous_name = MACH_PORT_NULL; | |
511 | ||
512 | if (task != current_task()) { | |
513 | goto done; | |
514 | } | |
515 | ||
516 | disp = ipc_object_copyin_type(args->notifyPoly); | |
517 | if (disp != MACH_MSG_TYPE_PORT_SEND_ONCE) { | |
518 | goto done; | |
519 | } | |
520 | ||
521 | if (MACH_PORT_VALID(args->notify)) { | |
522 | rv = ipc_object_copyin(task->itk_space, args->notify, args->notifyPoly, | |
523 | (ipc_object_t *)¬ify, 0, NULL, 0); | |
524 | } else { | |
525 | notify = CAST_MACH_NAME_TO_PORT(args->notify); | |
526 | } | |
527 | if (rv != KERN_SUCCESS) { | |
528 | goto done; | |
529 | } | |
530 | ||
531 | rv = mach_port_request_notification(task->itk_space, args->name, | |
532 | args->msgid, args->sync, notify, &previous); | |
533 | if (rv != KERN_SUCCESS) { | |
534 | ipc_object_destroy(ip_to_object(notify), disp); | |
535 | goto done; | |
536 | } | |
537 | ||
538 | if (IP_VALID(previous)) { | |
539 | // Remove once <rdar://problem/45522961> is fixed. | |
540 | // We need to make ith_knote NULL as ipc_object_copyout() uses | |
541 | // thread-argument-passing and its value should not be garbage | |
542 | current_thread()->ith_knote = ITH_KNOTE_NULL; | |
543 | rv = ipc_object_copyout(task->itk_space, ip_to_object(previous), | |
c3c9b80d | 544 | MACH_MSG_TYPE_PORT_SEND_ONCE, IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, &previous_name); |
cb323159 | 545 | if (rv != KERN_SUCCESS) { |
cb323159 A |
546 | goto done; |
547 | } | |
548 | } | |
549 | ||
550 | rv = copyout(&previous_name, args->previous, sizeof(previous_name)); | |
551 | ||
552 | done: | |
553 | if (task) { | |
554 | task_deallocate(task); | |
555 | } | |
556 | return rv; | |
557 | } | |
558 | ||
39037602 A |
559 | kern_return_t |
560 | host_create_mach_voucher_trap(struct host_create_mach_voucher_args *args) | |
561 | { | |
562 | host_t host = port_name_to_host(args->host); | |
563 | ipc_voucher_t new_voucher = IV_NULL; | |
564 | ipc_port_t voucher_port = IPC_PORT_NULL; | |
565 | mach_port_name_t voucher_name = 0; | |
f427ee49 | 566 | kern_return_t kr = KERN_SUCCESS; |
39037602 | 567 | |
0a7de745 | 568 | if (host == HOST_NULL) { |
39037602 | 569 | return MACH_SEND_INVALID_DEST; |
0a7de745 | 570 | } |
0a7de745 | 571 | if (args->recipes_size < 0) { |
39037602 | 572 | return KERN_INVALID_ARGUMENT; |
f427ee49 A |
573 | } |
574 | if (args->recipes_size > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) { | |
39037602 | 575 | return MIG_ARRAY_TOO_LARGE; |
0a7de745 | 576 | } |
39037602 | 577 | |
f427ee49 A |
578 | /* keep small recipes on the stack for speed */ |
579 | uint8_t buf[MACH_VOUCHER_TRAP_STACK_LIMIT]; | |
580 | uint8_t *krecipes = buf; | |
39037602 | 581 | |
f427ee49 A |
582 | if (args->recipes_size > MACH_VOUCHER_TRAP_STACK_LIMIT) { |
583 | krecipes = kheap_alloc(KHEAP_TEMP, args->recipes_size, Z_WAITOK); | |
584 | if (krecipes == NULL) { | |
585 | return KERN_RESOURCE_SHORTAGE; | |
39037602 | 586 | } |
39037602 A |
587 | } |
588 | ||
f427ee49 A |
589 | if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) { |
590 | kr = KERN_MEMORY_ERROR; | |
591 | goto done; | |
592 | } | |
39037602 | 593 | |
f427ee49 A |
594 | kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher); |
595 | if (kr != KERN_SUCCESS) { | |
596 | goto done; | |
39037602 A |
597 | } |
598 | ||
f427ee49 A |
599 | voucher_port = convert_voucher_to_port(new_voucher); |
600 | voucher_name = ipc_port_copyout_send(voucher_port, current_space()); | |
601 | ||
602 | kr = copyout(&voucher_name, args->voucher, sizeof(voucher_name)); | |
603 | ||
39037602 | 604 | done: |
f427ee49 A |
605 | if (args->recipes_size > MACH_VOUCHER_TRAP_STACK_LIMIT) { |
606 | kheap_free(KHEAP_TEMP, krecipes, args->recipes_size); | |
607 | } | |
608 | ||
39037602 A |
609 | return kr; |
610 | } | |
611 | ||
612 | kern_return_t | |
613 | mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args) | |
614 | { | |
615 | ipc_voucher_t voucher = IV_NULL; | |
616 | kern_return_t kr = KERN_SUCCESS; | |
617 | mach_msg_type_number_t sz = 0; | |
618 | ||
0a7de745 | 619 | if (copyin(args->recipe_size, (void *)&sz, sizeof(sz))) { |
39037602 | 620 | return KERN_MEMORY_ERROR; |
0a7de745 | 621 | } |
39037602 | 622 | |
0a7de745 | 623 | if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) { |
39037602 | 624 | return MIG_ARRAY_TOO_LARGE; |
0a7de745 | 625 | } |
39037602 A |
626 | |
627 | voucher = convert_port_name_to_voucher(args->voucher_name); | |
0a7de745 | 628 | if (voucher == IV_NULL) { |
39037602 | 629 | return MACH_SEND_INVALID_DEST; |
0a7de745 | 630 | } |
39037602 | 631 | |
f427ee49 A |
632 | /* keep small recipes on the stack for speed */ |
633 | uint8_t buf[MACH_VOUCHER_TRAP_STACK_LIMIT]; | |
634 | uint8_t *krecipe = buf; | |
eee35659 | 635 | mach_msg_type_number_t max_sz = sz; |
39037602 | 636 | |
f427ee49 A |
637 | if (max_sz > MACH_VOUCHER_TRAP_STACK_LIMIT) { |
638 | krecipe = kheap_alloc(KHEAP_TEMP, max_sz, Z_WAITOK); | |
39037602 | 639 | if (!krecipe) { |
f427ee49 | 640 | return KERN_RESOURCE_SHORTAGE; |
39037602 | 641 | } |
f427ee49 | 642 | } |
39037602 | 643 | |
f427ee49 A |
644 | if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, max_sz)) { |
645 | kr = KERN_MEMORY_ERROR; | |
646 | goto done; | |
647 | } | |
39037602 | 648 | |
f427ee49 A |
649 | kr = mach_voucher_extract_attr_recipe(voucher, args->key, |
650 | (mach_voucher_attr_raw_recipe_t)krecipe, &sz); | |
651 | assert(sz <= max_sz); | |
39037602 | 652 | |
f427ee49 A |
653 | if (kr == KERN_SUCCESS && sz > 0) { |
654 | kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz); | |
39037602 | 655 | } |
0a7de745 | 656 | if (kr == KERN_SUCCESS) { |
d9a64523 | 657 | kr = copyout(&sz, args->recipe_size, sizeof(sz)); |
0a7de745 | 658 | } |
39037602 | 659 | |
f427ee49 | 660 | |
39037602 | 661 | done: |
f427ee49 A |
662 | if (max_sz > MACH_VOUCHER_TRAP_STACK_LIMIT) { |
663 | kheap_free(KHEAP_TEMP, krecipe, max_sz); | |
664 | } | |
665 | ||
39037602 A |
666 | ipc_voucher_release(voucher); |
667 | return kr; | |
668 | } | |
c3c9b80d A |
669 | |
670 | /* | |
671 | * Mach Trap: task_dyld_process_info_notify_get_trap | |
672 | * | |
673 | * Return an array of active dyld notifier port names for current_task(). User | |
674 | * is responsible for allocating the memory for the mach port names array | |
675 | * and deallocating the port names inside the array returned. | |
676 | * | |
677 | * Does not consume any reference. | |
678 | * | |
679 | * Args: | |
680 | * names_addr: Address for mach port names array. (In param only) | |
681 | * names_count_addr: Number of active dyld notifier ports. (In-Out param) | |
682 | * In: Number of slots available for copyout in caller | |
683 | * Out: Actual number of ports copied out | |
684 | * | |
685 | * Returns: | |
686 | * | |
687 | * KERN_SUCCESS: A valid namesCnt is returned. (Can be zero) | |
688 | * KERN_INVALID_ARGUMENT: Arguments are invalid. | |
689 | * KERN_MEMORY_ERROR: Memory copyio operations failed. | |
690 | * KERN_NO_SPACE: User allocated memory for port names copyout is insufficient. | |
691 | * | |
692 | * Other error code see task_info(). | |
693 | */ | |
694 | kern_return_t | |
695 | task_dyld_process_info_notify_get_trap(struct task_dyld_process_info_notify_get_trap_args *args) | |
696 | { | |
697 | struct task_dyld_info dyld_info; | |
698 | mach_msg_type_number_t info_count = TASK_DYLD_INFO_COUNT; | |
699 | mach_port_name_t copyout_names[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT]; | |
700 | ipc_port_t copyout_ports[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT]; | |
701 | ipc_port_t release_ports[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT]; | |
702 | uint32_t copyout_count = 0, release_count = 0, active_count = 0; | |
703 | mach_vm_address_t ports_addr; /* a user space address */ | |
704 | mach_port_name_t new_name; | |
705 | natural_t user_names_count = 0; | |
706 | ipc_port_t sright; | |
707 | kern_return_t kr; | |
708 | ipc_port_t *portp; | |
709 | ipc_entry_t entry; | |
710 | ||
711 | if ((mach_port_name_array_t)args->names_addr == NULL || (natural_t *)args->names_count_addr == NULL) { | |
712 | return KERN_INVALID_ARGUMENT; | |
713 | } | |
714 | ||
715 | kr = copyin((vm_map_address_t)args->names_count_addr, &user_names_count, sizeof(natural_t)); | |
716 | if (kr) { | |
717 | return KERN_MEMORY_FAILURE; | |
718 | } | |
719 | ||
720 | if (user_names_count == 0) { | |
721 | return KERN_NO_SPACE; | |
722 | } | |
723 | ||
724 | kr = task_info(current_task(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &info_count); | |
725 | if (kr) { | |
726 | return kr; | |
727 | } | |
728 | ||
729 | if (dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32) { | |
730 | ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr + | |
731 | offsetof(struct user32_dyld_all_image_infos, notifyMachPorts)); | |
732 | } else { | |
733 | ports_addr = (mach_vm_address_t)(dyld_info.all_image_info_addr + | |
734 | offsetof(struct user64_dyld_all_image_infos, notifyMachPorts)); | |
735 | } | |
736 | ||
737 | lck_mtx_lock(&g_dyldinfo_mtx); | |
738 | itk_lock(current_task()); | |
739 | ||
740 | if (current_task()->itk_dyld_notify == NULL) { | |
741 | itk_unlock(current_task()); | |
742 | (void)copyoutmap_atomic32(current_task()->map, MACH_PORT_NULL, (vm_map_address_t)ports_addr); /* reset magic */ | |
743 | lck_mtx_unlock(&g_dyldinfo_mtx); | |
744 | ||
745 | kr = copyout(©out_count, (vm_map_address_t)args->names_count_addr, sizeof(natural_t)); | |
746 | return kr ? KERN_MEMORY_ERROR : KERN_SUCCESS; | |
747 | } | |
748 | ||
749 | for (int slot = 0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; slot++) { | |
750 | portp = ¤t_task()->itk_dyld_notify[slot]; | |
751 | if (*portp == IPC_PORT_NULL) { | |
752 | continue; | |
753 | } else { | |
754 | sright = ipc_port_copy_send(*portp); | |
755 | if (IP_VALID(sright)) { | |
756 | copyout_ports[active_count++] = sright; /* donates */ | |
757 | sright = IPC_PORT_NULL; | |
758 | } else { | |
759 | release_ports[release_count++] = *portp; /* donates */ | |
760 | *portp = IPC_PORT_NULL; | |
761 | } | |
762 | } | |
763 | } | |
764 | ||
765 | task_dyld_process_info_update_helper(current_task(), active_count, | |
766 | (vm_map_address_t)ports_addr, release_ports, release_count); | |
767 | /* itk_lock, g_dyldinfo_mtx are unlocked upon return */ | |
768 | ||
769 | for (int i = 0; i < active_count; i++) { | |
770 | sright = copyout_ports[i]; /* donates */ | |
771 | copyout_ports[i] = IPC_PORT_NULL; | |
772 | ||
773 | assert(IP_VALID(sright)); | |
774 | ip_reference(sright); | |
775 | /* | |
776 | * Below we consume each send right in copyout_ports, and if copyout_send | |
777 | * succeeds, replace it with a port ref; otherwise release the port ref. | |
778 | * | |
779 | * We can reuse copyout_ports array for this purpose since | |
780 | * copyout_count <= active_count. | |
781 | */ | |
782 | new_name = ipc_port_copyout_send(sright, current_space()); /* consumes */ | |
783 | if (MACH_PORT_VALID(new_name)) { | |
784 | copyout_names[copyout_count] = new_name; | |
785 | copyout_ports[copyout_count] = sright; /* now holds port ref */ | |
786 | copyout_count++; | |
787 | } else { | |
788 | ip_release(sright); | |
789 | } | |
790 | } | |
791 | ||
792 | assert(copyout_count <= active_count); | |
793 | ||
794 | if (user_names_count < copyout_count) { | |
795 | kr = KERN_NO_SPACE; | |
796 | goto copyout_failed; | |
797 | } | |
798 | ||
799 | /* copyout to caller's local copy */ | |
800 | kr = copyout(copyout_names, (vm_map_address_t)args->names_addr, | |
801 | copyout_count * sizeof(mach_port_name_t)); | |
802 | if (kr) { | |
803 | kr = KERN_MEMORY_ERROR; | |
804 | goto copyout_failed; | |
805 | } | |
806 | ||
807 | kr = copyout(©out_count, (vm_map_address_t)args->names_count_addr, sizeof(natural_t)); | |
808 | if (kr) { | |
809 | kr = KERN_MEMORY_ERROR; | |
810 | goto copyout_failed; | |
811 | } | |
812 | ||
813 | /* now, release port refs on copyout_ports */ | |
814 | for (int i = 0; i < copyout_count; i++) { | |
815 | sright = copyout_ports[i]; | |
816 | assert(IP_VALID(sright)); | |
817 | ip_release(sright); | |
818 | } | |
819 | ||
820 | return KERN_SUCCESS; | |
821 | ||
822 | ||
823 | copyout_failed: | |
824 | /* | |
825 | * No locks are held beyond this point. | |
826 | * | |
827 | * Release port refs on copyout_ports, and deallocate ports that we copied out | |
828 | * earlier. | |
829 | */ | |
830 | for (int i = 0; i < copyout_count; i++) { | |
831 | sright = copyout_ports[i]; | |
832 | assert(IP_VALID(sright)); | |
833 | ||
834 | if (ipc_right_lookup_write(current_space(), copyout_names[i], &entry)) { | |
835 | /* userspace has deallocated the name we copyout */ | |
836 | ip_release(sright); | |
837 | continue; | |
838 | } | |
839 | /* space is locked and active */ | |
840 | if (entry->ie_object == ip_to_object(sright) || | |
841 | IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_DEAD_NAME) { | |
842 | (void)ipc_right_dealloc(current_space(), copyout_names[i], entry); /* unlocks space */ | |
843 | } else { | |
844 | is_write_unlock(current_space()); | |
845 | } | |
846 | ||
847 | /* space is unlocked */ | |
848 | ip_release(sright); | |
849 | } | |
850 | ||
851 | return kr; | |
852 | } |