1 /*
2 * Copyright (c) 2000-2021 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 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or [email protected]
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * File: vm/vm_user.c
60 * Author: Avadis Tevanian, Jr., Michael Wayne Young
61 *
62 * User-exported virtual memory functions.
63 */
64
65 /*
66 * There are three implementations of the "XXX_allocate" functionality in
67 * the kernel: mach_vm_allocate (for any task on the platform), vm_allocate
68 * (for a task with the same address space size, especially the current task),
69 * and vm32_vm_allocate (for the specific case of a 32-bit task). vm_allocate
70 * in the kernel should only be used on the kernel_task. vm32_vm_allocate only
71 * makes sense on platforms where a user task can either be 32 or 64, or the kernel
72 * task can be 32 or 64. mach_vm_allocate makes sense everywhere, and is preferred
73 * for new code.
74 *
75 * The entrypoints into the kernel are more complex. All platforms support a
76 * mach_vm_allocate-style API (subsystem 4800) which operates with the largest
77 * size types for the platform. On platforms that only support U32/K32,
78 * subsystem 4800 is all you need. On platforms that support both U32 and U64,
79 * subsystem 3800 is used disambiguate the size of parameters, and they will
80 * always be 32-bit and call into the vm32_vm_allocate APIs. On non-U32/K32 platforms,
81 * the MIG glue should never call into vm_allocate directly, because the calling
82 * task and kernel_task are unlikely to use the same size parameters
83 *
84 * New VM call implementations should be added here and to mach_vm.defs
85 * (subsystem 4800), and use mach_vm_* "wide" types.
86 */
87
88 #include <debug.h>
89
90 #include <mach/boolean.h>
91 #include <mach/kern_return.h>
92 #include <mach/mach_types.h> /* to get vm_address_t */
93 #include <mach/memory_object.h>
94 #include <mach/std_types.h> /* to get pointer_t */
95 #include <mach/upl.h>
96 #include <mach/vm_attributes.h>
97 #include <mach/vm_param.h>
98 #include <mach/vm_statistics.h>
99 #include <mach/mach_syscalls.h>
100 #include <mach/sdt.h>
101 #include <mach/memory_entry.h>
102
103 #include <mach/host_priv_server.h>
104 #include <mach/mach_vm_server.h>
105 #include <mach/memory_entry_server.h>
106 #include <mach/vm_map_server.h>
107
108 #include <kern/host.h>
109 #include <kern/kalloc.h>
110 #include <kern/task.h>
111 #include <kern/misc_protos.h>
112 #include <vm/vm_fault.h>
113 #include <vm/vm_map_internal.h>
114 #include <vm/vm_object_xnu.h>
115 #include <vm/vm_kern.h>
116 #include <vm/vm_page_internal.h>
117 #include <vm/memory_object_internal.h>
118 #include <vm/vm_pageout_internal.h>
119 #include <vm/vm_protos.h>
120 #include <vm/vm_purgeable_internal.h>
121 #include <vm/vm_memory_entry_xnu.h>
122 #include <vm/vm_kern_internal.h>
123 #include <vm/vm_iokit.h>
124 #include <vm/vm_sanitize_internal.h>
125 #if CONFIG_DEFERRED_RECLAIM
126 #include <vm/vm_reclaim_internal.h>
127 #endif /* CONFIG_DEFERRED_RECLAIM */
128 #include <vm/vm_init_xnu.h>
129
130 #include <san/kasan.h>
131
132 #include <libkern/OSDebug.h>
133 #include <IOKit/IOBSD.h>
134 #include <sys/kdebug_triage.h>
135
136 #include <sys/code_signing.h> /* for is_address_space_debugged */
137
138 /*
139 * mach_vm_allocate allocates "zero fill" memory in the specfied
140 * map.
141 */
142 kern_return_t
mach_vm_allocate_external(vm_map_t map,mach_vm_offset_ut * addr,mach_vm_size_ut size,int flags)143 mach_vm_allocate_external(
144 vm_map_t map,
145 mach_vm_offset_ut *addr,
146 mach_vm_size_ut size,
147 int flags)
148 {
149 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
150
151 /* filter out any kernel-only flags */
152 if (flags & ~VM_FLAGS_USER_ALLOCATE) {
153 ktriage_record(thread_tid(current_thread()),
154 KDBG_TRIAGE_EVENTID(KDBG_TRIAGE_SUBSYS_VM,
155 KDBG_TRIAGE_RESERVED,
156 KDBG_TRIAGE_VM_ALLOCATE_KERNEL_BADFLAGS_ERROR),
157 KERN_INVALID_ARGUMENT /* arg */);
158 return KERN_INVALID_ARGUMENT;
159 }
160
161 vm_map_kernel_flags_set_vmflags(&vmk_flags, flags);
162
163 return mach_vm_allocate_kernel(map, addr, size, vmk_flags);
164 }
165
166 /*
167 * vm_allocate
168 * Legacy routine that allocates "zero fill" memory in the specfied
169 * map (which is limited to the same size as the kernel).
170 */
171 kern_return_t
vm_allocate_external(vm_map_t map,vm_offset_ut * addr,vm_size_ut size,int flags)172 vm_allocate_external(
173 vm_map_t map,
174 vm_offset_ut *addr,
175 vm_size_ut size,
176 int flags)
177 {
178 return mach_vm_allocate_external(map, addr, size, flags);
179 }
180
181 static __attribute__((always_inline, warn_unused_result))
182 kern_return_t
mach_vm_deallocate_sanitize(vm_map_t map,mach_vm_offset_ut start_u,mach_vm_size_ut size_u,mach_vm_offset_t * start,mach_vm_offset_t * end,mach_vm_size_t * size)183 mach_vm_deallocate_sanitize(
184 vm_map_t map,
185 mach_vm_offset_ut start_u,
186 mach_vm_size_ut size_u,
187 mach_vm_offset_t *start,
188 mach_vm_offset_t *end,
189 mach_vm_size_t *size)
190 {
191 vm_sanitize_flags_t flags = VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS;
192
193
194 return vm_sanitize_addr_size(start_u, size_u,
195 VM_SANITIZE_CALLER_VM_DEALLOCATE, map, flags,
196 start, end, size);
197 }
198
199 /*
200 * mach_vm_deallocate -
201 * deallocates the specified range of addresses in the
202 * specified address map.
203 */
204 kern_return_t
mach_vm_deallocate(vm_map_t map,mach_vm_offset_ut start_u,mach_vm_size_ut size_u)205 mach_vm_deallocate(
206 vm_map_t map,
207 mach_vm_offset_ut start_u,
208 mach_vm_size_ut size_u)
209 {
210 mach_vm_offset_t start, end;
211 mach_vm_size_t size;
212 kern_return_t kr;
213
214 if (map == VM_MAP_NULL) {
215 return KERN_INVALID_ARGUMENT;
216 }
217
218 kr = mach_vm_deallocate_sanitize(map,
219 start_u,
220 size_u,
221 &start,
222 &end,
223 &size);
224 if (__improbable(kr != KERN_SUCCESS)) {
225 return vm_sanitize_get_kr(kr);
226 }
227
228 return vm_map_remove_guard(map, start, end,
229 VM_MAP_REMOVE_NO_FLAGS,
230 KMEM_GUARD_NONE).kmr_return;
231 }
232
233 /*
234 * vm_deallocate -
235 * deallocates the specified range of addresses in the
236 * specified address map (limited to addresses the same
237 * size as the kernel).
238 */
239 kern_return_t
vm_deallocate(vm_map_t map,vm_offset_ut start,vm_size_ut size)240 vm_deallocate(
241 vm_map_t map,
242 vm_offset_ut start,
243 vm_size_ut size)
244 {
245 return mach_vm_deallocate(map, start, size);
246 }
247
248 /*
249 * mach_vm_inherit -
250 * Sets the inheritance of the specified range in the
251 * specified map.
252 */
253 kern_return_t
mach_vm_inherit(vm_map_t map,mach_vm_offset_ut start_u,mach_vm_size_ut size_u,vm_inherit_ut new_inheritance_u)254 mach_vm_inherit(
255 vm_map_t map,
256 mach_vm_offset_ut start_u,
257 mach_vm_size_ut size_u,
258 vm_inherit_ut new_inheritance_u)
259 {
260 if (map == VM_MAP_NULL) {
261 return KERN_INVALID_ARGUMENT;
262 }
263
264 if (VM_SANITIZE_UNSAFE_IS_ZERO(size_u)) {
265 return KERN_SUCCESS;
266 }
267
268 return vm_map_inherit(map,
269 start_u,
270 vm_sanitize_compute_ut_end(start_u, size_u),
271 new_inheritance_u);
272 }
273
274 /*
275 * vm_inherit -
276 * Sets the inheritance of the specified range in the
277 * specified map (range limited to addresses
278 */
279 kern_return_t
vm_inherit(vm_map_t map,vm_offset_ut start_u,vm_size_ut size_u,vm_inherit_ut new_inheritance_u)280 vm_inherit(
281 vm_map_t map,
282 vm_offset_ut start_u,
283 vm_size_ut size_u,
284 vm_inherit_ut new_inheritance_u)
285 {
286 return mach_vm_inherit(map, start_u, size_u, new_inheritance_u);
287 }
288
289 /*
290 * mach_vm_protect -
291 * Sets the protection of the specified range in the
292 * specified map.
293 */
294
295 kern_return_t
mach_vm_protect(vm_map_t map,mach_vm_address_ut start_u,mach_vm_size_ut size_u,boolean_t set_maximum,vm_prot_ut new_protection_u)296 mach_vm_protect(
297 vm_map_t map,
298 mach_vm_address_ut start_u,
299 mach_vm_size_ut size_u,
300 boolean_t set_maximum,
301 vm_prot_ut new_protection_u)
302 {
303 if (map == VM_MAP_NULL) {
304 return KERN_INVALID_ARGUMENT;
305 }
306
307 if (VM_SANITIZE_UNSAFE_IS_ZERO(size_u)) {
308 return KERN_SUCCESS;
309 }
310
311 return vm_map_protect(map,
312 start_u,
313 vm_sanitize_compute_ut_end(start_u, size_u),
314 set_maximum,
315 new_protection_u);
316 }
317
318 /*
319 * vm_protect -
320 * Sets the protection of the specified range in the
321 * specified map. Addressability of the range limited
322 * to the same size as the kernel.
323 */
324
325 kern_return_t
vm_protect(vm_map_t map,vm_offset_ut start_u,vm_size_ut size_u,boolean_t set_maximum,vm_prot_ut new_protection_u)326 vm_protect(
327 vm_map_t map,
328 vm_offset_ut start_u,
329 vm_size_ut size_u,
330 boolean_t set_maximum,
331 vm_prot_ut new_protection_u)
332 {
333 return mach_vm_protect(map, start_u, size_u, set_maximum, new_protection_u);
334 }
335
336 /*
337 * mach_vm_machine_attributes -
338 * Handle machine-specific attributes for a mapping, such
339 * as cachability, migrability, etc.
340 */
341 kern_return_t
mach_vm_machine_attribute(vm_map_t map,mach_vm_address_ut addr_u,mach_vm_size_ut size_u,vm_machine_attribute_t attribute,vm_machine_attribute_val_t * value)342 mach_vm_machine_attribute(
343 vm_map_t map,
344 mach_vm_address_ut addr_u,
345 mach_vm_size_ut size_u,
346 vm_machine_attribute_t attribute,
347 vm_machine_attribute_val_t *value) /* IN/OUT */
348 {
349 if (map == VM_MAP_NULL) {
350 return KERN_INVALID_ARGUMENT;
351 }
352
353 if (VM_SANITIZE_UNSAFE_IS_ZERO(size_u)) {
354 return KERN_SUCCESS;
355 }
356
357 return vm_map_machine_attribute(map,
358 addr_u,
359 vm_sanitize_compute_ut_end(addr_u, size_u),
360 attribute,
361 value);
362 }
363
364 /*
365 * vm_machine_attribute -
366 * Handle machine-specific attributes for a mapping, such
367 * as cachability, migrability, etc. Limited addressability
368 * (same range limits as for the native kernel map).
369 */
370 kern_return_t
vm_machine_attribute(vm_map_t map,vm_address_ut addr_u,vm_size_ut size_u,vm_machine_attribute_t attribute,vm_machine_attribute_val_t * value)371 vm_machine_attribute(
372 vm_map_t map,
373 vm_address_ut addr_u,
374 vm_size_ut size_u,
375 vm_machine_attribute_t attribute,
376 vm_machine_attribute_val_t *value) /* IN/OUT */
377 {
378 return mach_vm_machine_attribute(map, addr_u, size_u, attribute, value);
379 }
380
381 /*
382 * mach_vm_read -
383 * Read/copy a range from one address space and return it to the caller.
384 *
385 * It is assumed that the address for the returned memory is selected by
386 * the IPC implementation as part of receiving the reply to this call.
387 * If IPC isn't used, the caller must deal with the vm_map_copy_t object
388 * that gets returned.
389 *
390 * JMM - because of mach_msg_type_number_t, this call is limited to a
391 * single 4GB region at this time.
392 *
393 */
394 kern_return_t
mach_vm_read(vm_map_t map,mach_vm_address_ut addr,mach_vm_size_ut size,pointer_ut * data,mach_msg_type_number_t * data_size)395 mach_vm_read(
396 vm_map_t map,
397 mach_vm_address_ut addr,
398 mach_vm_size_ut size,
399 pointer_ut *data,
400 mach_msg_type_number_t *data_size)
401 {
402 kern_return_t error;
403 vm_map_copy_t ipc_address;
404
405 if (map == VM_MAP_NULL) {
406 return KERN_INVALID_ARGUMENT;
407 }
408
409 /*
410 * mach_msg_type_number_t is a signed int,
411 * make sure we do not overflow it.
412 */
413 if (!VM_SANITIZE_UNSAFE_FITS(size, mach_msg_type_number_t)) {
414 return KERN_INVALID_ARGUMENT;
415 }
416
417 error = vm_map_copyin(map, addr, size, FALSE, &ipc_address);
418
419 if (KERN_SUCCESS == error) {
420 VM_SANITIZE_UT_SET(*data, (pointer_t) ipc_address);
421 /* On success we know size was validated by vm_map_copyin. */
422 *data_size =
423 (mach_msg_type_number_t)VM_SANITIZE_UNSAFE_UNWRAP(size);
424 }
425 return error;
426 }
427
428 /*
429 * vm_read -
430 * Read/copy a range from one address space and return it to the caller.
431 * Limited addressability (same range limits as for the native kernel map).
432 *
433 * It is assumed that the address for the returned memory is selected by
434 * the IPC implementation as part of receiving the reply to this call.
435 * If IPC isn't used, the caller must deal with the vm_map_copy_t object
436 * that gets returned.
437 */
438 kern_return_t
vm_read(vm_map_t map,vm_address_ut addr,vm_size_ut size,pointer_ut * data,mach_msg_type_number_t * data_size)439 vm_read(
440 vm_map_t map,
441 vm_address_ut addr,
442 vm_size_ut size,
443 pointer_ut *data,
444 mach_msg_type_number_t *data_size)
445 {
446 return mach_vm_read(map, addr, size, data, data_size);
447 }
448
449 /*
450 * mach_vm_read_list -
451 * Read/copy a list of address ranges from specified map.
452 *
453 * MIG does not know how to deal with a returned array of
454 * vm_map_copy_t structures, so we have to do the copyout
455 * manually here.
456 */
457 kern_return_t
mach_vm_read_list(vm_map_t map,mach_vm_read_entry_t data_list,natural_t count)458 mach_vm_read_list(
459 vm_map_t map,
460 mach_vm_read_entry_t data_list,
461 natural_t count)
462 {
463 mach_msg_type_number_t i;
464 kern_return_t error;
465 vm_map_copy_t copy;
466
467 if (map == VM_MAP_NULL ||
468 count > VM_MAP_ENTRY_MAX) {
469 return KERN_INVALID_ARGUMENT;
470 }
471
472 error = KERN_SUCCESS;
473 for (i = 0; i < count; i++) {
474 vm_map_address_t map_addr;
475 vm_map_size_t map_size;
476
477 map_addr = (vm_map_address_t)(data_list[i].address);
478 map_size = (vm_map_size_t)(data_list[i].size);
479
480 if (map_size != 0) {
481 error = vm_map_copyin(map,
482 map_addr,
483 map_size,
484 FALSE, /* src_destroy */
485 ©);
486 if (KERN_SUCCESS == error) {
487 error = vm_map_copyout(
488 current_task()->map,
489 &map_addr,
490 copy);
491 if (KERN_SUCCESS == error) {
492 data_list[i].address = map_addr;
493 continue;
494 }
495 vm_map_copy_discard(copy);
496 }
497 }
498 data_list[i].address = (mach_vm_address_t)0;
499 data_list[i].size = (mach_vm_size_t)0;
500 }
501 return error;
502 }
503
504 /*
505 * vm_read_list -
506 * Read/copy a list of address ranges from specified map.
507 *
508 * MIG does not know how to deal with a returned array of
509 * vm_map_copy_t structures, so we have to do the copyout
510 * manually here.
511 *
512 * The source and destination ranges are limited to those
513 * that can be described with a vm_address_t (i.e. same
514 * size map as the kernel).
515 *
516 * JMM - If the result of the copyout is an address range
517 * that cannot be described with a vm_address_t (i.e. the
518 * caller had a larger address space but used this call
519 * anyway), it will result in a truncated address being
520 * returned (and a likely confused caller).
521 */
522
523 kern_return_t
vm_read_list(vm_map_t map,vm_read_entry_t data_list,natural_t count)524 vm_read_list(
525 vm_map_t map,
526 vm_read_entry_t data_list,
527 natural_t count)
528 {
529 mach_msg_type_number_t i;
530 kern_return_t error;
531 vm_map_copy_t copy;
532
533 if (map == VM_MAP_NULL ||
534 count > VM_MAP_ENTRY_MAX) {
535 return KERN_INVALID_ARGUMENT;
536 }
537
538 error = KERN_SUCCESS;
539 for (i = 0; i < count; i++) {
540 vm_map_address_t map_addr;
541 vm_map_size_t map_size;
542
543 map_addr = (vm_map_address_t)(data_list[i].address);
544 map_size = (vm_map_size_t)(data_list[i].size);
545
546 if (map_size != 0) {
547 error = vm_map_copyin(map,
548 map_addr,
549 map_size,
550 FALSE, /* src_destroy */
551 ©);
552 if (KERN_SUCCESS == error) {
553 error = vm_map_copyout(current_task()->map,
554 &map_addr,
555 copy);
556 if (KERN_SUCCESS == error) {
557 data_list[i].address =
558 CAST_DOWN(vm_offset_t, map_addr);
559 continue;
560 }
561 vm_map_copy_discard(copy);
562 }
563 }
564 data_list[i].address = (mach_vm_address_t)0;
565 data_list[i].size = (mach_vm_size_t)0;
566 }
567 return error;
568 }
569
570 /*
571 * mach_vm_read_overwrite -
572 * Overwrite a range of the current map with data from the specified
573 * map/address range.
574 *
575 * In making an assumption that the current thread is local, it is
576 * no longer cluster-safe without a fully supportive local proxy
577 * thread/task (but we don't support cluster's anymore so this is moot).
578 */
579
580 kern_return_t
mach_vm_read_overwrite(vm_map_t map,mach_vm_address_ut address,mach_vm_size_ut size,mach_vm_address_ut data,mach_vm_size_ut * data_size)581 mach_vm_read_overwrite(
582 vm_map_t map,
583 mach_vm_address_ut address,
584 mach_vm_size_ut size,
585 mach_vm_address_ut data,
586 mach_vm_size_ut *data_size)
587 {
588 kern_return_t error;
589 vm_map_copy_t copy;
590
591 if (map == VM_MAP_NULL) {
592 return KERN_INVALID_ARGUMENT;
593 }
594
595 error = vm_map_copyin(map, address, size, FALSE, ©);
596
597 if (KERN_SUCCESS == error) {
598 if (copy) {
599 assert(VM_SANITIZE_UNSAFE_IS_EQUAL(size, copy->size));
600 }
601
602 error = vm_map_copy_overwrite(current_thread()->map,
603 data,
604 copy,
605 size,
606 FALSE);
607 if (KERN_SUCCESS == error) {
608 *data_size = size;
609 return error;
610 }
611 vm_map_copy_discard(copy);
612 }
613 return error;
614 }
615
616 /*
617 * vm_read_overwrite -
618 * Overwrite a range of the current map with data from the specified
619 * map/address range.
620 *
621 * This routine adds the additional limitation that the source and
622 * destination ranges must be describable with vm_address_t values
623 * (i.e. the same size address spaces as the kernel, or at least the
624 * the ranges are in that first portion of the respective address
625 * spaces).
626 */
627
628 kern_return_t
vm_read_overwrite(vm_map_t map,vm_address_ut address,vm_size_ut size,vm_address_ut data,vm_size_ut * data_size)629 vm_read_overwrite(
630 vm_map_t map,
631 vm_address_ut address,
632 vm_size_ut size,
633 vm_address_ut data,
634 vm_size_ut *data_size)
635 {
636 return mach_vm_read_overwrite(map, address, size, data, data_size);
637 }
638
639 /*
640 * mach_vm_update_pointers_with_remote_tags -
641 */
642
643 kern_return_t
mach_vm_update_pointers_with_remote_tags(__unused vm_map_t map,__unused mach_vm_offset_list_t in_pointer_list,__unused mach_msg_type_number_t in_pointer_listCnt,__unused mach_vm_offset_list_t out_pointer_list,__unused mach_msg_type_number_t * out_pointer_listCnt)644 mach_vm_update_pointers_with_remote_tags(
645 __unused vm_map_t map,
646 __unused mach_vm_offset_list_t in_pointer_list,
647 __unused mach_msg_type_number_t in_pointer_listCnt,
648 __unused mach_vm_offset_list_t out_pointer_list,
649 __unused mach_msg_type_number_t *out_pointer_listCnt)
650 {
651 if (!in_pointer_list
652 || !out_pointer_list
653 || in_pointer_listCnt >= 512
654 /* The length of the output pointer list must match the input pointer list */
655 || !out_pointer_listCnt
656 || *out_pointer_listCnt != in_pointer_listCnt
657 ) {
658 return KERN_INVALID_ARGUMENT;
659 }
660
661 if (!map || !map->pmap) {
662 return KERN_INVALID_ARGUMENT;
663 }
664
665 return KERN_FAILURE;
666 }
667
668 /*
669 * mach_vm_write -
670 * Overwrite the specified address range with the data provided
671 * (from the current map).
672 */
673 kern_return_t
mach_vm_write(vm_map_t map,mach_vm_address_ut address,pointer_ut data_u,mach_msg_type_number_t size)674 mach_vm_write(
675 vm_map_t map,
676 mach_vm_address_ut address,
677 pointer_ut data_u,
678 mach_msg_type_number_t size)
679 {
680 if (map == VM_MAP_NULL) {
681 return KERN_INVALID_ARGUMENT;
682 }
683
684 /*
685 * data is created by the kernel's MIG server from a userspace buffer,
686 * so it is safe to unwrap.
687 */
688 vm_map_copy_t data = (vm_map_copy_t) VM_SANITIZE_UNSAFE_UNWRAP(data_u);
689
690 return vm_map_copy_overwrite(map,
691 address,
692 data,
693 size,
694 FALSE /* interruptible XXX */);
695 }
696
697 /*
698 * vm_write -
699 * Overwrite the specified address range with the data provided
700 * (from the current map).
701 *
702 * The addressability of the range of addresses to overwrite is
703 * limited bu the use of a vm_address_t (same size as kernel map).
704 * Either the target map is also small, or the range is in the
705 * low addresses within it.
706 */
707 kern_return_t
vm_write(vm_map_t map,vm_address_ut address,pointer_ut data,mach_msg_type_number_t size)708 vm_write(
709 vm_map_t map,
710 vm_address_ut address,
711 pointer_ut data,
712 mach_msg_type_number_t size)
713 {
714 return mach_vm_write(map, address, data, size);
715 }
716
717 /*
718 * mach_vm_copy -
719 * Overwrite one range of the specified map with the contents of
720 * another range within that same map (i.e. both address ranges
721 * are "over there").
722 */
723 kern_return_t
mach_vm_copy(vm_map_t map,mach_vm_address_ut source_address,mach_vm_size_ut size,mach_vm_address_ut dest_address)724 mach_vm_copy(
725 vm_map_t map,
726 mach_vm_address_ut source_address,
727 mach_vm_size_ut size,
728 mach_vm_address_ut dest_address)
729 {
730 vm_map_copy_t copy;
731 kern_return_t kr;
732
733 if (map == VM_MAP_NULL) {
734 return KERN_INVALID_ARGUMENT;
735 }
736
737 kr = vm_map_copyin(map, source_address, size, FALSE, ©);
738
739 if (KERN_SUCCESS == kr) {
740 if (copy) {
741 assert(VM_SANITIZE_UNSAFE_IS_EQUAL(size, copy->size));
742 }
743
744 kr = vm_map_copy_overwrite(map,
745 dest_address,
746 copy,
747 size,
748 FALSE);
749
750 if (KERN_SUCCESS != kr) {
751 vm_map_copy_discard(copy);
752 }
753 }
754 return kr;
755 }
756
757 kern_return_t
vm_copy(vm_map_t map,vm_address_ut source_address,vm_size_ut size,vm_address_ut dest_address)758 vm_copy(
759 vm_map_t map,
760 vm_address_ut source_address,
761 vm_size_ut size,
762 vm_address_ut dest_address)
763 {
764 return mach_vm_copy(map, source_address, size, dest_address);
765 }
766
767 /*
768 * mach_vm_map -
769 * Map some range of an object into an address space.
770 *
771 * The object can be one of several types of objects:
772 * NULL - anonymous memory
773 * a named entry - a range within another address space
774 * or a range within a memory object
775 * a whole memory object
776 *
777 */
778 kern_return_t
mach_vm_map_external(vm_map_t target_map,mach_vm_offset_ut * address,mach_vm_size_ut initial_size,mach_vm_offset_ut mask,int flags,ipc_port_t port,memory_object_offset_ut offset,boolean_t copy,vm_prot_ut cur_protection,vm_prot_ut max_protection,vm_inherit_ut inheritance)779 mach_vm_map_external(
780 vm_map_t target_map,
781 mach_vm_offset_ut *address,
782 mach_vm_size_ut initial_size,
783 mach_vm_offset_ut mask,
784 int flags,
785 ipc_port_t port,
786 memory_object_offset_ut offset,
787 boolean_t copy,
788 vm_prot_ut cur_protection,
789 vm_prot_ut max_protection,
790 vm_inherit_ut inheritance)
791 {
792 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
793
794 /* filter out any kernel-only flags */
795 if (flags & ~VM_FLAGS_USER_MAP) {
796 return KERN_INVALID_ARGUMENT;
797 }
798
799 vm_map_kernel_flags_set_vmflags(&vmk_flags, flags);
800 /* range_id is set by mach_vm_map_kernel */
801 return mach_vm_map_kernel(target_map, address, initial_size, mask,
802 vmk_flags, port, offset, copy,
803 cur_protection, max_protection,
804 inheritance);
805 }
806
807 /* legacy interface */
808 __attribute__((always_inline))
809 kern_return_t
vm_map_64_external(vm_map_t target_map,vm_offset_ut * address,vm_size_ut size,vm_offset_ut mask,int flags,ipc_port_t port,memory_object_offset_ut offset,boolean_t copy,vm_prot_ut cur_protection,vm_prot_ut max_protection,vm_inherit_ut inheritance)810 vm_map_64_external(
811 vm_map_t target_map,
812 vm_offset_ut *address,
813 vm_size_ut size,
814 vm_offset_ut mask,
815 int flags,
816 ipc_port_t port,
817 memory_object_offset_ut offset,
818 boolean_t copy,
819 vm_prot_ut cur_protection,
820 vm_prot_ut max_protection,
821 vm_inherit_ut inheritance)
822 {
823 return mach_vm_map_external(target_map, address,
824 size, mask, flags, port, offset, copy,
825 cur_protection, max_protection, inheritance);
826 }
827
828 /* temporary, until world build */
829 __attribute__((always_inline))
830 kern_return_t
vm_map_external(vm_map_t target_map,vm_offset_ut * address,vm_size_ut size,vm_offset_ut mask,int flags,ipc_port_t port,vm_offset_ut offset,boolean_t copy,vm_prot_ut cur_protection,vm_prot_ut max_protection,vm_inherit_ut inheritance)831 vm_map_external(
832 vm_map_t target_map,
833 vm_offset_ut *address,
834 vm_size_ut size,
835 vm_offset_ut mask,
836 int flags,
837 ipc_port_t port,
838 vm_offset_ut offset,
839 boolean_t copy,
840 vm_prot_ut cur_protection,
841 vm_prot_ut max_protection,
842 vm_inherit_ut inheritance)
843 {
844 return mach_vm_map_external(target_map, address,
845 size, mask, flags, port, offset, copy,
846 cur_protection, max_protection, inheritance);
847 }
848
849 static __attribute__((always_inline, warn_unused_result))
850 kern_return_t
mach_vm_remap_new_external_sanitize(vm_map_t target_map,vm_prot_ut cur_protection_u,vm_prot_ut max_protection_u,vm_prot_t * cur_protection,vm_prot_t * max_protection)851 mach_vm_remap_new_external_sanitize(
852 vm_map_t target_map,
853 vm_prot_ut cur_protection_u,
854 vm_prot_ut max_protection_u,
855 vm_prot_t *cur_protection,
856 vm_prot_t *max_protection)
857 {
858 return vm_sanitize_cur_and_max_prots(cur_protection_u, max_protection_u,
859 VM_SANITIZE_CALLER_VM_MAP_REMAP, target_map,
860 cur_protection, max_protection);
861 }
862
863 /*
864 * mach_vm_remap_new -
865 * Behaves like mach_vm_remap, except that VM_FLAGS_RETURN_DATA_ADDR is always set
866 * and {cur,max}_protection are in/out.
867 */
868 kern_return_t
mach_vm_remap_new_external(vm_map_t target_map,mach_vm_offset_ut * address,mach_vm_size_ut size,mach_vm_offset_ut mask,int flags,mach_port_t src_tport,mach_vm_offset_ut memory_address,boolean_t copy,vm_prot_ut * cur_protection_u,vm_prot_ut * max_protection_u,vm_inherit_ut inheritance)869 mach_vm_remap_new_external(
870 vm_map_t target_map,
871 mach_vm_offset_ut *address,
872 mach_vm_size_ut size,
873 mach_vm_offset_ut mask,
874 int flags,
875 mach_port_t src_tport,
876 mach_vm_offset_ut memory_address,
877 boolean_t copy,
878 vm_prot_ut *cur_protection_u, /* IN/OUT */
879 vm_prot_ut *max_protection_u, /* IN/OUT */
880 vm_inherit_ut inheritance)
881 {
882 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
883 vm_map_t src_map;
884 vm_prot_t cur_protection, max_protection;
885 kern_return_t kr;
886
887 if (target_map == VM_MAP_NULL) {
888 return KERN_INVALID_ARGUMENT;
889 }
890
891 /* filter out any kernel-only flags */
892 if (flags & ~VM_FLAGS_USER_REMAP) {
893 return KERN_INVALID_ARGUMENT;
894 }
895
896 vm_map_kernel_flags_set_vmflags(&vmk_flags,
897 flags | VM_FLAGS_RETURN_DATA_ADDR);
898
899 /*
900 * We don't need cur_protection here, but sanitizing it before
901 * enforcing W^X below matches historical error codes better.
902 */
903 kr = mach_vm_remap_new_external_sanitize(target_map,
904 *cur_protection_u,
905 *max_protection_u,
906 &cur_protection,
907 &max_protection);
908 if (__improbable(kr != KERN_SUCCESS)) {
909 return vm_sanitize_get_kr(kr);
910 }
911
912 if ((max_protection & (VM_PROT_WRITE | VM_PROT_EXECUTE)) ==
913 (VM_PROT_WRITE | VM_PROT_EXECUTE)) {
914 /*
915 * XXX FBDP TODO
916 * enforce target's "wx" policies
917 */
918 return KERN_PROTECTION_FAILURE;
919 }
920
921 if (copy || max_protection == VM_PROT_READ || max_protection == VM_PROT_NONE) {
922 src_map = convert_port_to_map_read(src_tport);
923 } else {
924 src_map = convert_port_to_map(src_tport);
925 }
926
927 /* range_id is set by vm_map_remap */
928 kr = vm_map_remap(target_map,
929 address,
930 size,
931 mask,
932 vmk_flags,
933 src_map,
934 memory_address,
935 copy,
936 cur_protection_u, /* IN/OUT */
937 max_protection_u, /* IN/OUT */
938 inheritance);
939
940 vm_map_deallocate(src_map);
941
942 if (kr == KERN_SUCCESS) {
943 ipc_port_release_send(src_tport); /* consume on success */
944 }
945 return kr;
946 }
947
948 /*
949 * mach_vm_remap -
950 * Remap a range of memory from one task into another,
951 * to another address range within the same task, or
952 * over top of itself (with altered permissions and/or
953 * as an in-place copy of itself).
954 */
955 kern_return_t
mach_vm_remap_external(vm_map_t target_map,mach_vm_offset_ut * address,mach_vm_size_ut size,mach_vm_offset_ut mask,int flags,vm_map_t src_map,mach_vm_offset_ut memory_address,boolean_t copy,vm_prot_ut * cur_protection,vm_prot_ut * max_protection,vm_inherit_ut inheritance)956 mach_vm_remap_external(
957 vm_map_t target_map,
958 mach_vm_offset_ut *address,
959 mach_vm_size_ut size,
960 mach_vm_offset_ut mask,
961 int flags,
962 vm_map_t src_map,
963 mach_vm_offset_ut memory_address,
964 boolean_t copy,
965 vm_prot_ut *cur_protection, /* OUT */
966 vm_prot_ut *max_protection, /* OUT */
967 vm_inherit_ut inheritance)
968 {
969 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
970
971 /* filter out any kernel-only flags */
972 if (flags & ~VM_FLAGS_USER_REMAP) {
973 return KERN_INVALID_ARGUMENT;
974 }
975
976 vm_map_kernel_flags_set_vmflags(&vmk_flags, flags);
977
978 *cur_protection = vm_sanitize_wrap_prot(VM_PROT_NONE);
979 *max_protection = vm_sanitize_wrap_prot(VM_PROT_NONE);
980 vmk_flags.vmkf_remap_legacy_mode = true;
981
982 /* range_id is set by vm_map_remap */
983 return vm_map_remap(target_map,
984 address,
985 size,
986 mask,
987 vmk_flags,
988 src_map,
989 memory_address,
990 copy,
991 cur_protection,
992 max_protection,
993 inheritance);
994 }
995
996 /*
997 * vm_remap_new -
998 * Behaves like vm_remap, except that VM_FLAGS_RETURN_DATA_ADDR is always set
999 * and {cur,max}_protection are in/out.
1000 */
1001 kern_return_t
vm_remap_new_external(vm_map_t target_map,vm_offset_ut * address,vm_size_ut size,vm_offset_ut mask,int flags,mach_port_t src_tport,vm_offset_ut memory_address,boolean_t copy,vm_prot_ut * cur_protection,vm_prot_ut * max_protection,vm_inherit_ut inheritance)1002 vm_remap_new_external(
1003 vm_map_t target_map,
1004 vm_offset_ut *address,
1005 vm_size_ut size,
1006 vm_offset_ut mask,
1007 int flags,
1008 mach_port_t src_tport,
1009 vm_offset_ut memory_address,
1010 boolean_t copy,
1011 vm_prot_ut *cur_protection, /* IN/OUT */
1012 vm_prot_ut *max_protection, /* IN/OUT */
1013 vm_inherit_ut inheritance)
1014 {
1015 return mach_vm_remap_new_external(target_map,
1016 address,
1017 size,
1018 mask,
1019 flags,
1020 src_tport,
1021 memory_address,
1022 copy,
1023 cur_protection, /* IN/OUT */
1024 max_protection, /* IN/OUT */
1025 inheritance);
1026 }
1027
1028 /*
1029 * vm_remap -
1030 * Remap a range of memory from one task into another,
1031 * to another address range within the same task, or
1032 * over top of itself (with altered permissions and/or
1033 * as an in-place copy of itself).
1034 *
1035 * The addressability of the source and target address
1036 * range is limited by the size of vm_address_t (in the
1037 * kernel context).
1038 */
1039 kern_return_t
vm_remap_external(vm_map_t target_map,vm_offset_ut * address,vm_size_ut size,vm_offset_ut mask,int flags,vm_map_t src_map,vm_offset_ut memory_address,boolean_t copy,vm_prot_ut * cur_protection,vm_prot_ut * max_protection,vm_inherit_ut inheritance)1040 vm_remap_external(
1041 vm_map_t target_map,
1042 vm_offset_ut *address,
1043 vm_size_ut size,
1044 vm_offset_ut mask,
1045 int flags,
1046 vm_map_t src_map,
1047 vm_offset_ut memory_address,
1048 boolean_t copy,
1049 vm_prot_ut *cur_protection, /* OUT */
1050 vm_prot_ut *max_protection, /* OUT */
1051 vm_inherit_ut inheritance)
1052 {
1053 return mach_vm_remap_external(target_map, address,
1054 size, mask, flags, src_map, memory_address, copy,
1055 cur_protection, max_protection, inheritance);
1056 }
1057
1058 /*
1059 * NOTE: these routine (and this file) will no longer require mach_host_server.h
1060 * when mach_vm_wire and vm_wire are changed to use ledgers.
1061 */
1062 #include <mach/mach_host_server.h>
1063 /*
1064 * mach_vm_wire
1065 * Specify that the range of the virtual address space
1066 * of the target task must not cause page faults for
1067 * the indicated accesses.
1068 *
1069 * [ To unwire the pages, specify VM_PROT_NONE. ]
1070 */
1071 kern_return_t
mach_vm_wire_external(host_priv_t host_priv,vm_map_t map,mach_vm_address_ut start,mach_vm_size_ut size,vm_prot_ut access)1072 mach_vm_wire_external(
1073 host_priv_t host_priv,
1074 vm_map_t map,
1075 mach_vm_address_ut start,
1076 mach_vm_size_ut size,
1077 vm_prot_ut access)
1078 {
1079 kern_return_t rc;
1080 mach_vm_offset_ut end;
1081
1082 if (host_priv == HOST_PRIV_NULL) {
1083 return KERN_INVALID_HOST;
1084 }
1085
1086 if (map == VM_MAP_NULL) {
1087 return KERN_INVALID_TASK;
1088 }
1089
1090 end = vm_sanitize_compute_ut_end(start, size);
1091 if (VM_SANITIZE_UNSAFE_IS_ZERO(access)) {
1092 rc = vm_map_unwire_impl(map, start, end, true,
1093 VM_SANITIZE_CALLER_VM_UNWIRE_USER);
1094 } else {
1095 rc = vm_map_wire_impl(map, start, end, access,
1096 VM_KERN_MEMORY_MLOCK, true, NULL, VM_SANITIZE_CALLER_VM_WIRE_USER);
1097 }
1098
1099 return rc;
1100 }
1101
1102 /*
1103 * vm_wire -
1104 * Specify that the range of the virtual address space
1105 * of the target task must not cause page faults for
1106 * the indicated accesses.
1107 *
1108 * [ To unwire the pages, specify VM_PROT_NONE. ]
1109 */
1110 kern_return_t
vm_wire(host_priv_t host_priv,vm_map_t map,vm_offset_ut start,vm_size_ut size,vm_prot_ut access)1111 vm_wire(
1112 host_priv_t host_priv,
1113 vm_map_t map,
1114 vm_offset_ut start,
1115 vm_size_ut size,
1116 vm_prot_ut access)
1117 {
1118 return mach_vm_wire_external(host_priv, map, start, size, access);
1119 }
1120
1121 /*
1122 * vm_msync
1123 *
1124 * Synchronises the memory range specified with its backing store
1125 * image by either flushing or cleaning the contents to the appropriate
1126 * memory manager.
1127 *
1128 * interpretation of sync_flags
1129 * VM_SYNC_INVALIDATE - discard pages, only return precious
1130 * pages to manager.
1131 *
1132 * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS)
1133 * - discard pages, write dirty or precious
1134 * pages back to memory manager.
1135 *
1136 * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS
1137 * - write dirty or precious pages back to
1138 * the memory manager.
1139 *
1140 * VM_SYNC_CONTIGUOUS - does everything normally, but if there
1141 * is a hole in the region, and we would
1142 * have returned KERN_SUCCESS, return
1143 * KERN_INVALID_ADDRESS instead.
1144 *
1145 * RETURNS
1146 * KERN_INVALID_TASK Bad task parameter
1147 * KERN_INVALID_ARGUMENT both sync and async were specified.
1148 * KERN_SUCCESS The usual.
1149 * KERN_INVALID_ADDRESS There was a hole in the region.
1150 */
1151
1152 kern_return_t
mach_vm_msync(vm_map_t map,mach_vm_address_ut address_u,mach_vm_size_ut size_u,vm_sync_t sync_flags)1153 mach_vm_msync(
1154 vm_map_t map,
1155 mach_vm_address_ut address_u,
1156 mach_vm_size_ut size_u,
1157 vm_sync_t sync_flags)
1158 {
1159 if (map == VM_MAP_NULL) {
1160 return KERN_INVALID_TASK;
1161 }
1162
1163 if (VM_SANITIZE_UNSAFE_IS_ZERO(size_u)) {
1164 return KERN_SUCCESS;
1165 }
1166
1167 return vm_map_msync(map, address_u, size_u, sync_flags);
1168 }
1169
1170 /*
1171 * vm_msync
1172 *
1173 * Synchronises the memory range specified with its backing store
1174 * image by either flushing or cleaning the contents to the appropriate
1175 * memory manager.
1176 *
1177 * interpretation of sync_flags
1178 * VM_SYNC_INVALIDATE - discard pages, only return precious
1179 * pages to manager.
1180 *
1181 * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS)
1182 * - discard pages, write dirty or precious
1183 * pages back to memory manager.
1184 *
1185 * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS
1186 * - write dirty or precious pages back to
1187 * the memory manager.
1188 *
1189 * VM_SYNC_CONTIGUOUS - does everything normally, but if there
1190 * is a hole in the region, and we would
1191 * have returned KERN_SUCCESS, return
1192 * KERN_INVALID_ADDRESS instead.
1193 *
1194 * The addressability of the range is limited to that which can
1195 * be described by a vm_address_t.
1196 *
1197 * RETURNS
1198 * KERN_INVALID_TASK Bad task parameter
1199 * KERN_INVALID_ARGUMENT both sync and async were specified.
1200 * KERN_SUCCESS The usual.
1201 * KERN_INVALID_ADDRESS There was a hole in the region.
1202 */
1203
1204 kern_return_t
vm_msync(vm_map_t map,vm_address_ut address_u,vm_size_ut size_u,vm_sync_t sync_flags)1205 vm_msync(
1206 vm_map_t map,
1207 vm_address_ut address_u,
1208 vm_size_ut size_u,
1209 vm_sync_t sync_flags)
1210 {
1211 return mach_vm_msync(map, address_u, size_u, sync_flags);
1212 }
1213
1214
1215 int
vm_toggle_entry_reuse(int toggle,int * old_value)1216 vm_toggle_entry_reuse(int toggle, int *old_value)
1217 {
1218 vm_map_t map = current_map();
1219
1220 vmlp_api_start(VM_TOGGLE_ENTRY_REUSE);
1221
1222 assert(!map->is_nested_map);
1223 if (toggle == VM_TOGGLE_GETVALUE && old_value != NULL) {
1224 *old_value = map->disable_vmentry_reuse;
1225 } else if (toggle == VM_TOGGLE_SET) {
1226 vm_map_entry_t map_to_entry;
1227
1228 vm_map_lock(map);
1229 vm_map_disable_hole_optimization(map);
1230 map->disable_vmentry_reuse = TRUE;
1231 __IGNORE_WCASTALIGN(map_to_entry = vm_map_to_entry(map));
1232 if (map->first_free == map_to_entry) {
1233 map->highest_entry_end = vm_map_min(map);
1234 } else {
1235 map->highest_entry_end = map->first_free->vme_end;
1236 }
1237 vm_map_unlock(map);
1238 } else if (toggle == VM_TOGGLE_CLEAR) {
1239 vm_map_lock(map);
1240 map->disable_vmentry_reuse = FALSE;
1241 vm_map_unlock(map);
1242 } else {
1243 vmlp_api_end(VM_TOGGLE_ENTRY_REUSE, KERN_INVALID_ARGUMENT);
1244 return KERN_INVALID_ARGUMENT;
1245 }
1246
1247 vmlp_api_end(VM_TOGGLE_ENTRY_REUSE, KERN_SUCCESS);
1248 return KERN_SUCCESS;
1249 }
1250
1251
1252 static __attribute__((always_inline, warn_unused_result))
1253 kern_return_t
mach_vm_behavior_set_sanitize(vm_map_t map,mach_vm_offset_ut start_u,mach_vm_size_ut size_u,vm_behavior_ut new_behavior_u,mach_vm_offset_t * start,mach_vm_offset_t * end,mach_vm_size_t * size,vm_behavior_t * new_behavior)1254 mach_vm_behavior_set_sanitize(
1255 vm_map_t map,
1256 mach_vm_offset_ut start_u,
1257 mach_vm_size_ut size_u,
1258 vm_behavior_ut new_behavior_u,
1259 mach_vm_offset_t *start,
1260 mach_vm_offset_t *end,
1261 mach_vm_size_t *size,
1262 vm_behavior_t *new_behavior)
1263 {
1264 mach_vm_offset_t align_mask;
1265 kern_return_t kr;
1266
1267 kr = vm_sanitize_behavior(new_behavior_u, VM_SANITIZE_CALLER_VM_BEHAVIOR_SET, new_behavior);
1268 if (__improbable(kr != KERN_SUCCESS)) {
1269 return kr;
1270 }
1271
1272 /* Choose alignment of addr/size based on the behavior being set. */
1273 switch (*new_behavior) {
1274 case VM_BEHAVIOR_REUSABLE:
1275 case VM_BEHAVIOR_REUSE:
1276 case VM_BEHAVIOR_CAN_REUSE:
1277 case VM_BEHAVIOR_ZERO:
1278 /*
1279 * Align to the hardware page size, to allow
1280 * malloc() to maximize the amount of re-usability,
1281 * even on systems with larger software page size.
1282 */
1283 align_mask = PAGE_MASK;
1284 break;
1285 default:
1286 align_mask = VM_MAP_PAGE_MASK(map);
1287 break;
1288 }
1289
1290 vm_sanitize_flags_t flags = VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS;
1291
1292
1293 kr = vm_sanitize_addr_size(start_u, size_u, VM_SANITIZE_CALLER_VM_BEHAVIOR_SET,
1294 align_mask, map, flags, start, end, size);
1295 if (__improbable(kr != KERN_SUCCESS)) {
1296 return kr;
1297 }
1298
1299 return KERN_SUCCESS;
1300 }
1301
1302 /*
1303 * mach_vm_behavior_set
1304 *
1305 * Sets the paging behavior attribute for the specified range
1306 * in the specified map.
1307 *
1308 * This routine will fail with KERN_INVALID_ADDRESS if any address
1309 * in [start,start+size) is not a valid allocated memory region.
1310 */
1311 kern_return_t
mach_vm_behavior_set(vm_map_t map,mach_vm_offset_ut start_u,mach_vm_size_ut size_u,vm_behavior_ut new_behavior_u)1312 mach_vm_behavior_set(
1313 vm_map_t map,
1314 mach_vm_offset_ut start_u,
1315 mach_vm_size_ut size_u,
1316 vm_behavior_ut new_behavior_u)
1317 {
1318 kern_return_t kr;
1319 mach_vm_offset_t start, end;
1320 mach_vm_size_t size;
1321 vm_behavior_t new_behavior;
1322
1323 if (map == VM_MAP_NULL) {
1324 return KERN_INVALID_ARGUMENT;
1325 }
1326
1327 kr = mach_vm_behavior_set_sanitize(map,
1328 start_u, size_u, new_behavior_u,
1329 &start, &end, &size, &new_behavior);
1330 if (__improbable(kr != KERN_SUCCESS)) {
1331 return vm_sanitize_get_kr(kr);
1332 }
1333
1334 return vm_map_behavior_set(map,
1335 start,
1336 end,
1337 new_behavior);
1338 }
1339
1340 /*
1341 * vm_behavior_set
1342 *
1343 * Sets the paging behavior attribute for the specified range
1344 * in the specified map.
1345 *
1346 * This routine will fail with KERN_INVALID_ADDRESS if any address
1347 * in [start,start+size) is not a valid allocated memory region.
1348 *
1349 * This routine is potentially limited in addressibility by the
1350 * use of vm_offset_t (if the map provided is larger than the
1351 * kernel's).
1352 */
1353 kern_return_t
vm_behavior_set(vm_map_t map,vm_offset_ut start,vm_size_ut size,vm_behavior_ut new_behavior)1354 vm_behavior_set(
1355 vm_map_t map,
1356 vm_offset_ut start,
1357 vm_size_ut size,
1358 vm_behavior_ut new_behavior)
1359 {
1360 return mach_vm_behavior_set(map,
1361 start,
1362 size,
1363 new_behavior);
1364 }
1365
1366 /*
1367 * mach_vm_region:
1368 *
1369 * User call to obtain information about a region in
1370 * a task's address map. Currently, only one flavor is
1371 * supported.
1372 *
1373 * XXX The reserved and behavior fields cannot be filled
1374 * in until the vm merge from the IK is completed, and
1375 * vm_reserve is implemented.
1376 *
1377 * XXX Dependency: syscall_vm_region() also supports only one flavor.
1378 */
1379
1380 kern_return_t
mach_vm_region(vm_map_t map,mach_vm_offset_ut * address_u,mach_vm_size_ut * size_u,vm_region_flavor_t flavor,vm_region_info_t info,mach_msg_type_number_t * count,mach_port_t * object_name)1381 mach_vm_region(
1382 vm_map_t map,
1383 mach_vm_offset_ut *address_u, /* IN/OUT */
1384 mach_vm_size_ut *size_u, /* OUT */
1385 vm_region_flavor_t flavor, /* IN */
1386 vm_region_info_t info, /* OUT */
1387 mach_msg_type_number_t *count, /* IN/OUT */
1388 mach_port_t *object_name) /* OUT */
1389 {
1390 if (VM_MAP_NULL == map) {
1391 return KERN_INVALID_ARGUMENT;
1392 }
1393
1394 /* legacy conversion */
1395 if (VM_REGION_BASIC_INFO == flavor) {
1396 flavor = VM_REGION_BASIC_INFO_64;
1397 }
1398
1399 return vm_map_region(map, address_u, size_u, flavor, info, count,
1400 object_name);
1401 }
1402
1403 static inline kern_return_t
vm_region_get_kern_return(kern_return_t kr,vm_offset_ut addr_u,vm_size_ut size_u)1404 vm_region_get_kern_return(
1405 kern_return_t kr,
1406 vm_offset_ut addr_u,
1407 vm_size_ut size_u)
1408 {
1409 vm_offset_ut end_u = vm_sanitize_compute_ut_end(addr_u, size_u);
1410
1411 if (KERN_SUCCESS == kr && VM_SANITIZE_UNSAFE_UNWRAP(end_u) > VM_MAX_ADDRESS) {
1412 return KERN_INVALID_ADDRESS;
1413 }
1414 return kr;
1415 }
1416
1417 /*
1418 * vm_region_64 and vm_region:
1419 *
1420 * User call to obtain information about a region in
1421 * a task's address map. Currently, only one flavor is
1422 * supported.
1423 *
1424 * XXX The reserved and behavior fields cannot be filled
1425 * in until the vm merge from the IK is completed, and
1426 * vm_reserve is implemented.
1427 *
1428 * XXX Dependency: syscall_vm_region() also supports only one flavor.
1429 */
1430
1431 kern_return_t
vm_region_64(vm_map_t map,vm_offset_ut * address_u,vm_size_ut * size_u,vm_region_flavor_t flavor,vm_region_info_t info,mach_msg_type_number_t * count,mach_port_t * object_name)1432 vm_region_64(
1433 vm_map_t map,
1434 vm_offset_ut *address_u, /* IN/OUT */
1435 vm_size_ut *size_u, /* OUT */
1436 vm_region_flavor_t flavor, /* IN */
1437 vm_region_info_t info, /* OUT */
1438 mach_msg_type_number_t *count, /* IN/OUT */
1439 mach_port_t *object_name) /* OUT */
1440 {
1441 kern_return_t kr;
1442
1443 kr = mach_vm_region(map, address_u, size_u, flavor, info, count,
1444 object_name);
1445
1446 return vm_region_get_kern_return(kr, *address_u, *size_u);
1447 }
1448
1449 kern_return_t
vm_region(vm_map_t map,vm_address_ut * address_u,vm_size_ut * size_u,vm_region_flavor_t flavor,vm_region_info_t info,mach_msg_type_number_t * count,mach_port_t * object_name)1450 vm_region(
1451 vm_map_t map,
1452 vm_address_ut *address_u, /* IN/OUT */
1453 vm_size_ut *size_u, /* OUT */
1454 vm_region_flavor_t flavor, /* IN */
1455 vm_region_info_t info, /* OUT */
1456 mach_msg_type_number_t *count, /* IN/OUT */
1457 mach_port_t *object_name) /* OUT */
1458 {
1459 kern_return_t kr;
1460
1461 if (VM_MAP_NULL == map) {
1462 return KERN_INVALID_ARGUMENT;
1463 }
1464
1465 kr = vm_map_region(map, address_u, size_u, flavor, info, count,
1466 object_name);
1467
1468 return vm_region_get_kern_return(kr, *address_u, *size_u);
1469 }
1470
1471 /*
1472 * vm_region_recurse: A form of vm_region which follows the
1473 * submaps in a target map
1474 *
1475 */
1476 kern_return_t
mach_vm_region_recurse(vm_map_t map,mach_vm_address_ut * address_u,mach_vm_size_ut * size_u,uint32_t * depth,vm_region_recurse_info_t info,mach_msg_type_number_t * infoCnt)1477 mach_vm_region_recurse(
1478 vm_map_t map,
1479 mach_vm_address_ut *address_u,
1480 mach_vm_size_ut *size_u,
1481 uint32_t *depth,
1482 vm_region_recurse_info_t info,
1483 mach_msg_type_number_t *infoCnt)
1484 {
1485 if (VM_MAP_NULL == map) {
1486 return KERN_INVALID_ARGUMENT;
1487 }
1488
1489 return vm_map_region_recurse_64(map, address_u, size_u, depth,
1490 (vm_region_submap_info_64_t)info, infoCnt);
1491 }
1492
1493 /*
1494 * vm_region_recurse: A form of vm_region which follows the
1495 * submaps in a target map
1496 *
1497 */
1498 kern_return_t
vm_region_recurse_64(vm_map_t map,vm_address_ut * address_u,vm_size_ut * size_u,uint32_t * depth,vm_region_recurse_info_64_t info,mach_msg_type_number_t * infoCnt)1499 vm_region_recurse_64(
1500 vm_map_t map,
1501 vm_address_ut *address_u,
1502 vm_size_ut *size_u,
1503 uint32_t *depth,
1504 vm_region_recurse_info_64_t info,
1505 mach_msg_type_number_t *infoCnt)
1506 {
1507 kern_return_t kr;
1508
1509 kr = mach_vm_region_recurse(map, address_u, size_u, depth,
1510 (vm_region_recurse_info_t)info, infoCnt);
1511
1512 return vm_region_get_kern_return(kr, *address_u, *size_u);
1513 }
1514
1515 kern_return_t
vm_region_recurse(vm_map_t map,vm_offset_ut * address_u,vm_size_ut * size_u,natural_t * depth,vm_region_recurse_info_t info32,mach_msg_type_number_t * infoCnt)1516 vm_region_recurse(
1517 vm_map_t map,
1518 vm_offset_ut *address_u, /* IN/OUT */
1519 vm_size_ut *size_u, /* OUT */
1520 natural_t *depth, /* IN/OUT */
1521 vm_region_recurse_info_t info32, /* IN/OUT */
1522 mach_msg_type_number_t *infoCnt) /* IN/OUT */
1523 {
1524 vm_region_submap_info_data_64_t info64;
1525 vm_region_submap_info_t info;
1526 kern_return_t kr;
1527
1528 if (VM_MAP_NULL == map || *infoCnt < VM_REGION_SUBMAP_INFO_COUNT) {
1529 return KERN_INVALID_ARGUMENT;
1530 }
1531
1532 info = (vm_region_submap_info_t)info32;
1533 *infoCnt = VM_REGION_SUBMAP_INFO_COUNT_64;
1534
1535 kr = vm_map_region_recurse_64(map, address_u, size_u,
1536 depth, &info64, infoCnt);
1537
1538 info->protection = info64.protection;
1539 info->max_protection = info64.max_protection;
1540 info->inheritance = info64.inheritance;
1541 info->offset = (uint32_t)info64.offset; /* trouble-maker */
1542 info->user_tag = info64.user_tag;
1543 info->pages_resident = info64.pages_resident;
1544 info->pages_shared_now_private = info64.pages_shared_now_private;
1545 info->pages_swapped_out = info64.pages_swapped_out;
1546 info->pages_dirtied = info64.pages_dirtied;
1547 info->ref_count = info64.ref_count;
1548 info->shadow_depth = info64.shadow_depth;
1549 info->external_pager = info64.external_pager;
1550 info->share_mode = info64.share_mode;
1551 info->is_submap = info64.is_submap;
1552 info->behavior = info64.behavior;
1553 info->object_id = info64.object_id;
1554 info->user_wired_count = info64.user_wired_count;
1555
1556 *infoCnt = VM_REGION_SUBMAP_INFO_COUNT;
1557
1558 return vm_region_get_kern_return(kr, *address_u, *size_u);
1559 }
1560
1561 kern_return_t
mach_vm_purgable_control(vm_map_t map,mach_vm_offset_ut address_u,vm_purgable_t control,int * state)1562 mach_vm_purgable_control(
1563 vm_map_t map,
1564 mach_vm_offset_ut address_u,
1565 vm_purgable_t control,
1566 int *state)
1567 {
1568 if (VM_MAP_NULL == map) {
1569 return KERN_INVALID_ARGUMENT;
1570 }
1571
1572 switch (control) {
1573 case VM_PURGABLE_SET_STATE:
1574 case VM_PURGABLE_GET_STATE:
1575 case VM_PURGABLE_PURGE_ALL:
1576 break;
1577 case VM_PURGABLE_SET_STATE_FROM_KERNEL:
1578 default:
1579 /* not allowed from user-space */
1580 return KERN_INVALID_ARGUMENT;
1581 }
1582
1583 return vm_map_purgable_control(map, address_u, control, state);
1584 }
1585
1586 kern_return_t
mach_vm_purgable_control_external(mach_port_t target_tport,mach_vm_offset_ut address_u,vm_purgable_t control,int * state)1587 mach_vm_purgable_control_external(
1588 mach_port_t target_tport,
1589 mach_vm_offset_ut address_u,
1590 vm_purgable_t control,
1591 int *state)
1592 {
1593 vm_map_t map;
1594 kern_return_t kr;
1595
1596 if (control == VM_PURGABLE_GET_STATE) {
1597 map = convert_port_to_map_read(target_tport);
1598 } else {
1599 map = convert_port_to_map(target_tport);
1600 }
1601
1602 kr = mach_vm_purgable_control(map, address_u, control, state);
1603 vm_map_deallocate(map);
1604
1605 return kr;
1606 }
1607
1608 kern_return_t
vm_purgable_control_external(mach_port_t target_tport,vm_offset_ut address,vm_purgable_t control,int * state)1609 vm_purgable_control_external(
1610 mach_port_t target_tport,
1611 vm_offset_ut address,
1612 vm_purgable_t control,
1613 int *state)
1614 {
1615 return mach_vm_purgable_control_external(target_tport, address, control, state);
1616 }
1617
1618
1619 kern_return_t
mach_vm_page_query(vm_map_t map,mach_vm_offset_ut offset_u,int * disposition,int * ref_count)1620 mach_vm_page_query(
1621 vm_map_t map,
1622 mach_vm_offset_ut offset_u,
1623 int *disposition,
1624 int *ref_count)
1625 {
1626 kern_return_t kr;
1627 vm_page_info_basic_data_t info;
1628 mach_msg_type_number_t count;
1629
1630 if (VM_MAP_NULL == map) {
1631 return KERN_INVALID_ARGUMENT;
1632 }
1633
1634 count = VM_PAGE_INFO_BASIC_COUNT;
1635 kr = vm_map_page_info(map, offset_u, VM_PAGE_INFO_BASIC,
1636 (vm_page_info_t) &info, &count);
1637 if (kr == KERN_SUCCESS) {
1638 *disposition = info.disposition;
1639 *ref_count = info.ref_count;
1640 } else {
1641 *disposition = 0;
1642 *ref_count = 0;
1643 }
1644
1645 return kr;
1646 }
1647
1648 kern_return_t
vm_map_page_query(vm_map_t map,vm_offset_ut offset,int * disposition,int * ref_count)1649 vm_map_page_query(
1650 vm_map_t map,
1651 vm_offset_ut offset,
1652 int *disposition,
1653 int *ref_count)
1654 {
1655 return mach_vm_page_query(map, offset, disposition, ref_count);
1656 }
1657
1658 static __attribute__((always_inline, warn_unused_result))
1659 kern_return_t
mach_vm_page_range_query_sanitize(mach_vm_offset_ut address_u,mach_vm_size_ut size_u,int effective_page_mask,mach_vm_address_ut dispositions_addr_u,mach_vm_size_ut dispositions_count_u,mach_vm_offset_t * start,mach_vm_size_t * size,mach_vm_address_t * dispositions_addr,mach_vm_size_t * disp_buf_req_size)1660 mach_vm_page_range_query_sanitize(
1661 mach_vm_offset_ut address_u,
1662 mach_vm_size_ut size_u,
1663 int effective_page_mask,
1664 mach_vm_address_ut dispositions_addr_u,
1665 mach_vm_size_ut dispositions_count_u,
1666 mach_vm_offset_t *start,
1667 mach_vm_size_t *size,
1668 mach_vm_address_t *dispositions_addr,
1669 mach_vm_size_t *disp_buf_req_size)
1670 {
1671 mach_vm_offset_t end;
1672 mach_vm_size_t dispositions_count;
1673 mach_vm_address_t discard;
1674
1675 /*
1676 * There are no alignment requirements on
1677 * dispositions_addr_u/dispositions_count_u, those are derived into
1678 * inputs into copyout. So it is safe to unwrap them. We do want to
1679 * check that the range starting at dispositions_addr_u and ending
1680 * after dispositions_count_u integers is sound (i.e., doesn't wrap
1681 * around due to integer overflow).
1682 */
1683 *dispositions_addr = VM_SANITIZE_UNSAFE_UNWRAP(dispositions_addr_u);
1684 dispositions_count = VM_SANITIZE_UNSAFE_UNWRAP(dispositions_count_u);
1685 if (
1686 os_mul_overflow(
1687 dispositions_count,
1688 sizeof(int),
1689 disp_buf_req_size) ||
1690 os_add_overflow(
1691 *dispositions_addr,
1692 *disp_buf_req_size,
1693 &discard)) {
1694 return KERN_INVALID_ARGUMENT;
1695 }
1696
1697 return vm_sanitize_addr_size(address_u, size_u,
1698 VM_SANITIZE_CALLER_VM_MAP_PAGE_RANGE_QUERY,
1699 effective_page_mask,
1700 VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH, start,
1701 &end, size);
1702 }
1703
1704 kern_return_t
mach_vm_page_range_query(vm_map_t map,mach_vm_offset_ut address_u,mach_vm_size_ut size_u,mach_vm_address_ut dispositions_addr_u,mach_vm_size_ut * dispositions_count_u)1705 mach_vm_page_range_query(
1706 vm_map_t map,
1707 mach_vm_offset_ut address_u,
1708 mach_vm_size_ut size_u,
1709 mach_vm_address_ut dispositions_addr_u,
1710 mach_vm_size_ut *dispositions_count_u)
1711 {
1712 kern_return_t kr;
1713 int num_pages = 0, i = 0;
1714 mach_vm_size_t curr_sz = 0, copy_sz = 0;
1715 mach_vm_size_t disp_buf_req_size = 0, disp_buf_total_size = 0;
1716 mach_msg_type_number_t count = 0;
1717 mach_vm_address_t dispositions_addr;
1718
1719 void *info = NULL;
1720 void *local_disp = NULL;
1721 vm_map_size_t info_size = 0, local_disp_size = 0;
1722 mach_vm_offset_t start = 0;
1723 vm_map_size_t size;
1724 int effective_page_shift, effective_page_size, effective_page_mask;
1725
1726 if (map == VM_MAP_NULL || dispositions_count_u == NULL) {
1727 return KERN_INVALID_ARGUMENT;
1728 }
1729
1730 effective_page_shift = vm_self_region_page_shift_safely(map);
1731 if (effective_page_shift == -1) {
1732 return KERN_INVALID_ARGUMENT;
1733 }
1734 effective_page_size = (1 << effective_page_shift);
1735 effective_page_mask = effective_page_size - 1;
1736
1737 kr = mach_vm_page_range_query_sanitize(address_u,
1738 size_u,
1739 effective_page_mask,
1740 dispositions_addr_u,
1741 *dispositions_count_u,
1742 &start,
1743 &size,
1744 &dispositions_addr,
1745 &disp_buf_req_size);
1746 if (__improbable(kr != KERN_SUCCESS)) {
1747 return vm_sanitize_get_kr(kr);
1748 }
1749
1750 if (disp_buf_req_size == 0 || size == 0) {
1751 return KERN_SUCCESS;
1752 }
1753
1754 /*
1755 * For large requests, we will go through them
1756 * MAX_PAGE_RANGE_QUERY chunk at a time.
1757 */
1758
1759 curr_sz = MIN(size, MAX_PAGE_RANGE_QUERY);
1760 num_pages = (int) (curr_sz >> effective_page_shift);
1761
1762 info_size = num_pages * sizeof(vm_page_info_basic_data_t);
1763 info = kalloc_data(info_size, Z_WAITOK);
1764
1765 local_disp_size = num_pages * sizeof(int);
1766 local_disp = kalloc_data(local_disp_size, Z_WAITOK);
1767
1768 if (info == NULL || local_disp == NULL) {
1769 kr = KERN_RESOURCE_SHORTAGE;
1770 goto out;
1771 }
1772
1773 while (size) {
1774 count = VM_PAGE_INFO_BASIC_COUNT;
1775 kr = vm_map_page_range_info_internal(
1776 map,
1777 start,
1778 vm_map_round_page(start + curr_sz, effective_page_mask),
1779 effective_page_shift,
1780 VM_PAGE_INFO_BASIC,
1781 (vm_page_info_t) info,
1782 &count);
1783
1784 assert(kr == KERN_SUCCESS);
1785
1786 for (i = 0; i < num_pages; i++) {
1787 ((int*)local_disp)[i] = ((vm_page_info_basic_t)info)[i].disposition;
1788 }
1789
1790 copy_sz = MIN(disp_buf_req_size, num_pages * sizeof(int) /* an int per page */);
1791 kr = copyout(local_disp, (mach_vm_address_t)dispositions_addr, copy_sz);
1792
1793 start += curr_sz;
1794 disp_buf_req_size -= copy_sz;
1795 disp_buf_total_size += copy_sz;
1796
1797 if (kr != 0) {
1798 break;
1799 }
1800
1801 if ((disp_buf_req_size == 0) || (curr_sz >= size)) {
1802 /*
1803 * We might have inspected the full range OR
1804 * more than it esp. if the user passed in
1805 * non-page aligned start/size and/or if we
1806 * descended into a submap. We are done here.
1807 */
1808
1809 size = 0;
1810 } else {
1811 dispositions_addr += copy_sz;
1812
1813 size -= curr_sz;
1814
1815 curr_sz = MIN(vm_map_round_page(size, effective_page_mask), MAX_PAGE_RANGE_QUERY);
1816 num_pages = (int)(curr_sz >> effective_page_shift);
1817 }
1818 }
1819
1820 VM_SANITIZE_UT_SET(
1821 *dispositions_count_u,
1822 disp_buf_total_size / sizeof(int));
1823
1824 out:
1825 kfree_data(local_disp, local_disp_size);
1826 kfree_data(info, info_size);
1827 return kr;
1828 }
1829
1830 kern_return_t
mach_vm_page_info(vm_map_t map,mach_vm_address_ut address,vm_page_info_flavor_t flavor,vm_page_info_t info,mach_msg_type_number_t * count)1831 mach_vm_page_info(
1832 vm_map_t map,
1833 mach_vm_address_ut address,
1834 vm_page_info_flavor_t flavor,
1835 vm_page_info_t info,
1836 mach_msg_type_number_t *count)
1837 {
1838 kern_return_t kr;
1839
1840 if (map == VM_MAP_NULL) {
1841 return KERN_INVALID_ARGUMENT;
1842 }
1843
1844 kr = vm_map_page_info(map, address, flavor, info, count);
1845 return kr;
1846 }
1847
1848 /*
1849 * task_wire
1850 *
1851 * Set or clear the map's wiring_required flag. This flag, if set,
1852 * will cause all future virtual memory allocation to allocate
1853 * user wired memory. Unwiring pages wired down as a result of
1854 * this routine is done with the vm_wire interface.
1855 */
1856 kern_return_t
task_wire(vm_map_t map,boolean_t must_wire __unused)1857 task_wire(
1858 vm_map_t map,
1859 boolean_t must_wire __unused)
1860 {
1861 if (map == VM_MAP_NULL) {
1862 return KERN_INVALID_ARGUMENT;
1863 }
1864
1865 return KERN_NOT_SUPPORTED;
1866 }
1867
1868 kern_return_t
vm_map_exec_lockdown(vm_map_t map)1869 vm_map_exec_lockdown(
1870 vm_map_t map)
1871 {
1872 vmlp_api_start(VM_MAP_EXEC_LOCKDOWN);
1873
1874 if (map == VM_MAP_NULL) {
1875 vmlp_api_end(VM_MAP_EXEC_LOCKDOWN, KERN_INVALID_ARGUMENT);
1876 return KERN_INVALID_ARGUMENT;
1877 }
1878
1879 vm_map_lock(map);
1880 map->map_disallow_new_exec = TRUE;
1881 vm_map_unlock(map);
1882
1883 vmlp_api_end(VM_MAP_EXEC_LOCKDOWN, KERN_SUCCESS);
1884 return KERN_SUCCESS;
1885 }
1886
1887 #if XNU_PLATFORM_MacOSX
1888 kern_return_t
vm_region_object_create(__unused vm_map_t target_map,__unused vm_size_t size,__unused ipc_port_t * object_handle)1889 vm_region_object_create(
1890 __unused vm_map_t target_map,
1891 __unused vm_size_t size,
1892 __unused ipc_port_t *object_handle)
1893 {
1894 return KERN_NOT_SUPPORTED;
1895 }
1896 #endif /* XNU_PLATFORM_MacOSX */
1897
1898 extern boolean_t proc_is_simulated(struct proc *p);
1899
1900 kern_return_t
mach_vm_deferred_reclamation_buffer_allocate(task_t task,mach_vm_address_ut * address,uint64_t * sampling_period,uint32_t initial_capacity,uint32_t max_capacity)1901 mach_vm_deferred_reclamation_buffer_allocate(
1902 task_t task,
1903 mach_vm_address_ut *address,
1904 uint64_t *sampling_period,
1905 uint32_t initial_capacity,
1906 uint32_t max_capacity)
1907 {
1908 #if CONFIG_DEFERRED_RECLAIM
1909 if (task != current_task()) {
1910 /* Remote buffer operations are not supported*/
1911 return KERN_INVALID_TASK;
1912 }
1913 struct proc *p = task_get_proc_raw(task);
1914 if (proc_is_simulated(p)) {
1915 return KERN_NOT_SUPPORTED;
1916 }
1917 return vm_deferred_reclamation_buffer_allocate_internal(task, address, sampling_period, initial_capacity, max_capacity);
1918 #else
1919 (void) task;
1920 (void) address;
1921 (void) size;
1922 return KERN_NOT_SUPPORTED;
1923 #endif /* CONFIG_DEFERRED_RECLAIM */
1924 }
1925
1926 kern_return_t
mach_vm_deferred_reclamation_buffer_flush(task_t task,uint32_t num_entries_to_reclaim,mach_vm_size_ut * bytes_reclaimed_out)1927 mach_vm_deferred_reclamation_buffer_flush(
1928 task_t task,
1929 uint32_t num_entries_to_reclaim,
1930 mach_vm_size_ut *bytes_reclaimed_out)
1931 {
1932 #if CONFIG_DEFERRED_RECLAIM
1933 kern_return_t kr;
1934 mach_vm_size_t bytes_reclaimed = 0;
1935 if (task != current_task()) {
1936 /* Remote buffer operations are not supported */
1937 return KERN_INVALID_TASK;
1938 }
1939 if (bytes_reclaimed_out == NULL) {
1940 return KERN_INVALID_ARGUMENT;
1941 }
1942 kr = vm_deferred_reclamation_buffer_flush_internal(task, num_entries_to_reclaim, &bytes_reclaimed);
1943 *bytes_reclaimed_out = vm_sanitize_wrap_size(bytes_reclaimed);
1944 return kr;
1945 #else
1946 (void) task;
1947 (void) num_entries_to_reclaim;
1948 return KERN_NOT_SUPPORTED;
1949 #endif /* CONFIG_DEFERRED_RECLAIM */
1950 }
1951
1952 kern_return_t
mach_vm_deferred_reclamation_buffer_resize(task_t task,uint32_t new_len,mach_vm_size_ut * bytes_reclaimed_out)1953 mach_vm_deferred_reclamation_buffer_resize(task_t task,
1954 uint32_t new_len,
1955 mach_vm_size_ut *bytes_reclaimed_out)
1956 {
1957 #if CONFIG_DEFERRED_RECLAIM
1958 mach_error_t err;
1959 mach_vm_size_t bytes_reclaimed = 0;
1960
1961 if (task != current_task()) {
1962 /* Remote buffer operations are not supported */
1963 return KERN_INVALID_TASK;
1964 }
1965 if (bytes_reclaimed_out == NULL) {
1966 return KERN_INVALID_ARGUMENT;
1967 }
1968
1969 err = vm_deferred_reclamation_buffer_resize_internal(task, new_len, &bytes_reclaimed);
1970 *bytes_reclaimed_out = vm_sanitize_wrap_size(bytes_reclaimed);
1971 return err;
1972 #else
1973 (void) task;
1974 (void) size;
1975 return KERN_NOT_SUPPORTED;
1976 #endif /* CONFIG_DEFERRED_RECLAIM */
1977 }
1978
1979 kern_return_t
mach_vm_deferred_reclamation_buffer_query(task_t task,mach_vm_address_ut * addr_out_ut,mach_vm_size_ut * size_out_ut)1980 mach_vm_deferred_reclamation_buffer_query(task_t task,
1981 mach_vm_address_ut *addr_out_ut,
1982 mach_vm_size_ut *size_out_ut)
1983 {
1984 #if CONFIG_DEFERRED_RECLAIM
1985 return vm_deferred_reclamation_buffer_query_internal(task, addr_out_ut, size_out_ut);
1986 #else /* CONFIG_DEFERRED_RECLAIM */
1987 (void) task;
1988 (void) addr_out_ut;
1989 (void) size_out_ut;
1990 return KERN_NOT_SUPPORTED;
1991 #endif /* !CONFIG_DEFERRED_RECLAIM */
1992 }
1993
1994 #if CONFIG_MAP_RANGES
1995
1996 extern void qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
1997
1998 static int
vm_map_user_range_cmp(const void * e1,const void * e2)1999 vm_map_user_range_cmp(const void *e1, const void *e2)
2000 {
2001 const struct vm_map_user_range *r1 = e1;
2002 const struct vm_map_user_range *r2 = e2;
2003
2004 if (r1->vmur_min_address != r2->vmur_min_address) {
2005 return r1->vmur_min_address < r2->vmur_min_address ? -1 : 1;
2006 }
2007
2008 return 0;
2009 }
2010
2011 static int
mach_vm_range_recipe_v1_cmp(const void * e1,const void * e2)2012 mach_vm_range_recipe_v1_cmp(const void *e1, const void *e2)
2013 {
2014 const mach_vm_range_recipe_v1_t *r1 = e1;
2015 const mach_vm_range_recipe_v1_t *r2 = e2;
2016
2017 if (r1->range.min_address != r2->range.min_address) {
2018 return r1->range.min_address < r2->range.min_address ? -1 : 1;
2019 }
2020
2021 return 0;
2022 }
2023
2024 static inline __result_use_check kern_return_t
mach_vm_range_create_v1_sanitize(vm_map_t map,mach_vm_range_recipe_v1_ut * recipe_u,uint32_t count,mach_vm_range_recipe_v1_t ** recipe_p)2025 mach_vm_range_create_v1_sanitize(
2026 vm_map_t map,
2027 mach_vm_range_recipe_v1_ut *recipe_u,
2028 uint32_t count,
2029 mach_vm_range_recipe_v1_t **recipe_p)
2030 {
2031 kern_return_t kr;
2032
2033 for (size_t i = 0; i < count; i++) {
2034 vm_map_offset_t start, end;
2035 vm_map_size_t size;
2036 mach_vm_range_ut * range_u = &recipe_u[i].range_u;
2037 kr = vm_sanitize_addr_end(
2038 range_u->min_address_u,
2039 range_u->max_address_u,
2040 VM_SANITIZE_CALLER_MACH_VM_RANGE_CREATE,
2041 map,
2042 VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS
2043 | VM_SANITIZE_FLAGS_CHECK_ALIGNED_START
2044 | VM_SANITIZE_FLAGS_CHECK_ALIGNED_SIZE,
2045 &start, &end, &size); // Ignore return values
2046 if (__improbable(kr != KERN_SUCCESS)) {
2047 return kr;
2048 }
2049 }
2050 /*
2051 * Sanitization only checked properties of recipe_u.
2052 * We can now see it through the lens of the safe type.
2053 * The cast is undefined behavior, but of the kind VM sanitization
2054 * relies on anyway, so we don't expect this to cause issues.
2055 */
2056 *recipe_p = (mach_vm_range_recipe_v1_t *)recipe_u;
2057
2058 return KERN_SUCCESS;
2059 }
2060
2061 /*!
2062 * @function mach_vm_range_create_v1()
2063 *
2064 * @brief
2065 * Handle the backend for mach_vm_range_create() for the
2066 * MACH_VM_RANGE_FLAVOR_V1 flavor.
2067 *
2068 * @description
2069 * This call allows to create "ranges" in the map of a task
2070 * that have special semantics/policies around placement of
2071 * new allocations (in the vm_map_locate_space() sense).
2072 *
2073 * @returns
2074 * - KERN_SUCCESS on success
2075 * - KERN_INVALID_ARGUMENT for incorrect arguments
2076 * - KERN_NO_SPACE if the maximum amount of ranges would be exceeded
2077 * - KERN_MEMORY_PRESENT if any of the requested ranges
2078 * overlaps with existing ranges or allocations in the map.
2079 */
2080 static kern_return_t
mach_vm_range_create_v1(vm_map_t map,mach_vm_range_recipe_v1_ut * recipe_u,uint32_t new_count)2081 mach_vm_range_create_v1(
2082 vm_map_t map,
2083 mach_vm_range_recipe_v1_ut *recipe_u,
2084 uint32_t new_count)
2085 {
2086 mach_vm_range_recipe_v1_t *recipe;
2087 vm_map_user_range_t table;
2088 kern_return_t kr = KERN_SUCCESS;
2089 uint16_t count;
2090
2091 vmlp_api_start(MACH_VM_RANGE_CREATE_V1);
2092
2093 struct mach_vm_range void1 = {
2094 .min_address = map->default_range.max_address,
2095 .max_address = map->data_range.min_address,
2096 };
2097 struct mach_vm_range void2 = {
2098 .min_address = map->data_range.max_address,
2099 #if XNU_TARGET_OS_IOS && EXTENDED_USER_VA_SUPPORT
2100 .max_address = MACH_VM_JUMBO_ADDRESS,
2101 #else /* !XNU_TARGET_OS_IOS || !EXTENDED_USER_VA_SUPPORT */
2102 .max_address = vm_map_max(map),
2103 #endif /* XNU_TARGET_OS_IOS && EXTENDED_USER_VA_SUPPORT */
2104 };
2105
2106 kr = mach_vm_range_create_v1_sanitize(map, recipe_u, new_count, &recipe);
2107 if (__improbable(kr != KERN_SUCCESS)) {
2108 kr = vm_sanitize_get_kr(kr);
2109 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, kr);
2110 return kr;
2111 }
2112
2113 qsort(recipe, new_count, sizeof(mach_vm_range_recipe_v1_t),
2114 mach_vm_range_recipe_v1_cmp);
2115
2116 /*
2117 * Step 1: Validate that the recipes have no intersections.
2118 */
2119
2120 for (size_t i = 0; i < new_count; i++) {
2121 mach_vm_range_t r = &recipe[i].range;
2122 mach_vm_size_t s;
2123
2124 if (recipe[i].flags) {
2125 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, KERN_INVALID_ARGUMENT);
2126 return KERN_INVALID_ARGUMENT;
2127 }
2128
2129 static_assert((int)UMEM_RANGE_ID_FIXED == MACH_VM_RANGE_FIXED);
2130 switch (recipe[i].range_tag) {
2131 case MACH_VM_RANGE_FIXED:
2132 break;
2133 default:
2134 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, KERN_INVALID_ARGUMENT);
2135 return KERN_INVALID_ARGUMENT;
2136 }
2137
2138 s = mach_vm_range_size(r);
2139 if (!mach_vm_range_contains(&void1, r->min_address, s) &&
2140 !mach_vm_range_contains(&void2, r->min_address, s)) {
2141 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, KERN_INVALID_ARGUMENT);
2142 return KERN_INVALID_ARGUMENT;
2143 }
2144
2145 if (i > 0 && recipe[i - 1].range.max_address >
2146 recipe[i].range.min_address) {
2147 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, KERN_INVALID_ARGUMENT);
2148 return KERN_INVALID_ARGUMENT;
2149 }
2150 }
2151
2152 vm_map_lock(map);
2153
2154 table = map->extra_ranges;
2155 count = map->extra_ranges_count;
2156
2157 if (count + new_count > VM_MAP_EXTRA_RANGES_MAX) {
2158 kr = KERN_NO_SPACE;
2159 goto out_unlock;
2160 }
2161
2162 /*
2163 * Step 2: Check that there is no intersection with existing ranges.
2164 */
2165
2166 for (size_t i = 0, j = 0; i < new_count && j < count;) {
2167 mach_vm_range_t r1 = &recipe[i].range;
2168 vm_map_user_range_t r2 = &table[j];
2169
2170 if (r1->max_address <= r2->vmur_min_address) {
2171 i++;
2172 } else if (r2->vmur_max_address <= r1->min_address) {
2173 j++;
2174 } else {
2175 kr = KERN_MEMORY_PRESENT;
2176 goto out_unlock;
2177 }
2178 }
2179
2180 /*
2181 * Step 3: commit the new ranges.
2182 */
2183
2184 static_assert(VM_MAP_EXTRA_RANGES_MAX * sizeof(struct vm_map_user_range) <=
2185 KALLOC_SAFE_ALLOC_SIZE);
2186
2187 table = krealloc_data(table,
2188 count * sizeof(struct vm_map_user_range),
2189 (count + new_count) * sizeof(struct vm_map_user_range),
2190 Z_ZERO | Z_WAITOK | Z_NOFAIL);
2191
2192 for (size_t i = 0; i < new_count; i++) {
2193 static_assert(MACH_VM_MAX_ADDRESS < (1ull << 56));
2194
2195 table[count + i] = (struct vm_map_user_range){
2196 .vmur_min_address = recipe[i].range.min_address,
2197 .vmur_max_address = recipe[i].range.max_address,
2198 .vmur_range_id = (vm_map_range_id_t)recipe[i].range_tag,
2199 };
2200 }
2201
2202 qsort(table, count + new_count,
2203 sizeof(struct vm_map_user_range), vm_map_user_range_cmp);
2204
2205 map->extra_ranges_count += new_count;
2206 map->extra_ranges = table;
2207
2208 out_unlock:
2209 vm_map_unlock(map);
2210
2211 if (kr == KERN_SUCCESS) {
2212 for (size_t i = 0; i < new_count; i++) {
2213 vm_map_kernel_flags_t vmk_flags = {
2214 .vmf_fixed = true,
2215 .vmf_overwrite = true,
2216 .vmkf_overwrite_immutable = true,
2217 .vm_tag = recipe[i].vm_tag,
2218 };
2219 __assert_only kern_return_t kr2;
2220
2221 vmlp_range_event(map, recipe[i].range.min_address, recipe[i].range.max_address - recipe[i].range.min_address);
2222
2223 kr2 = vm_map_enter(map, &recipe[i].range.min_address,
2224 mach_vm_range_size(&recipe[i].range),
2225 0, vmk_flags, VM_OBJECT_NULL, 0, FALSE,
2226 VM_PROT_NONE, VM_PROT_ALL,
2227 VM_INHERIT_DEFAULT);
2228 assert(kr2 == KERN_SUCCESS);
2229 }
2230 }
2231 vmlp_api_end(MACH_VM_RANGE_CREATE_V1, kr);
2232 return kr;
2233 }
2234
2235 kern_return_t
mach_vm_range_create(vm_map_t map,mach_vm_range_flavor_t flavor,mach_vm_range_recipes_raw_t recipe,natural_t size)2236 mach_vm_range_create(
2237 vm_map_t map,
2238 mach_vm_range_flavor_t flavor,
2239 mach_vm_range_recipes_raw_t recipe,
2240 natural_t size)
2241 {
2242 if (map != current_map()) {
2243 return KERN_INVALID_ARGUMENT;
2244 }
2245
2246 if (!map->uses_user_ranges) {
2247 return KERN_NOT_SUPPORTED;
2248 }
2249
2250 if (size == 0) {
2251 return KERN_SUCCESS;
2252 }
2253
2254 if (flavor == MACH_VM_RANGE_FLAVOR_V1) {
2255 mach_vm_range_recipe_v1_ut *array;
2256
2257 if (size % sizeof(mach_vm_range_recipe_v1_ut)) {
2258 return KERN_INVALID_ARGUMENT;
2259 }
2260
2261 size /= sizeof(mach_vm_range_recipe_v1_ut);
2262 if (size > VM_MAP_EXTRA_RANGES_MAX) {
2263 return KERN_NO_SPACE;
2264 }
2265
2266 array = (mach_vm_range_recipe_v1_ut *)recipe;
2267 return mach_vm_range_create_v1(map, array, size);
2268 }
2269
2270 return KERN_INVALID_ARGUMENT;
2271 }
2272
2273 #else /* !CONFIG_MAP_RANGES */
2274
2275 kern_return_t
mach_vm_range_create(vm_map_t map,mach_vm_range_flavor_t flavor,mach_vm_range_recipes_raw_t recipe,natural_t size)2276 mach_vm_range_create(
2277 vm_map_t map,
2278 mach_vm_range_flavor_t flavor,
2279 mach_vm_range_recipes_raw_t recipe,
2280 natural_t size)
2281 {
2282 #pragma unused(map, flavor, recipe, size)
2283 return KERN_NOT_SUPPORTED;
2284 }
2285
2286 #endif /* !CONFIG_MAP_RANGES */
2287
2288 /*
2289 * These symbols are looked up at runtime by vmware, VirtualBox,
2290 * despite not being exported in the symbol sets.
2291 */
2292
2293 #if defined(__x86_64__)
2294
2295 extern typeof(mach_vm_remap_external) mach_vm_remap;
2296 extern typeof(mach_vm_map_external) mach_vm_map;
2297 extern typeof(vm_map_external) vm_map;
2298
2299 kern_return_t
mach_vm_map(vm_map_t target_map,mach_vm_offset_ut * address,mach_vm_size_ut initial_size,mach_vm_offset_ut mask,int flags,ipc_port_t port,memory_object_offset_ut offset,boolean_t copy,vm_prot_ut cur_protection,vm_prot_ut max_protection,vm_inherit_ut inheritance)2300 mach_vm_map(
2301 vm_map_t target_map,
2302 mach_vm_offset_ut *address,
2303 mach_vm_size_ut initial_size,
2304 mach_vm_offset_ut mask,
2305 int flags,
2306 ipc_port_t port,
2307 memory_object_offset_ut offset,
2308 boolean_t copy,
2309 vm_prot_ut cur_protection,
2310 vm_prot_ut max_protection,
2311 vm_inherit_ut inheritance)
2312 {
2313 return mach_vm_map_external(target_map, address, initial_size, mask, flags, port,
2314 offset, copy, cur_protection, max_protection, inheritance);
2315 }
2316
2317 kern_return_t
mach_vm_remap(vm_map_t target_map,mach_vm_offset_ut * address,mach_vm_size_ut size,mach_vm_offset_ut mask,int flags,vm_map_t src_map,mach_vm_offset_ut memory_address,boolean_t copy,vm_prot_ut * cur_protection,vm_prot_ut * max_protection,vm_inherit_ut inheritance)2318 mach_vm_remap(
2319 vm_map_t target_map,
2320 mach_vm_offset_ut *address,
2321 mach_vm_size_ut size,
2322 mach_vm_offset_ut mask,
2323 int flags,
2324 vm_map_t src_map,
2325 mach_vm_offset_ut memory_address,
2326 boolean_t copy,
2327 vm_prot_ut *cur_protection, /* OUT */
2328 vm_prot_ut *max_protection, /* OUT */
2329 vm_inherit_ut inheritance)
2330 {
2331 return mach_vm_remap_external(target_map, address, size, mask, flags, src_map, memory_address,
2332 copy, cur_protection, max_protection, inheritance);
2333 }
2334
2335 kern_return_t
vm_map(vm_map_t target_map,vm_offset_ut * address,vm_size_ut size,vm_offset_ut mask,int flags,ipc_port_t port,vm_offset_ut offset,boolean_t copy,vm_prot_ut cur_protection,vm_prot_ut max_protection,vm_inherit_ut inheritance)2336 vm_map(
2337 vm_map_t target_map,
2338 vm_offset_ut *address,
2339 vm_size_ut size,
2340 vm_offset_ut mask,
2341 int flags,
2342 ipc_port_t port,
2343 vm_offset_ut offset,
2344 boolean_t copy,
2345 vm_prot_ut cur_protection,
2346 vm_prot_ut max_protection,
2347 vm_inherit_ut inheritance)
2348 {
2349 return mach_vm_map(target_map, address,
2350 size, mask, flags, port, offset, copy,
2351 cur_protection, max_protection, inheritance);
2352 }
2353
2354 #endif /* __x86_64__ */
2355