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