]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/mach_kernelrpc.c
xnu-3789.31.2.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_kernelrpc.c
index 75244966f01b67eb69a7a7635bcf4446a93535f1..1b50efbb70a949df9be73959ed61dc039732fc04 100644 (file)
 #include <mach/mach_traps.h>
 #include <mach/mach_vm_server.h>
 #include <mach/mach_port_server.h>
+#include <mach/mach_host_server.h>
+#include <mach/mach_voucher_server.h>
 #include <mach/vm_map.h>
 #include <kern/task.h>
 #include <kern/ipc_tt.h>
+#include <kern/kalloc.h>
 #include <vm/vm_protos.h>
 
 int
@@ -93,6 +96,58 @@ done:
        return (rv);
 }
 
+int
+_kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args *args)
+{
+       mach_vm_offset_t addr;
+       task_t task = port_name_to_task(args->target);
+       int rv = MACH_SEND_INVALID_DEST;
+
+       if (task != current_task())
+               goto done;
+
+       if (copyin(args->addr, (char *)&addr, sizeof (addr)))
+               goto done;
+
+       rv = mach_vm_map(task->map, &addr, args->size, args->mask, args->flags,
+                       IPC_PORT_NULL, 0, FALSE, args->cur_protection, VM_PROT_ALL,
+                       VM_INHERIT_DEFAULT);
+       if (rv == KERN_SUCCESS)
+               rv = copyout(&addr, args->addr, sizeof (addr));
+
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
+int
+_kernelrpc_mach_vm_purgable_control_trap(
+       struct _kernelrpc_mach_vm_purgable_control_trap_args *args)
+{
+       int state;
+       task_t task = port_name_to_task(args->target);
+       int rv = MACH_SEND_INVALID_DEST;
+
+       if (task != current_task())
+               goto done;
+
+       if (copyin(args->state, (char *)&state, sizeof (state)))
+               goto done;
+
+       rv = mach_vm_purgable_control(task->map,
+                                     args->address,
+                                     args->control,
+                                     &state);
+       if (rv == KERN_SUCCESS)
+               rv = copyout(&state, args->state, sizeof (state));
+       
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
 int
 _kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args *args)
 {
@@ -201,6 +256,11 @@ _kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_
        disp = ipc_object_copyin_type(args->polyPoly);
 
        rv = mach_port_insert_right(task->itk_space, args->name, port, disp);
+       if (rv != KERN_SUCCESS) {
+               if (IO_VALID((ipc_object_t)port)) {
+                       ipc_object_destroy((ipc_object_t)port, disp);
+               }
+       }
        
 done:
        if (task)
@@ -242,3 +302,194 @@ done:
                task_deallocate(task);
        return (rv);
 }
+
+int
+_kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args *args)
+{
+       task_t task = port_name_to_task(args->target);
+       mach_port_name_t name;
+       int rv = MACH_SEND_INVALID_DEST;
+       mach_port_options_t options;
+
+       if (copyin(args->options, (char *)&options, sizeof (options))) {
+               rv = MACH_SEND_INVALID_DATA;
+               goto done;
+       }
+
+       if (task != current_task())
+               goto done;
+
+       rv = mach_port_construct(task->itk_space, &options, args->context, &name);
+       if (rv == KERN_SUCCESS)
+               rv = copyout(&name, args->name, sizeof (name));
+
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
+int
+_kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args *args)
+{
+       task_t task = port_name_to_task(args->target);
+       int rv = MACH_SEND_INVALID_DEST;
+
+       if (task != current_task())
+               goto done;
+
+       rv = mach_port_destruct(task->itk_space, args->name, args->srdelta, args->guard);
+       
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
+int
+_kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args *args)
+{
+       task_t task = port_name_to_task(args->target);
+       int rv = MACH_SEND_INVALID_DEST;
+
+       if (task != current_task())
+               goto done;
+
+       rv = mach_port_guard(task->itk_space, args->name, args->guard, args->strict);
+       
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
+int
+_kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args *args)
+{
+       task_t task = port_name_to_task(args->target);
+       int rv = MACH_SEND_INVALID_DEST;
+
+       if (task != current_task())
+               goto done;
+
+       rv = mach_port_unguard(task->itk_space, args->name, args->guard);
+       
+done:
+       if (task)
+               task_deallocate(task);
+       return (rv);
+}
+
+kern_return_t
+host_create_mach_voucher_trap(struct host_create_mach_voucher_args *args)
+{
+       host_t host = port_name_to_host(args->host);
+       ipc_voucher_t new_voucher = IV_NULL;
+       ipc_port_t voucher_port = IPC_PORT_NULL;
+       mach_port_name_t voucher_name = 0;
+       kern_return_t kr = 0;
+
+       if (host == HOST_NULL)
+               return MACH_SEND_INVALID_DEST;
+
+       if (args->recipes_size < 0)
+               return KERN_INVALID_ARGUMENT;
+       else if (args->recipes_size > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
+               return MIG_ARRAY_TOO_LARGE;
+
+       if (args->recipes_size < MACH_VOUCHER_TRAP_STACK_LIMIT) {
+               /* keep small recipes on the stack for speed */
+               uint8_t krecipes[args->recipes_size];
+               if (copyin(args->recipes, (void *)krecipes, args->recipes_size)) {
+                       kr = KERN_MEMORY_ERROR;
+                       goto done;
+               }
+               kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
+       } else {
+               uint8_t *krecipes = kalloc((vm_size_t)args->recipes_size);
+               if (!krecipes) {
+                       kr = KERN_RESOURCE_SHORTAGE;
+                       goto done;
+               }
+
+               if (copyin(args->recipes, (void *)krecipes, args->recipes_size)) {
+                       kfree(krecipes, (vm_size_t)args->recipes_size);
+                       kr = KERN_MEMORY_ERROR;
+                       goto done;
+               }
+
+               kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
+               kfree(krecipes, (vm_size_t)args->recipes_size);
+       }
+
+       if (kr == 0) {
+               voucher_port = convert_voucher_to_port(new_voucher);
+               voucher_name = ipc_port_copyout_send(voucher_port, current_space());
+
+               kr = copyout(&voucher_name, args->voucher, sizeof(voucher_name));
+       }
+
+done:
+       return kr;
+}
+
+kern_return_t
+mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args)
+{
+       ipc_voucher_t voucher = IV_NULL;
+       kern_return_t kr = KERN_SUCCESS;
+       mach_msg_type_number_t sz = 0;
+
+       if (copyin(args->recipe_size, (void *)&sz, sizeof(sz)))
+               return KERN_MEMORY_ERROR;
+
+       if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
+               return MIG_ARRAY_TOO_LARGE;
+
+       voucher = convert_port_name_to_voucher(args->voucher_name);
+       if (voucher == IV_NULL)
+               return MACH_SEND_INVALID_DEST;
+
+       mach_msg_type_number_t __assert_only max_sz = sz;
+
+       if (sz < MACH_VOUCHER_TRAP_STACK_LIMIT) {
+               /* keep small recipes on the stack for speed */
+               uint8_t krecipe[sz];
+               if (copyin(args->recipe, (void *)krecipe, sz)) {
+                       kr = KERN_MEMORY_ERROR;
+                       goto done;
+               }
+               kr = mach_voucher_extract_attr_recipe(voucher, args->key,
+                                                     (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
+               assert(sz <= max_sz);
+
+               if (kr == KERN_SUCCESS && sz > 0)
+                       kr = copyout(krecipe, (void *)args->recipe, sz);
+       } else {
+               uint8_t *krecipe = kalloc((vm_size_t)sz);
+               if (!krecipe) {
+                       kr = KERN_RESOURCE_SHORTAGE;
+                       goto done;
+               }
+
+               if (copyin(args->recipe, (void *)krecipe, args->recipe_size)) {
+                       kfree(krecipe, (vm_size_t)sz);
+                       kr = KERN_MEMORY_ERROR;
+                       goto done;
+               }
+
+               kr = mach_voucher_extract_attr_recipe(voucher, args->key,
+                                                     (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
+               assert(sz <= max_sz);
+
+               if (kr == KERN_SUCCESS && sz > 0)
+                       kr = copyout(krecipe, (void *)args->recipe, sz);
+               kfree(krecipe, (vm_size_t)sz);
+       }
+
+       kr = copyout(&sz, args->recipe_size, sizeof(sz));
+
+done:
+       ipc_voucher_release(voucher);
+       return kr;
+}