]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/mach_kernelrpc.c
xnu-7195.60.75.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
A
39#include <vm/vm_protos.h>
40
f427ee49
A
41kern_return_t
42mach_port_get_attributes(
43 ipc_space_t space,
44 mach_port_name_t name,
45 int flavor,
46 mach_port_info_t info,
47 mach_msg_type_number_t *count);
48
316670eb
A
49int
50_kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args *args)
51{
52 mach_vm_offset_t addr;
53 task_t task = port_name_to_task(args->target);
54 int rv = MACH_SEND_INVALID_DEST;
55
0a7de745 56 if (task != current_task()) {
316670eb 57 goto done;
0a7de745 58 }
316670eb 59
0a7de745 60 if (copyin(args->addr, (char *)&addr, sizeof(addr))) {
316670eb 61 goto done;
0a7de745 62 }
316670eb 63
5ba3f43e 64 rv = mach_vm_allocate_external(task->map, &addr, args->size, args->flags);
0a7de745
A
65 if (rv == KERN_SUCCESS) {
66 rv = copyout(&addr, args->addr, sizeof(addr));
67 }
68
316670eb 69done:
0a7de745 70 if (task) {
316670eb 71 task_deallocate(task);
0a7de745
A
72 }
73 return rv;
316670eb
A
74}
75
76int
77_kernelrpc_mach_vm_deallocate_trap(struct _kernelrpc_mach_vm_deallocate_args *args)
78{
79 task_t task = port_name_to_task(args->target);
80 int rv = MACH_SEND_INVALID_DEST;
81
0a7de745 82 if (task != current_task()) {
316670eb 83 goto done;
0a7de745 84 }
316670eb
A
85
86 rv = mach_vm_deallocate(task->map, args->address, args->size);
0a7de745 87
316670eb 88done:
0a7de745 89 if (task) {
316670eb 90 task_deallocate(task);
0a7de745
A
91 }
92 return rv;
316670eb
A
93}
94
95int
96_kernelrpc_mach_vm_protect_trap(struct _kernelrpc_mach_vm_protect_args *args)
97{
98 task_t task = port_name_to_task(args->target);
99 int rv = MACH_SEND_INVALID_DEST;
100
0a7de745 101 if (task != current_task()) {
316670eb 102 goto done;
0a7de745 103 }
316670eb
A
104
105 rv = mach_vm_protect(task->map, args->address, args->size,
106 args->set_maximum, args->new_protection);
0a7de745 107
316670eb 108done:
0a7de745 109 if (task) {
316670eb 110 task_deallocate(task);
0a7de745
A
111 }
112 return rv;
316670eb
A
113}
114
39236c6e
A
115int
116_kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args *args)
117{
118 mach_vm_offset_t addr;
119 task_t task = port_name_to_task(args->target);
120 int rv = MACH_SEND_INVALID_DEST;
121
0a7de745 122 if (task != current_task()) {
39236c6e 123 goto done;
0a7de745 124 }
39236c6e 125
0a7de745 126 if (copyin(args->addr, (char *)&addr, sizeof(addr))) {
39236c6e 127 goto done;
0a7de745 128 }
39236c6e 129
5ba3f43e 130 rv = mach_vm_map_external(task->map, &addr, args->size, args->mask, args->flags,
0a7de745
A
131 IPC_PORT_NULL, 0, FALSE, args->cur_protection, VM_PROT_ALL,
132 VM_INHERIT_DEFAULT);
133 if (rv == KERN_SUCCESS) {
134 rv = copyout(&addr, args->addr, sizeof(addr));
135 }
39236c6e
A
136
137done:
0a7de745 138 if (task) {
39236c6e 139 task_deallocate(task);
0a7de745
A
140 }
141 return rv;
39236c6e
A
142}
143
39037602
A
144int
145_kernelrpc_mach_vm_purgable_control_trap(
146 struct _kernelrpc_mach_vm_purgable_control_trap_args *args)
147{
148 int state;
149 task_t task = port_name_to_task(args->target);
150 int rv = MACH_SEND_INVALID_DEST;
151
0a7de745 152 if (task != current_task()) {
39037602 153 goto done;
0a7de745 154 }
39037602 155
0a7de745 156 if (copyin(args->state, (char *)&state, sizeof(state))) {
39037602 157 goto done;
0a7de745 158 }
39037602
A
159
160 rv = mach_vm_purgable_control(task->map,
0a7de745
A
161 args->address,
162 args->control,
163 &state);
164 if (rv == KERN_SUCCESS) {
165 rv = copyout(&state, args->state, sizeof(state));
166 }
167
39037602 168done:
0a7de745 169 if (task) {
39037602 170 task_deallocate(task);
0a7de745
A
171 }
172 return rv;
39037602
A
173}
174
316670eb
A
175int
176_kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args *args)
177{
178 task_t task = port_name_to_task(args->target);
179 mach_port_name_t name;
180 int rv = MACH_SEND_INVALID_DEST;
181
0a7de745 182 if (task != current_task()) {
316670eb 183 goto done;
0a7de745 184 }
316670eb
A
185
186 rv = mach_port_allocate(task->itk_space, args->right, &name);
0a7de745
A
187 if (rv == KERN_SUCCESS) {
188 rv = copyout(&name, args->name, sizeof(name));
189 }
190
316670eb 191
316670eb 192done:
0a7de745 193 if (task) {
316670eb 194 task_deallocate(task);
0a7de745
A
195 }
196 return rv;
316670eb
A
197}
198
316670eb
A
199int
200_kernelrpc_mach_port_deallocate_trap(struct _kernelrpc_mach_port_deallocate_args *args)
201{
202 task_t task = port_name_to_task(args->target);
203 int rv = MACH_SEND_INVALID_DEST;
204
0a7de745 205 if (task != current_task()) {
316670eb 206 goto done;
0a7de745 207 }
316670eb
A
208
209 rv = mach_port_deallocate(task->itk_space, args->name);
0a7de745 210
316670eb 211done:
0a7de745 212 if (task) {
316670eb 213 task_deallocate(task);
0a7de745
A
214 }
215 return rv;
316670eb
A
216}
217
218int
219_kernelrpc_mach_port_mod_refs_trap(struct _kernelrpc_mach_port_mod_refs_args *args)
220{
221 task_t task = port_name_to_task(args->target);
222 int rv = MACH_SEND_INVALID_DEST;
223
0a7de745 224 if (task != current_task()) {
316670eb 225 goto done;
0a7de745 226 }
316670eb
A
227
228 rv = mach_port_mod_refs(task->itk_space, args->name, args->right, args->delta);
0a7de745 229
316670eb 230done:
0a7de745 231 if (task) {
316670eb 232 task_deallocate(task);
0a7de745
A
233 }
234 return rv;
316670eb
A
235}
236
237
238int
239_kernelrpc_mach_port_move_member_trap(struct _kernelrpc_mach_port_move_member_args *args)
240{
241 task_t task = port_name_to_task(args->target);
242 int rv = MACH_SEND_INVALID_DEST;
243
0a7de745 244 if (task != current_task()) {
316670eb 245 goto done;
0a7de745 246 }
316670eb
A
247
248 rv = mach_port_move_member(task->itk_space, args->member, args->after);
0a7de745 249
316670eb 250done:
0a7de745 251 if (task) {
316670eb 252 task_deallocate(task);
0a7de745
A
253 }
254 return rv;
316670eb
A
255}
256
257int
258_kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args *args)
259{
260 task_t task = port_name_to_task(args->target);
261 ipc_port_t port;
262 mach_msg_type_name_t disp;
263 int rv = MACH_SEND_INVALID_DEST;
264
0a7de745 265 if (task != current_task()) {
316670eb 266 goto done;
0a7de745 267 }
316670eb 268
cb323159
A
269 if (args->name == args->poly) {
270 switch (args->polyPoly) {
271 case MACH_MSG_TYPE_MAKE_SEND:
272 case MACH_MSG_TYPE_COPY_SEND:
273 /* fastpath MAKE_SEND / COPY_SEND which is the most common case */
274 rv = ipc_object_insert_send_right(task->itk_space, args->poly,
275 args->polyPoly);
276 goto done;
277
278 default:
279 break;
280 }
281 }
282
316670eb 283 rv = ipc_object_copyin(task->itk_space, args->poly, args->polyPoly,
cb323159 284 (ipc_object_t *)&port, 0, NULL, IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND);
0a7de745 285 if (rv != KERN_SUCCESS) {
316670eb 286 goto done;
0a7de745 287 }
316670eb
A
288 disp = ipc_object_copyin_type(args->polyPoly);
289
290 rv = mach_port_insert_right(task->itk_space, args->name, port, disp);
cb323159
A
291 if (rv != KERN_SUCCESS && IP_VALID(port)) {
292 ipc_object_destroy(ip_to_object(port), disp);
d190cdc3 293 }
0a7de745 294
316670eb 295done:
0a7de745 296 if (task) {
316670eb 297 task_deallocate(task);
0a7de745
A
298 }
299 return rv;
316670eb
A
300}
301
d9a64523
A
302int
303_kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args *args)
304{
f427ee49 305 task_inspect_t task = port_name_to_task_read_no_eval(args->target);
d9a64523
A
306 int rv = MACH_SEND_INVALID_DEST;
307 mach_msg_type_number_t count;
308
0a7de745 309 if (task != current_task()) {
d9a64523 310 goto done;
0a7de745 311 }
d9a64523
A
312
313 // MIG does not define the type or size of the mach_port_info_t out array
314 // anywhere, so derive them from the field in the generated reply struct
f427ee49 315#define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_from_user_t*)NULL)->port_info_out)
d9a64523
A
316#define MACH_PORT_INFO_STACK_LIMIT 80 // current size is 68 == 17 * sizeof(integer_t)
317 _Static_assert(sizeof(MACH_PORT_INFO_OUT) < MACH_PORT_INFO_STACK_LIMIT,
0a7de745
A
318 "mach_port_info_t has grown significantly, reevaluate stack usage");
319 const mach_msg_type_number_t max_count = (sizeof(MACH_PORT_INFO_OUT) / sizeof(MACH_PORT_INFO_OUT[0]));
d9a64523
A
320 typeof(MACH_PORT_INFO_OUT[0]) info[max_count];
321
b226f5e5
A
322 /*
323 * zero out our stack buffer because not all flavors of
324 * port_get_attributes initialize the whole struct
325 */
326 bzero(info, sizeof(MACH_PORT_INFO_OUT));
327
d9a64523
A
328 if (copyin(CAST_USER_ADDR_T(args->count), &count, sizeof(count))) {
329 rv = MACH_SEND_INVALID_DATA;
330 goto done;
331 }
0a7de745 332 if (count > max_count) {
d9a64523 333 count = max_count;
0a7de745 334 }
d9a64523
A
335
336 rv = mach_port_get_attributes(task->itk_space, args->name, args->flavor, info, &count);
0a7de745 337 if (rv == KERN_SUCCESS) {
d9a64523 338 rv = copyout(&count, CAST_USER_ADDR_T(args->count), sizeof(count));
0a7de745
A
339 }
340 if (rv == KERN_SUCCESS && count > 0) {
d9a64523 341 rv = copyout(info, CAST_USER_ADDR_T(args->info), count * sizeof(info[0]));
0a7de745 342 }
d9a64523
A
343
344done:
0a7de745 345 if (task) {
d9a64523 346 task_deallocate(task);
0a7de745
A
347 }
348 return rv;
d9a64523
A
349}
350
316670eb
A
351int
352_kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args *args)
353{
354 task_t task = port_name_to_task(args->target);
355 int rv = MACH_SEND_INVALID_DEST;
356
0a7de745 357 if (task != current_task()) {
316670eb 358 goto done;
0a7de745 359 }
316670eb
A
360
361 rv = mach_port_insert_member(task->itk_space, args->name, args->pset);
0a7de745 362
316670eb 363done:
0a7de745 364 if (task) {
316670eb 365 task_deallocate(task);
0a7de745
A
366 }
367 return rv;
316670eb
A
368}
369
370
371int
372_kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_args *args)
373{
374 task_t task = port_name_to_task(args->target);
375 int rv = MACH_SEND_INVALID_DEST;
376
0a7de745 377 if (task != current_task()) {
316670eb 378 goto done;
0a7de745 379 }
316670eb
A
380
381 rv = mach_port_extract_member(task->itk_space, args->name, args->pset);
0a7de745 382
316670eb 383done:
0a7de745 384 if (task) {
316670eb 385 task_deallocate(task);
0a7de745
A
386 }
387 return rv;
316670eb 388}
39236c6e
A
389
390int
391_kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args *args)
392{
393 task_t task = port_name_to_task(args->target);
394 mach_port_name_t name;
395 int rv = MACH_SEND_INVALID_DEST;
396 mach_port_options_t options;
397
0a7de745 398 if (copyin(args->options, (char *)&options, sizeof(options))) {
39236c6e
A
399 rv = MACH_SEND_INVALID_DATA;
400 goto done;
401 }
402
0a7de745 403 if (task != current_task()) {
39236c6e 404 goto done;
0a7de745 405 }
39236c6e
A
406
407 rv = mach_port_construct(task->itk_space, &options, args->context, &name);
0a7de745
A
408 if (rv == KERN_SUCCESS) {
409 rv = copyout(&name, args->name, sizeof(name));
410 }
39236c6e
A
411
412done:
0a7de745 413 if (task) {
39236c6e 414 task_deallocate(task);
0a7de745
A
415 }
416 return rv;
39236c6e
A
417}
418
419int
420_kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args *args)
421{
422 task_t task = port_name_to_task(args->target);
423 int rv = MACH_SEND_INVALID_DEST;
424
0a7de745 425 if (task != current_task()) {
39236c6e 426 goto done;
0a7de745 427 }
39236c6e
A
428
429 rv = mach_port_destruct(task->itk_space, args->name, args->srdelta, args->guard);
0a7de745 430
39236c6e 431done:
0a7de745 432 if (task) {
39236c6e 433 task_deallocate(task);
0a7de745
A
434 }
435 return rv;
39236c6e
A
436}
437
438int
439_kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args *args)
440{
441 task_t task = port_name_to_task(args->target);
442 int rv = MACH_SEND_INVALID_DEST;
443
0a7de745 444 if (task != current_task()) {
39236c6e 445 goto done;
0a7de745 446 }
39236c6e
A
447
448 rv = mach_port_guard(task->itk_space, args->name, args->guard, args->strict);
0a7de745 449
39236c6e 450done:
0a7de745 451 if (task) {
39236c6e 452 task_deallocate(task);
0a7de745
A
453 }
454 return rv;
39236c6e
A
455}
456
457int
458_kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args *args)
459{
460 task_t task = port_name_to_task(args->target);
461 int rv = MACH_SEND_INVALID_DEST;
462
0a7de745 463 if (task != current_task()) {
39236c6e 464 goto done;
0a7de745 465 }
39236c6e
A
466
467 rv = mach_port_unguard(task->itk_space, args->name, args->guard);
0a7de745 468
39236c6e 469done:
0a7de745 470 if (task) {
39236c6e 471 task_deallocate(task);
0a7de745
A
472 }
473 return rv;
39236c6e
A
474}
475
cb323159
A
476int
477_kernelrpc_mach_port_type_trap(struct _kernelrpc_mach_port_type_args *args)
478{
479 task_t task = port_name_to_task(args->target);
480 int rv = MACH_SEND_INVALID_DEST;
481 mach_port_type_t type;
482
483 if (task != current_task()) {
484 goto done;
485 }
486
487 rv = mach_port_type(task->itk_space, args->name, &type);
488 if (rv == KERN_SUCCESS) {
489 rv = copyout(&type, args->ptype, sizeof(type));
490 }
491
492done:
493 if (task) {
494 task_deallocate(task);
495 }
496 return rv;
497}
498
499int
500_kernelrpc_mach_port_request_notification_trap(
501 struct _kernelrpc_mach_port_request_notification_args *args)
502{
503 task_t task = port_name_to_task(args->target);
504 int rv = MACH_SEND_INVALID_DEST;
505 ipc_port_t notify, previous;
506 mach_msg_type_name_t disp;
507 mach_port_name_t previous_name = MACH_PORT_NULL;
508
509 if (task != current_task()) {
510 goto done;
511 }
512
513 disp = ipc_object_copyin_type(args->notifyPoly);
514 if (disp != MACH_MSG_TYPE_PORT_SEND_ONCE) {
515 goto done;
516 }
517
518 if (MACH_PORT_VALID(args->notify)) {
519 rv = ipc_object_copyin(task->itk_space, args->notify, args->notifyPoly,
520 (ipc_object_t *)&notify, 0, NULL, 0);
521 } else {
522 notify = CAST_MACH_NAME_TO_PORT(args->notify);
523 }
524 if (rv != KERN_SUCCESS) {
525 goto done;
526 }
527
528 rv = mach_port_request_notification(task->itk_space, args->name,
529 args->msgid, args->sync, notify, &previous);
530 if (rv != KERN_SUCCESS) {
531 ipc_object_destroy(ip_to_object(notify), disp);
532 goto done;
533 }
534
535 if (IP_VALID(previous)) {
536 // Remove once <rdar://problem/45522961> is fixed.
537 // We need to make ith_knote NULL as ipc_object_copyout() uses
538 // thread-argument-passing and its value should not be garbage
539 current_thread()->ith_knote = ITH_KNOTE_NULL;
540 rv = ipc_object_copyout(task->itk_space, ip_to_object(previous),
541 MACH_MSG_TYPE_PORT_SEND_ONCE, NULL, NULL, &previous_name);
542 if (rv != KERN_SUCCESS) {
543 ipc_object_destroy(ip_to_object(previous),
544 MACH_MSG_TYPE_PORT_SEND_ONCE);
545 goto done;
546 }
547 }
548
549 rv = copyout(&previous_name, args->previous, sizeof(previous_name));
550
551done:
552 if (task) {
553 task_deallocate(task);
554 }
555 return rv;
556}
557
39037602
A
558kern_return_t
559host_create_mach_voucher_trap(struct host_create_mach_voucher_args *args)
560{
561 host_t host = port_name_to_host(args->host);
562 ipc_voucher_t new_voucher = IV_NULL;
563 ipc_port_t voucher_port = IPC_PORT_NULL;
564 mach_port_name_t voucher_name = 0;
f427ee49 565 kern_return_t kr = KERN_SUCCESS;
39037602 566
0a7de745 567 if (host == HOST_NULL) {
39037602 568 return MACH_SEND_INVALID_DEST;
0a7de745 569 }
0a7de745 570 if (args->recipes_size < 0) {
39037602 571 return KERN_INVALID_ARGUMENT;
f427ee49
A
572 }
573 if (args->recipes_size > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) {
39037602 574 return MIG_ARRAY_TOO_LARGE;
0a7de745 575 }
39037602 576
f427ee49
A
577 /* keep small recipes on the stack for speed */
578 uint8_t buf[MACH_VOUCHER_TRAP_STACK_LIMIT];
579 uint8_t *krecipes = buf;
39037602 580
f427ee49
A
581 if (args->recipes_size > MACH_VOUCHER_TRAP_STACK_LIMIT) {
582 krecipes = kheap_alloc(KHEAP_TEMP, args->recipes_size, Z_WAITOK);
583 if (krecipes == NULL) {
584 return KERN_RESOURCE_SHORTAGE;
39037602 585 }
39037602
A
586 }
587
f427ee49
A
588 if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) {
589 kr = KERN_MEMORY_ERROR;
590 goto done;
591 }
39037602 592
f427ee49
A
593 kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
594 if (kr != KERN_SUCCESS) {
595 goto done;
39037602
A
596 }
597
f427ee49
A
598 voucher_port = convert_voucher_to_port(new_voucher);
599 voucher_name = ipc_port_copyout_send(voucher_port, current_space());
600
601 kr = copyout(&voucher_name, args->voucher, sizeof(voucher_name));
602
39037602 603done:
f427ee49
A
604 if (args->recipes_size > MACH_VOUCHER_TRAP_STACK_LIMIT) {
605 kheap_free(KHEAP_TEMP, krecipes, args->recipes_size);
606 }
607
39037602
A
608 return kr;
609}
610
611kern_return_t
612mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args)
613{
614 ipc_voucher_t voucher = IV_NULL;
615 kern_return_t kr = KERN_SUCCESS;
616 mach_msg_type_number_t sz = 0;
617
0a7de745 618 if (copyin(args->recipe_size, (void *)&sz, sizeof(sz))) {
39037602 619 return KERN_MEMORY_ERROR;
0a7de745 620 }
39037602 621
0a7de745 622 if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) {
39037602 623 return MIG_ARRAY_TOO_LARGE;
0a7de745 624 }
39037602
A
625
626 voucher = convert_port_name_to_voucher(args->voucher_name);
0a7de745 627 if (voucher == IV_NULL) {
39037602 628 return MACH_SEND_INVALID_DEST;
0a7de745 629 }
39037602 630
f427ee49
A
631 /* keep small recipes on the stack for speed */
632 uint8_t buf[MACH_VOUCHER_TRAP_STACK_LIMIT];
633 uint8_t *krecipe = buf;
eee35659 634 mach_msg_type_number_t max_sz = sz;
39037602 635
f427ee49
A
636 if (max_sz > MACH_VOUCHER_TRAP_STACK_LIMIT) {
637 krecipe = kheap_alloc(KHEAP_TEMP, max_sz, Z_WAITOK);
39037602 638 if (!krecipe) {
f427ee49 639 return KERN_RESOURCE_SHORTAGE;
39037602 640 }
f427ee49 641 }
39037602 642
f427ee49
A
643 if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, max_sz)) {
644 kr = KERN_MEMORY_ERROR;
645 goto done;
646 }
39037602 647
f427ee49
A
648 kr = mach_voucher_extract_attr_recipe(voucher, args->key,
649 (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
650 assert(sz <= max_sz);
39037602 651
f427ee49
A
652 if (kr == KERN_SUCCESS && sz > 0) {
653 kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz);
39037602 654 }
0a7de745 655 if (kr == KERN_SUCCESS) {
d9a64523 656 kr = copyout(&sz, args->recipe_size, sizeof(sz));
0a7de745 657 }
39037602 658
f427ee49 659
39037602 660done:
f427ee49
A
661 if (max_sz > MACH_VOUCHER_TRAP_STACK_LIMIT) {
662 kheap_free(KHEAP_TEMP, krecipe, max_sz);
663 }
664
39037602
A
665 ipc_voucher_release(voucher);
666 return kr;
667}