]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/mach_kernelrpc.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_kernelrpc.c
CommitLineData
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
42kern_return_t
43mach_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
50extern lck_mtx_t g_dyldinfo_mtx;
51
316670eb
A
52int
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 72done:
0a7de745 73 if (task) {
316670eb 74 task_deallocate(task);
0a7de745
A
75 }
76 return rv;
316670eb
A
77}
78
79int
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 91done:
0a7de745 92 if (task) {
316670eb 93 task_deallocate(task);
0a7de745
A
94 }
95 return rv;
316670eb
A
96}
97
98int
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 111done:
0a7de745 112 if (task) {
316670eb 113 task_deallocate(task);
0a7de745
A
114 }
115 return rv;
316670eb
A
116}
117
39236c6e
A
118int
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
140done:
0a7de745 141 if (task) {
39236c6e 142 task_deallocate(task);
0a7de745
A
143 }
144 return rv;
39236c6e
A
145}
146
39037602
A
147int
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 171done:
0a7de745 172 if (task) {
39037602 173 task_deallocate(task);
0a7de745
A
174 }
175 return rv;
39037602
A
176}
177
316670eb
A
178int
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 195done:
0a7de745 196 if (task) {
316670eb 197 task_deallocate(task);
0a7de745
A
198 }
199 return rv;
316670eb
A
200}
201
316670eb
A
202int
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 214done:
0a7de745 215 if (task) {
316670eb 216 task_deallocate(task);
0a7de745
A
217 }
218 return rv;
316670eb
A
219}
220
221int
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 233done:
0a7de745 234 if (task) {
316670eb 235 task_deallocate(task);
0a7de745
A
236 }
237 return rv;
316670eb
A
238}
239
240
241int
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 253done:
0a7de745 254 if (task) {
316670eb 255 task_deallocate(task);
0a7de745
A
256 }
257 return rv;
316670eb
A
258}
259
260int
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 298done:
0a7de745 299 if (task) {
316670eb 300 task_deallocate(task);
0a7de745
A
301 }
302 return rv;
316670eb
A
303}
304
d9a64523
A
305int
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
347done:
0a7de745 348 if (task) {
d9a64523 349 task_deallocate(task);
0a7de745
A
350 }
351 return rv;
d9a64523
A
352}
353
316670eb
A
354int
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 366done:
0a7de745 367 if (task) {
316670eb 368 task_deallocate(task);
0a7de745
A
369 }
370 return rv;
316670eb
A
371}
372
373
374int
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 386done:
0a7de745 387 if (task) {
316670eb 388 task_deallocate(task);
0a7de745
A
389 }
390 return rv;
316670eb 391}
39236c6e
A
392
393int
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
415done:
0a7de745 416 if (task) {
39236c6e 417 task_deallocate(task);
0a7de745
A
418 }
419 return rv;
39236c6e
A
420}
421
422int
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 434done:
0a7de745 435 if (task) {
39236c6e 436 task_deallocate(task);
0a7de745
A
437 }
438 return rv;
39236c6e
A
439}
440
441int
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 453done:
0a7de745 454 if (task) {
39236c6e 455 task_deallocate(task);
0a7de745
A
456 }
457 return rv;
39236c6e
A
458}
459
460int
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 472done:
0a7de745 473 if (task) {
39236c6e 474 task_deallocate(task);
0a7de745
A
475 }
476 return rv;
39236c6e
A
477}
478
cb323159
A
479int
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
495done:
496 if (task) {
497 task_deallocate(task);
498 }
499 return rv;
500}
501
502int
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 *)&notify, 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
552done:
553 if (task) {
554 task_deallocate(task);
555 }
556 return rv;
557}
558
39037602
A
559kern_return_t
560host_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 604done:
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
612kern_return_t
613mach_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 661done:
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 */
694kern_return_t
695task_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(&copyout_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 = &current_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(&copyout_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
823copyout_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}