]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_kernelrpc.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_kernelrpc.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
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>
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>
40
41 int
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
48 if (task != current_task())
49 goto done;
50
51 if (copyin(args->addr, (char *)&addr, sizeof (addr)))
52 goto done;
53
54 rv = mach_vm_allocate_external(task->map, &addr, args->size, args->flags);
55 if (rv == KERN_SUCCESS)
56 rv = copyout(&addr, args->addr, sizeof (addr));
57
58 done:
59 if (task)
60 task_deallocate(task);
61 return (rv);
62 }
63
64 int
65 _kernelrpc_mach_vm_deallocate_trap(struct _kernelrpc_mach_vm_deallocate_args *args)
66 {
67 task_t task = port_name_to_task(args->target);
68 int rv = MACH_SEND_INVALID_DEST;
69
70 if (task != current_task())
71 goto done;
72
73 rv = mach_vm_deallocate(task->map, args->address, args->size);
74
75 done:
76 if (task)
77 task_deallocate(task);
78 return (rv);
79 }
80
81 int
82 _kernelrpc_mach_vm_protect_trap(struct _kernelrpc_mach_vm_protect_args *args)
83 {
84 task_t task = port_name_to_task(args->target);
85 int rv = MACH_SEND_INVALID_DEST;
86
87 if (task != current_task())
88 goto done;
89
90 rv = mach_vm_protect(task->map, args->address, args->size,
91 args->set_maximum, args->new_protection);
92
93 done:
94 if (task)
95 task_deallocate(task);
96 return (rv);
97 }
98
99 int
100 _kernelrpc_mach_vm_map_trap(struct _kernelrpc_mach_vm_map_trap_args *args)
101 {
102 mach_vm_offset_t addr;
103 task_t task = port_name_to_task(args->target);
104 int rv = MACH_SEND_INVALID_DEST;
105
106 if (task != current_task())
107 goto done;
108
109 if (copyin(args->addr, (char *)&addr, sizeof (addr)))
110 goto done;
111
112 rv = mach_vm_map_external(task->map, &addr, args->size, args->mask, args->flags,
113 IPC_PORT_NULL, 0, FALSE, args->cur_protection, VM_PROT_ALL,
114 VM_INHERIT_DEFAULT);
115 if (rv == KERN_SUCCESS)
116 rv = copyout(&addr, args->addr, sizeof (addr));
117
118 done:
119 if (task)
120 task_deallocate(task);
121 return (rv);
122 }
123
124 int
125 _kernelrpc_mach_vm_purgable_control_trap(
126 struct _kernelrpc_mach_vm_purgable_control_trap_args *args)
127 {
128 int state;
129 task_t task = port_name_to_task(args->target);
130 int rv = MACH_SEND_INVALID_DEST;
131
132 if (task != current_task())
133 goto done;
134
135 if (copyin(args->state, (char *)&state, sizeof (state)))
136 goto done;
137
138 rv = mach_vm_purgable_control(task->map,
139 args->address,
140 args->control,
141 &state);
142 if (rv == KERN_SUCCESS)
143 rv = copyout(&state, args->state, sizeof (state));
144
145 done:
146 if (task)
147 task_deallocate(task);
148 return (rv);
149 }
150
151 int
152 _kernelrpc_mach_port_allocate_trap(struct _kernelrpc_mach_port_allocate_args *args)
153 {
154 task_t task = port_name_to_task(args->target);
155 mach_port_name_t name;
156 int rv = MACH_SEND_INVALID_DEST;
157
158 if (task != current_task())
159 goto done;
160
161 rv = mach_port_allocate(task->itk_space, args->right, &name);
162 if (rv == KERN_SUCCESS)
163 rv = copyout(&name, args->name, sizeof (name));
164
165
166 done:
167 if (task)
168 task_deallocate(task);
169 return (rv);
170 }
171
172 int
173 _kernelrpc_mach_port_destroy_trap(struct _kernelrpc_mach_port_destroy_args *args)
174 {
175 task_t task = port_name_to_task(args->target);
176 int rv = MACH_SEND_INVALID_DEST;
177
178 if (task != current_task())
179 goto done;
180
181 rv = mach_port_destroy(task->itk_space, args->name);
182
183 done:
184 if (task)
185 task_deallocate(task);
186 return (rv);
187 }
188
189 int
190 _kernelrpc_mach_port_deallocate_trap(struct _kernelrpc_mach_port_deallocate_args *args)
191 {
192 task_t task = port_name_to_task(args->target);
193 int rv = MACH_SEND_INVALID_DEST;
194
195 if (task != current_task())
196 goto done;
197
198 rv = mach_port_deallocate(task->itk_space, args->name);
199
200 done:
201 if (task)
202 task_deallocate(task);
203 return (rv);
204 }
205
206 int
207 _kernelrpc_mach_port_mod_refs_trap(struct _kernelrpc_mach_port_mod_refs_args *args)
208 {
209 task_t task = port_name_to_task(args->target);
210 int rv = MACH_SEND_INVALID_DEST;
211
212 if (task != current_task())
213 goto done;
214
215 rv = mach_port_mod_refs(task->itk_space, args->name, args->right, args->delta);
216
217 done:
218 if (task)
219 task_deallocate(task);
220 return (rv);
221 }
222
223
224 int
225 _kernelrpc_mach_port_move_member_trap(struct _kernelrpc_mach_port_move_member_args *args)
226 {
227 task_t task = port_name_to_task(args->target);
228 int rv = MACH_SEND_INVALID_DEST;
229
230 if (task != current_task())
231 goto done;
232
233 rv = mach_port_move_member(task->itk_space, args->member, args->after);
234
235 done:
236 if (task)
237 task_deallocate(task);
238 return (rv);
239 }
240
241 int
242 _kernelrpc_mach_port_insert_right_trap(struct _kernelrpc_mach_port_insert_right_args *args)
243 {
244 task_t task = port_name_to_task(args->target);
245 ipc_port_t port;
246 mach_msg_type_name_t disp;
247 int rv = MACH_SEND_INVALID_DEST;
248
249 if (task != current_task())
250 goto done;
251
252 rv = ipc_object_copyin(task->itk_space, args->poly, args->polyPoly,
253 (ipc_object_t *)&port);
254 if (rv != KERN_SUCCESS)
255 goto done;
256 disp = ipc_object_copyin_type(args->polyPoly);
257
258 rv = mach_port_insert_right(task->itk_space, args->name, port, disp);
259 if (rv != KERN_SUCCESS) {
260 if (IO_VALID((ipc_object_t)port)) {
261 ipc_object_destroy((ipc_object_t)port, disp);
262 }
263 }
264
265 done:
266 if (task)
267 task_deallocate(task);
268 return (rv);
269 }
270
271 int
272 _kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args *args)
273 {
274 task_inspect_t task = port_name_to_task_inspect(args->target);
275 int rv = MACH_SEND_INVALID_DEST;
276 mach_msg_type_number_t count;
277
278 if (task != current_task())
279 goto done;
280
281 // MIG does not define the type or size of the mach_port_info_t out array
282 // anywhere, so derive them from the field in the generated reply struct
283 #define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_t*)NULL)->port_info_out)
284 #define MACH_PORT_INFO_STACK_LIMIT 80 // current size is 68 == 17 * sizeof(integer_t)
285 _Static_assert(sizeof(MACH_PORT_INFO_OUT) < MACH_PORT_INFO_STACK_LIMIT,
286 "mach_port_info_t has grown significantly, reevaluate stack usage");
287 const mach_msg_type_number_t max_count = (sizeof(MACH_PORT_INFO_OUT)/sizeof(MACH_PORT_INFO_OUT[0]));
288 typeof(MACH_PORT_INFO_OUT[0]) info[max_count];
289
290 if (copyin(CAST_USER_ADDR_T(args->count), &count, sizeof(count))) {
291 rv = MACH_SEND_INVALID_DATA;
292 goto done;
293 }
294 if (count > max_count)
295 count = max_count;
296
297 rv = mach_port_get_attributes(task->itk_space, args->name, args->flavor, info, &count);
298 if (rv == KERN_SUCCESS)
299 rv = copyout(&count, CAST_USER_ADDR_T(args->count), sizeof(count));
300 if (rv == KERN_SUCCESS && count > 0)
301 rv = copyout(info, CAST_USER_ADDR_T(args->info), count * sizeof(info[0]));
302
303 done:
304 if (task)
305 task_deallocate(task);
306 return (rv);
307 }
308
309 int
310 _kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args *args)
311 {
312 task_t task = port_name_to_task(args->target);
313 int rv = MACH_SEND_INVALID_DEST;
314
315 if (task != current_task())
316 goto done;
317
318 rv = mach_port_insert_member(task->itk_space, args->name, args->pset);
319
320 done:
321 if (task)
322 task_deallocate(task);
323 return (rv);
324 }
325
326
327 int
328 _kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_args *args)
329 {
330 task_t task = port_name_to_task(args->target);
331 int rv = MACH_SEND_INVALID_DEST;
332
333 if (task != current_task())
334 goto done;
335
336 rv = mach_port_extract_member(task->itk_space, args->name, args->pset);
337
338 done:
339 if (task)
340 task_deallocate(task);
341 return (rv);
342 }
343
344 int
345 _kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args *args)
346 {
347 task_t task = port_name_to_task(args->target);
348 mach_port_name_t name;
349 int rv = MACH_SEND_INVALID_DEST;
350 mach_port_options_t options;
351
352 if (copyin(args->options, (char *)&options, sizeof (options))) {
353 rv = MACH_SEND_INVALID_DATA;
354 goto done;
355 }
356
357 if (task != current_task())
358 goto done;
359
360 rv = mach_port_construct(task->itk_space, &options, args->context, &name);
361 if (rv == KERN_SUCCESS)
362 rv = copyout(&name, args->name, sizeof (name));
363
364 done:
365 if (task)
366 task_deallocate(task);
367 return (rv);
368 }
369
370 int
371 _kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args *args)
372 {
373 task_t task = port_name_to_task(args->target);
374 int rv = MACH_SEND_INVALID_DEST;
375
376 if (task != current_task())
377 goto done;
378
379 rv = mach_port_destruct(task->itk_space, args->name, args->srdelta, args->guard);
380
381 done:
382 if (task)
383 task_deallocate(task);
384 return (rv);
385 }
386
387 int
388 _kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args *args)
389 {
390 task_t task = port_name_to_task(args->target);
391 int rv = MACH_SEND_INVALID_DEST;
392
393 if (task != current_task())
394 goto done;
395
396 rv = mach_port_guard(task->itk_space, args->name, args->guard, args->strict);
397
398 done:
399 if (task)
400 task_deallocate(task);
401 return (rv);
402 }
403
404 int
405 _kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args *args)
406 {
407 task_t task = port_name_to_task(args->target);
408 int rv = MACH_SEND_INVALID_DEST;
409
410 if (task != current_task())
411 goto done;
412
413 rv = mach_port_unguard(task->itk_space, args->name, args->guard);
414
415 done:
416 if (task)
417 task_deallocate(task);
418 return (rv);
419 }
420
421 kern_return_t
422 host_create_mach_voucher_trap(struct host_create_mach_voucher_args *args)
423 {
424 host_t host = port_name_to_host(args->host);
425 ipc_voucher_t new_voucher = IV_NULL;
426 ipc_port_t voucher_port = IPC_PORT_NULL;
427 mach_port_name_t voucher_name = 0;
428 kern_return_t kr = 0;
429
430 if (host == HOST_NULL)
431 return MACH_SEND_INVALID_DEST;
432
433 if (args->recipes_size < 0)
434 return KERN_INVALID_ARGUMENT;
435 else if (args->recipes_size > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
436 return MIG_ARRAY_TOO_LARGE;
437
438 if (args->recipes_size < MACH_VOUCHER_TRAP_STACK_LIMIT) {
439 /* keep small recipes on the stack for speed */
440 uint8_t krecipes[args->recipes_size];
441 if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) {
442 kr = KERN_MEMORY_ERROR;
443 goto done;
444 }
445 kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
446 } else {
447 uint8_t *krecipes = kalloc((vm_size_t)args->recipes_size);
448 if (!krecipes) {
449 kr = KERN_RESOURCE_SHORTAGE;
450 goto done;
451 }
452
453 if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) {
454 kfree(krecipes, (vm_size_t)args->recipes_size);
455 kr = KERN_MEMORY_ERROR;
456 goto done;
457 }
458
459 kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
460 kfree(krecipes, (vm_size_t)args->recipes_size);
461 }
462
463 if (kr == 0) {
464 voucher_port = convert_voucher_to_port(new_voucher);
465 voucher_name = ipc_port_copyout_send(voucher_port, current_space());
466
467 kr = copyout(&voucher_name, args->voucher, sizeof(voucher_name));
468 }
469
470 done:
471 return kr;
472 }
473
474 kern_return_t
475 mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args)
476 {
477 ipc_voucher_t voucher = IV_NULL;
478 kern_return_t kr = KERN_SUCCESS;
479 mach_msg_type_number_t sz = 0;
480
481 if (copyin(args->recipe_size, (void *)&sz, sizeof(sz)))
482 return KERN_MEMORY_ERROR;
483
484 if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
485 return MIG_ARRAY_TOO_LARGE;
486
487 voucher = convert_port_name_to_voucher(args->voucher_name);
488 if (voucher == IV_NULL)
489 return MACH_SEND_INVALID_DEST;
490
491 mach_msg_type_number_t max_sz = sz;
492
493 if (sz < MACH_VOUCHER_TRAP_STACK_LIMIT) {
494 /* keep small recipes on the stack for speed */
495 uint8_t krecipe[sz];
496 if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, sz)) {
497 kr = KERN_MEMORY_ERROR;
498 goto done;
499 }
500 kr = mach_voucher_extract_attr_recipe(voucher, args->key,
501 (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
502 assert(sz <= max_sz);
503
504 if (kr == KERN_SUCCESS && sz > 0)
505 kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz);
506 } else {
507 uint8_t *krecipe = kalloc((vm_size_t)max_sz);
508 if (!krecipe) {
509 kr = KERN_RESOURCE_SHORTAGE;
510 goto done;
511 }
512
513 if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, sz)) {
514 kfree(krecipe, (vm_size_t)max_sz);
515 kr = KERN_MEMORY_ERROR;
516 goto done;
517 }
518
519 kr = mach_voucher_extract_attr_recipe(voucher, args->key,
520 (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
521 assert(sz <= max_sz);
522
523 if (kr == KERN_SUCCESS && sz > 0)
524 kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz);
525 kfree(krecipe, (vm_size_t)max_sz);
526 }
527
528 if (kr == KERN_SUCCESS)
529 kr = copyout(&sz, args->recipe_size, sizeof(sz));
530
531 done:
532 ipc_voucher_release(voucher);
533 return kr;
534 }