]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_kernelrpc.c
52bf7b11c6c723050a3218329bd86c11ebb5f9d5
[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
52 if (copyin(args->addr, (char *)&addr, sizeof(addr))) {
53 goto done;
54 }
55
56 rv = mach_vm_allocate_external(task->map, &addr, args->size, args->flags);
57 if (rv == KERN_SUCCESS) {
58 rv = copyout(&addr, args->addr, sizeof(addr));
59 }
60
61 done:
62 if (task) {
63 task_deallocate(task);
64 }
65 return rv;
66 }
67
68 int
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
74 if (task != current_task()) {
75 goto done;
76 }
77
78 rv = mach_vm_deallocate(task->map, args->address, args->size);
79
80 done:
81 if (task) {
82 task_deallocate(task);
83 }
84 return rv;
85 }
86
87 int
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
93 if (task != current_task()) {
94 goto done;
95 }
96
97 rv = mach_vm_protect(task->map, args->address, args->size,
98 args->set_maximum, args->new_protection);
99
100 done:
101 if (task) {
102 task_deallocate(task);
103 }
104 return rv;
105 }
106
107 int
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
114 if (task != current_task()) {
115 goto done;
116 }
117
118 if (copyin(args->addr, (char *)&addr, sizeof(addr))) {
119 goto done;
120 }
121
122 rv = mach_vm_map_external(task->map, &addr, args->size, args->mask, args->flags,
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 }
128
129 done:
130 if (task) {
131 task_deallocate(task);
132 }
133 return rv;
134 }
135
136 int
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
144 if (task != current_task()) {
145 goto done;
146 }
147
148 if (copyin(args->state, (char *)&state, sizeof(state))) {
149 goto done;
150 }
151
152 rv = mach_vm_purgable_control(task->map,
153 args->address,
154 args->control,
155 &state);
156 if (rv == KERN_SUCCESS) {
157 rv = copyout(&state, args->state, sizeof(state));
158 }
159
160 done:
161 if (task) {
162 task_deallocate(task);
163 }
164 return rv;
165 }
166
167 int
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
174 if (task != current_task()) {
175 goto done;
176 }
177
178 rv = mach_port_allocate(task->itk_space, args->right, &name);
179 if (rv == KERN_SUCCESS) {
180 rv = copyout(&name, args->name, sizeof(name));
181 }
182
183
184 done:
185 if (task) {
186 task_deallocate(task);
187 }
188 return rv;
189 }
190
191 int
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
197 if (task != current_task()) {
198 goto done;
199 }
200
201 rv = mach_port_destroy(task->itk_space, args->name);
202
203 done:
204 if (task) {
205 task_deallocate(task);
206 }
207 return rv;
208 }
209
210 int
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
216 if (task != current_task()) {
217 goto done;
218 }
219
220 rv = mach_port_deallocate(task->itk_space, args->name);
221
222 done:
223 if (task) {
224 task_deallocate(task);
225 }
226 return rv;
227 }
228
229 int
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
235 if (task != current_task()) {
236 goto done;
237 }
238
239 rv = mach_port_mod_refs(task->itk_space, args->name, args->right, args->delta);
240
241 done:
242 if (task) {
243 task_deallocate(task);
244 }
245 return rv;
246 }
247
248
249 int
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
255 if (task != current_task()) {
256 goto done;
257 }
258
259 rv = mach_port_move_member(task->itk_space, args->member, args->after);
260
261 done:
262 if (task) {
263 task_deallocate(task);
264 }
265 return rv;
266 }
267
268 int
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
276 if (task != current_task()) {
277 goto done;
278 }
279
280 rv = ipc_object_copyin(task->itk_space, args->poly, args->polyPoly,
281 (ipc_object_t *)&port);
282 if (rv != KERN_SUCCESS) {
283 goto done;
284 }
285 disp = ipc_object_copyin_type(args->polyPoly);
286
287 rv = mach_port_insert_right(task->itk_space, args->name, port, disp);
288 if (rv != KERN_SUCCESS) {
289 if (IO_VALID((ipc_object_t)port)) {
290 ipc_object_destroy((ipc_object_t)port, disp);
291 }
292 }
293
294 done:
295 if (task) {
296 task_deallocate(task);
297 }
298 return rv;
299 }
300
301 int
302 _kernelrpc_mach_port_get_attributes_trap(struct _kernelrpc_mach_port_get_attributes_args *args)
303 {
304 task_inspect_t task = port_name_to_task_inspect(args->target);
305 int rv = MACH_SEND_INVALID_DEST;
306 mach_msg_type_number_t count;
307
308 if (task != current_task()) {
309 goto done;
310 }
311
312 // MIG does not define the type or size of the mach_port_info_t out array
313 // anywhere, so derive them from the field in the generated reply struct
314 #define MACH_PORT_INFO_OUT (((__Reply__mach_port_get_attributes_t*)NULL)->port_info_out)
315 #define MACH_PORT_INFO_STACK_LIMIT 80 // current size is 68 == 17 * sizeof(integer_t)
316 _Static_assert(sizeof(MACH_PORT_INFO_OUT) < MACH_PORT_INFO_STACK_LIMIT,
317 "mach_port_info_t has grown significantly, reevaluate stack usage");
318 const mach_msg_type_number_t max_count = (sizeof(MACH_PORT_INFO_OUT) / sizeof(MACH_PORT_INFO_OUT[0]));
319 typeof(MACH_PORT_INFO_OUT[0]) info[max_count];
320
321 /*
322 * zero out our stack buffer because not all flavors of
323 * port_get_attributes initialize the whole struct
324 */
325 bzero(info, sizeof(MACH_PORT_INFO_OUT));
326
327 if (copyin(CAST_USER_ADDR_T(args->count), &count, sizeof(count))) {
328 rv = MACH_SEND_INVALID_DATA;
329 goto done;
330 }
331 if (count > max_count) {
332 count = max_count;
333 }
334
335 rv = mach_port_get_attributes(task->itk_space, args->name, args->flavor, info, &count);
336 if (rv == KERN_SUCCESS) {
337 rv = copyout(&count, CAST_USER_ADDR_T(args->count), sizeof(count));
338 }
339 if (rv == KERN_SUCCESS && count > 0) {
340 rv = copyout(info, CAST_USER_ADDR_T(args->info), count * sizeof(info[0]));
341 }
342
343 done:
344 if (task) {
345 task_deallocate(task);
346 }
347 return rv;
348 }
349
350 int
351 _kernelrpc_mach_port_insert_member_trap(struct _kernelrpc_mach_port_insert_member_args *args)
352 {
353 task_t task = port_name_to_task(args->target);
354 int rv = MACH_SEND_INVALID_DEST;
355
356 if (task != current_task()) {
357 goto done;
358 }
359
360 rv = mach_port_insert_member(task->itk_space, args->name, args->pset);
361
362 done:
363 if (task) {
364 task_deallocate(task);
365 }
366 return rv;
367 }
368
369
370 int
371 _kernelrpc_mach_port_extract_member_trap(struct _kernelrpc_mach_port_extract_member_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
380 rv = mach_port_extract_member(task->itk_space, args->name, args->pset);
381
382 done:
383 if (task) {
384 task_deallocate(task);
385 }
386 return rv;
387 }
388
389 int
390 _kernelrpc_mach_port_construct_trap(struct _kernelrpc_mach_port_construct_args *args)
391 {
392 task_t task = port_name_to_task(args->target);
393 mach_port_name_t name;
394 int rv = MACH_SEND_INVALID_DEST;
395 mach_port_options_t options;
396
397 if (copyin(args->options, (char *)&options, sizeof(options))) {
398 rv = MACH_SEND_INVALID_DATA;
399 goto done;
400 }
401
402 if (task != current_task()) {
403 goto done;
404 }
405
406 rv = mach_port_construct(task->itk_space, &options, args->context, &name);
407 if (rv == KERN_SUCCESS) {
408 rv = copyout(&name, args->name, sizeof(name));
409 }
410
411 done:
412 if (task) {
413 task_deallocate(task);
414 }
415 return rv;
416 }
417
418 int
419 _kernelrpc_mach_port_destruct_trap(struct _kernelrpc_mach_port_destruct_args *args)
420 {
421 task_t task = port_name_to_task(args->target);
422 int rv = MACH_SEND_INVALID_DEST;
423
424 if (task != current_task()) {
425 goto done;
426 }
427
428 rv = mach_port_destruct(task->itk_space, args->name, args->srdelta, args->guard);
429
430 done:
431 if (task) {
432 task_deallocate(task);
433 }
434 return rv;
435 }
436
437 int
438 _kernelrpc_mach_port_guard_trap(struct _kernelrpc_mach_port_guard_args *args)
439 {
440 task_t task = port_name_to_task(args->target);
441 int rv = MACH_SEND_INVALID_DEST;
442
443 if (task != current_task()) {
444 goto done;
445 }
446
447 rv = mach_port_guard(task->itk_space, args->name, args->guard, args->strict);
448
449 done:
450 if (task) {
451 task_deallocate(task);
452 }
453 return rv;
454 }
455
456 int
457 _kernelrpc_mach_port_unguard_trap(struct _kernelrpc_mach_port_unguard_args *args)
458 {
459 task_t task = port_name_to_task(args->target);
460 int rv = MACH_SEND_INVALID_DEST;
461
462 if (task != current_task()) {
463 goto done;
464 }
465
466 rv = mach_port_unguard(task->itk_space, args->name, args->guard);
467
468 done:
469 if (task) {
470 task_deallocate(task);
471 }
472 return rv;
473 }
474
475 kern_return_t
476 host_create_mach_voucher_trap(struct host_create_mach_voucher_args *args)
477 {
478 host_t host = port_name_to_host(args->host);
479 ipc_voucher_t new_voucher = IV_NULL;
480 ipc_port_t voucher_port = IPC_PORT_NULL;
481 mach_port_name_t voucher_name = 0;
482 kern_return_t kr = 0;
483
484 if (host == HOST_NULL) {
485 return MACH_SEND_INVALID_DEST;
486 }
487
488 if (args->recipes_size < 0) {
489 return KERN_INVALID_ARGUMENT;
490 } else if (args->recipes_size > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) {
491 return MIG_ARRAY_TOO_LARGE;
492 }
493
494 if (args->recipes_size < MACH_VOUCHER_TRAP_STACK_LIMIT) {
495 /* keep small recipes on the stack for speed */
496 uint8_t krecipes[args->recipes_size];
497 if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) {
498 kr = KERN_MEMORY_ERROR;
499 goto done;
500 }
501 kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
502 } else {
503 uint8_t *krecipes = kalloc((vm_size_t)args->recipes_size);
504 if (!krecipes) {
505 kr = KERN_RESOURCE_SHORTAGE;
506 goto done;
507 }
508
509 if (copyin(CAST_USER_ADDR_T(args->recipes), (void *)krecipes, args->recipes_size)) {
510 kfree(krecipes, (vm_size_t)args->recipes_size);
511 kr = KERN_MEMORY_ERROR;
512 goto done;
513 }
514
515 kr = host_create_mach_voucher(host, krecipes, args->recipes_size, &new_voucher);
516 kfree(krecipes, (vm_size_t)args->recipes_size);
517 }
518
519 if (kr == 0) {
520 voucher_port = convert_voucher_to_port(new_voucher);
521 voucher_name = ipc_port_copyout_send(voucher_port, current_space());
522
523 kr = copyout(&voucher_name, args->voucher, sizeof(voucher_name));
524 }
525
526 done:
527 return kr;
528 }
529
530 kern_return_t
531 mach_voucher_extract_attr_recipe_trap(struct mach_voucher_extract_attr_recipe_args *args)
532 {
533 ipc_voucher_t voucher = IV_NULL;
534 kern_return_t kr = KERN_SUCCESS;
535 mach_msg_type_number_t sz = 0;
536
537 if (copyin(args->recipe_size, (void *)&sz, sizeof(sz))) {
538 return KERN_MEMORY_ERROR;
539 }
540
541 if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE) {
542 return MIG_ARRAY_TOO_LARGE;
543 }
544
545 voucher = convert_port_name_to_voucher(args->voucher_name);
546 if (voucher == IV_NULL) {
547 return MACH_SEND_INVALID_DEST;
548 }
549
550 mach_msg_type_number_t max_sz = sz;
551
552 if (sz < MACH_VOUCHER_TRAP_STACK_LIMIT) {
553 /* keep small recipes on the stack for speed */
554 uint8_t krecipe[sz];
555 bzero(krecipe, sz);
556 if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, sz)) {
557 kr = KERN_MEMORY_ERROR;
558 goto done;
559 }
560 kr = mach_voucher_extract_attr_recipe(voucher, args->key,
561 (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
562 assert(sz <= max_sz);
563
564 if (kr == KERN_SUCCESS && sz > 0) {
565 kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz);
566 }
567 } else {
568 uint8_t *krecipe = kalloc((vm_size_t)max_sz);
569 if (!krecipe) {
570 kr = KERN_RESOURCE_SHORTAGE;
571 goto done;
572 }
573
574 if (copyin(CAST_USER_ADDR_T(args->recipe), (void *)krecipe, sz)) {
575 kfree(krecipe, (vm_size_t)max_sz);
576 kr = KERN_MEMORY_ERROR;
577 goto done;
578 }
579
580 kr = mach_voucher_extract_attr_recipe(voucher, args->key,
581 (mach_voucher_attr_raw_recipe_t)krecipe, &sz);
582 assert(sz <= max_sz);
583
584 if (kr == KERN_SUCCESS && sz > 0) {
585 kr = copyout(krecipe, CAST_USER_ADDR_T(args->recipe), sz);
586 }
587 kfree(krecipe, (vm_size_t)max_sz);
588 }
589
590 if (kr == KERN_SUCCESS) {
591 kr = copyout(&sz, args->recipe_size, sizeof(sz));
592 }
593
594 done:
595 ipc_voucher_release(voucher);
596 return kr;
597 }