2 * Copyright (c) 2011 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
33 #include <mach/mach_host_server.h>
34 #include <mach/mach_voucher_server.h>
35 #include <mach/vm_map.h>
36 #include <kern/task.h>
37 #include <kern/ipc_tt.h>
38 #include <kern/kalloc.h>
39 #include <vm/vm_protos.h>
42 mach_port_get_attributes(
44 mach_port_name_t name
,
46 mach_port_info_t info
,
47 mach_msg_type_number_t
*count
);
50 _kernelrpc_mach_vm_allocate_trap(struct _kernelrpc_mach_vm_allocate_trap_args
*args
)
52 mach_vm_offset_t addr
;
53 task_t task
= port_name_to_task(args
->target
);
54 int rv
= MACH_SEND_INVALID_DEST
;
56 if (task
!= current_task()) {
60 if (copyin(args
->addr
, (char *)&addr
, sizeof(addr
))) {
64 rv
= mach_vm_allocate_external(task
->map
, &addr
, args
->size
, args
->flags
);
65 if (rv
== KERN_SUCCESS
) {
66 rv
= copyout(&addr
, args
->addr
, sizeof(addr
));
71 task_deallocate(task
);
77 _kernelrpc_mach_vm_deallocate_trap(struct _kernelrpc_mach_vm_deallocate_args
*args
)
79 task_t task
= port_name_to_task(args
->target
);
80 int rv
= MACH_SEND_INVALID_DEST
;
82 if (task
!= current_task()) {
86 rv
= mach_vm_deallocate(task
->map
, args
->address
, args
->size
);
90 task_deallocate(task
);
96 _kernelrpc_mach_vm_protect_trap(struct _kernelrpc_mach_vm_protect_args
*args
)
98 task_t task
= port_name_to_task(args
->target
);
99 int rv
= MACH_SEND_INVALID_DEST
;
101 if (task
!= current_task()) {
105 rv
= mach_vm_protect(task
->map
, args
->address
, args
->size
,
106 args
->set_maximum
, args
->new_protection
);
110 task_deallocate(task
);
116 _kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args
*args
)
118 mach_vm_offset_t addr
;
119 task_t task
= port_name_to_task(args
->target
);
120 int rv
= MACH_SEND_INVALID_DEST
;
122 if (task
!= current_task()) {
126 if (copyin(args
->addr
, (char *)&addr
, sizeof(addr
))) {
130 rv
= mach_vm_map_external(task
->map
, &addr
, args
->size
, args
->mask
, args
->flags
,
131 IPC_PORT_NULL
, 0, FALSE
, args
->cur_protection
, VM_PROT_ALL
,
133 if (rv
== KERN_SUCCESS
) {
134 rv
= copyout(&addr
, args
->addr
, sizeof(addr
));
139 task_deallocate(task
);
145 _kernelrpc_mach_vm_purgable_control_trap(
146 struct _kernelrpc_mach_vm_purgable_control_trap_args
*args
)
149 task_t task
= port_name_to_task(args
->target
);
150 int rv
= MACH_SEND_INVALID_DEST
;
152 if (task
!= current_task()) {
156 if (copyin(args
->state
, (char *)&state
, sizeof(state
))) {
160 rv
= mach_vm_purgable_control(task
->map
,
164 if (rv
== KERN_SUCCESS
) {
165 rv
= copyout(&state
, args
->state
, sizeof(state
));
170 task_deallocate(task
);
176 _kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args
*args
)
178 task_t task
= port_name_to_task(args
->target
);
179 mach_port_name_t name
;
180 int rv
= MACH_SEND_INVALID_DEST
;
182 if (task
!= current_task()) {
186 rv
= mach_port_allocate(task
->itk_space
, args
->right
, &name
);
187 if (rv
== KERN_SUCCESS
) {
188 rv
= copyout(&name
, args
->name
, sizeof(name
));
194 task_deallocate(task
);
200 _kernelrpc_mach_port_deallocate_trap(struct _kernelrpc_mach_port_deallocate_args
*args
)
202 task_t task
= port_name_to_task(args
->target
);
203 int rv
= MACH_SEND_INVALID_DEST
;
205 if (task
!= current_task()) {
209 rv
= mach_port_deallocate(task
->itk_space
, args
->name
);
213 task_deallocate(task
);
219 _kernelrpc_mach_port_mod_refs_trap(struct _kernelrpc_mach_port_mod_refs_args
*args
)
221 task_t task
= port_name_to_task(args
->target
);
222 int rv
= MACH_SEND_INVALID_DEST
;
224 if (task
!= current_task()) {
228 rv
= mach_port_mod_refs(task
->itk_space
, args
->name
, args
->right
, args
->delta
);
232 task_deallocate(task
);
239 _kernelrpc_mach_port_move_member_trap(struct _kernelrpc_mach_port_move_member_args
*args
)
241 task_t task
= port_name_to_task(args
->target
);
242 int rv
= MACH_SEND_INVALID_DEST
;
244 if (task
!= current_task()) {
248 rv
= mach_port_move_member(task
->itk_space
, args
->member
, args
->after
);
252 task_deallocate(task
);
258 _kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args
*args
)
260 task_t task
= port_name_to_task(args
->target
);
262 mach_msg_type_name_t disp
;
263 int rv
= MACH_SEND_INVALID_DEST
;
265 if (task
!= current_task()) {
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
,
283 rv
= ipc_object_copyin(task
->itk_space
, args
->poly
, args
->polyPoly
,
284 (ipc_object_t
*)&port
, 0, NULL
, IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND
);
285 if (rv
!= KERN_SUCCESS
) {
288 disp
= ipc_object_copyin_type(args
->polyPoly
);
290 rv
= mach_port_insert_right(task
->itk_space
, args
->name
, port
, disp
);
291 if (rv
!= KERN_SUCCESS
&& IP_VALID(port
)) {
292 ipc_object_destroy(ip_to_object(port
), disp
);
297 task_deallocate(task
);
303 _kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args
*args
)
305 task_inspect_t task
= port_name_to_task_read_no_eval(args
->target
);
306 int rv
= MACH_SEND_INVALID_DEST
;
307 mach_msg_type_number_t count
;
309 if (task
!= current_task()) {
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
315 #define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_from_user_t*)NULL)->port_info_out)
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
,
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]));
320 typeof(MACH_PORT_INFO_OUT
[0]) info
[max_count
];
323 * zero out our stack buffer because not all flavors of
324 * port_get_attributes initialize the whole struct
326 bzero(info
, sizeof(MACH_PORT_INFO_OUT
));
328 if (copyin(CAST_USER_ADDR_T(args
->count
), &count
, sizeof(count
))) {
329 rv
= MACH_SEND_INVALID_DATA
;
332 if (count
> max_count
) {
336 rv
= mach_port_get_attributes(task
->itk_space
, args
->name
, args
->flavor
, info
, &count
);
337 if (rv
== KERN_SUCCESS
) {
338 rv
= copyout(&count
, CAST_USER_ADDR_T(args
->count
), sizeof(count
));
340 if (rv
== KERN_SUCCESS
&& count
> 0) {
341 rv
= copyout(info
, CAST_USER_ADDR_T(args
->info
), count
* sizeof(info
[0]));
346 task_deallocate(task
);
352 _kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args
*args
)
354 task_t task
= port_name_to_task(args
->target
);
355 int rv
= MACH_SEND_INVALID_DEST
;
357 if (task
!= current_task()) {
361 rv
= mach_port_insert_member(task
->itk_space
, args
->name
, args
->pset
);
365 task_deallocate(task
);
372 _kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_args
*args
)
374 task_t task
= port_name_to_task(args
->target
);
375 int rv
= MACH_SEND_INVALID_DEST
;
377 if (task
!= current_task()) {
381 rv
= mach_port_extract_member(task
->itk_space
, args
->name
, args
->pset
);
385 task_deallocate(task
);
391 _kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args
*args
)
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
;
398 if (copyin(args
->options
, (char *)&options
, sizeof(options
))) {
399 rv
= MACH_SEND_INVALID_DATA
;
403 if (task
!= current_task()) {
407 rv
= mach_port_construct(task
->itk_space
, &options
, args
->context
, &name
);
408 if (rv
== KERN_SUCCESS
) {
409 rv
= copyout(&name
, args
->name
, sizeof(name
));
414 task_deallocate(task
);
420 _kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args
*args
)
422 task_t task
= port_name_to_task(args
->target
);
423 int rv
= MACH_SEND_INVALID_DEST
;
425 if (task
!= current_task()) {
429 rv
= mach_port_destruct(task
->itk_space
, args
->name
, args
->srdelta
, args
->guard
);
433 task_deallocate(task
);
439 _kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args
*args
)
441 task_t task
= port_name_to_task(args
->target
);
442 int rv
= MACH_SEND_INVALID_DEST
;
444 if (task
!= current_task()) {
448 rv
= mach_port_guard(task
->itk_space
, args
->name
, args
->guard
, args
->strict
);
452 task_deallocate(task
);
458 _kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args
*args
)
460 task_t task
= port_name_to_task(args
->target
);
461 int rv
= MACH_SEND_INVALID_DEST
;
463 if (task
!= current_task()) {
467 rv
= mach_port_unguard(task
->itk_space
, args
->name
, args
->guard
);
471 task_deallocate(task
);
477 _kernelrpc_mach_port_type_trap(struct _kernelrpc_mach_port_type_args
*args
)
479 task_t task
= port_name_to_task(args
->target
);
480 int rv
= MACH_SEND_INVALID_DEST
;
481 mach_port_type_t type
;
483 if (task
!= current_task()) {
487 rv
= mach_port_type(task
->itk_space
, args
->name
, &type
);
488 if (rv
== KERN_SUCCESS
) {
489 rv
= copyout(&type
, args
->ptype
, sizeof(type
));
494 task_deallocate(task
);
500 _kernelrpc_mach_port_request_notification_trap(
501 struct _kernelrpc_mach_port_request_notification_args
*args
)
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
;
509 if (task
!= current_task()) {
513 disp
= ipc_object_copyin_type(args
->notifyPoly
);
514 if (disp
!= MACH_MSG_TYPE_PORT_SEND_ONCE
) {
518 if (MACH_PORT_VALID(args
->notify
)) {
519 rv
= ipc_object_copyin(task
->itk_space
, args
->notify
, args
->notifyPoly
,
520 (ipc_object_t
*)¬ify
, 0, NULL
, 0);
522 notify
= CAST_MACH_NAME_TO_PORT(args
->notify
);
524 if (rv
!= KERN_SUCCESS
) {
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
);
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
);
549 rv
= copyout(&previous_name
, args
->previous
, sizeof(previous_name
));
553 task_deallocate(task
);
559 host_create_mach_voucher_trap(struct host_create_mach_voucher_args
*args
)
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;
565 kern_return_t kr
= KERN_SUCCESS
;
567 if (host
== HOST_NULL
) {
568 return MACH_SEND_INVALID_DEST
;
570 if (args
->recipes_size
< 0) {
571 return KERN_INVALID_ARGUMENT
;
573 if (args
->recipes_size
> MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE
) {
574 return MIG_ARRAY_TOO_LARGE
;
577 /* keep small recipes on the stack for speed */
578 uint8_t buf
[MACH_VOUCHER_TRAP_STACK_LIMIT
];
579 uint8_t *krecipes
= buf
;
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
;
588 if (copyin(CAST_USER_ADDR_T(args
->recipes
), (void *)krecipes
, args
->recipes_size
)) {
589 kr
= KERN_MEMORY_ERROR
;
593 kr
= host_create_mach_voucher(host
, krecipes
, args
->recipes_size
, &new_voucher
);
594 if (kr
!= KERN_SUCCESS
) {
598 voucher_port
= convert_voucher_to_port(new_voucher
);
599 voucher_name
= ipc_port_copyout_send(voucher_port
, current_space());
601 kr
= copyout(&voucher_name
, args
->voucher
, sizeof(voucher_name
));
604 if (args
->recipes_size
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
605 kheap_free(KHEAP_TEMP
, krecipes
, args
->recipes_size
);
612 mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args
*args
)
614 ipc_voucher_t voucher
= IV_NULL
;
615 kern_return_t kr
= KERN_SUCCESS
;
616 mach_msg_type_number_t sz
= 0;
618 if (copyin(args
->recipe_size
, (void *)&sz
, sizeof(sz
))) {
619 return KERN_MEMORY_ERROR
;
622 if (sz
> MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE
) {
623 return MIG_ARRAY_TOO_LARGE
;
626 voucher
= convert_port_name_to_voucher(args
->voucher_name
);
627 if (voucher
== IV_NULL
) {
628 return MACH_SEND_INVALID_DEST
;
631 /* keep small recipes on the stack for speed */
632 uint8_t buf
[MACH_VOUCHER_TRAP_STACK_LIMIT
];
633 uint8_t *krecipe
= buf
;
634 mach_msg_type_number_t max_sz
= sz
;
636 if (max_sz
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
637 krecipe
= kheap_alloc(KHEAP_TEMP
, max_sz
, Z_WAITOK
);
639 return KERN_RESOURCE_SHORTAGE
;
643 if (copyin(CAST_USER_ADDR_T(args
->recipe
), (void *)krecipe
, max_sz
)) {
644 kr
= KERN_MEMORY_ERROR
;
648 kr
= mach_voucher_extract_attr_recipe(voucher
, args
->key
,
649 (mach_voucher_attr_raw_recipe_t
)krecipe
, &sz
);
650 assert(sz
<= max_sz
);
652 if (kr
== KERN_SUCCESS
&& sz
> 0) {
653 kr
= copyout(krecipe
, CAST_USER_ADDR_T(args
->recipe
), sz
);
655 if (kr
== KERN_SUCCESS
) {
656 kr
= copyout(&sz
, args
->recipe_size
, sizeof(sz
));
661 if (max_sz
> MACH_VOUCHER_TRAP_STACK_LIMIT
) {
662 kheap_free(KHEAP_TEMP
, krecipe
, max_sz
);
665 ipc_voucher_release(voucher
);