1 /*
2 * Copyright (c) 2024 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/memory_entry.h>
30 #include <mach/memory_entry_server.h>
31 #include <mach/vm_map_server.h>
32 #include <mach/mach_vm_server.h>
33 #include <vm/vm_purgeable_internal.h>
34 #include <mach/mach_host_server.h>
35 #include <IOKit/IOBSD.h>
36 #include <vm/vm_memory_entry_xnu.h>
37 #include <vm/vm_map_internal.h>
38 #include <vm/memory_object_internal.h>
39 #include <vm/vm_protos_internal.h>
40 #include <vm/vm_object_internal.h>
41 #include <vm/vm_iokit.h>
42
43 static void mach_memory_entry_no_senders(ipc_port_t, mach_port_mscount_t);
44
45 IPC_KOBJECT_DEFINE(IKOT_NAMED_ENTRY,
46 .iko_op_stable = true,
47 .iko_op_no_senders = mach_memory_entry_no_senders);
48
49 /*
50 * mach_make_memory_entry_64
51 *
52 * Think of it as a two-stage vm_remap() operation. First
53 * you get a handle. Second, you get map that handle in
54 * somewhere else. Rather than doing it all at once (and
55 * without needing access to the other whole map).
56 */
57 kern_return_t
mach_make_memory_entry_64(vm_map_t target_map,memory_object_size_ut * size_u,memory_object_offset_ut offset_u,vm_prot_ut permission_u,ipc_port_t * object_handle,ipc_port_t parent_handle)58 mach_make_memory_entry_64(
59 vm_map_t target_map,
60 memory_object_size_ut *size_u,
61 memory_object_offset_ut offset_u,
62 vm_prot_ut permission_u,
63 ipc_port_t *object_handle,
64 ipc_port_t parent_handle)
65 {
66 return mach_make_memory_entry_internal(target_map,
67 size_u,
68 offset_u,
69 permission_u,
70 VM_NAMED_ENTRY_KERNEL_FLAGS_NONE,
71 object_handle,
72 parent_handle);
73 }
74
75 static inline void
vm_memory_entry_decode_perm(vm_prot_t permission,unsigned int * access,vm_prot_t * protections,bool * mask_protections,bool * use_data_addr,bool * use_4K_compat)76 vm_memory_entry_decode_perm(
77 vm_prot_t permission,
78 unsigned int *access,
79 vm_prot_t *protections,
80 bool *mask_protections,
81 bool *use_data_addr,
82 bool *use_4K_compat)
83 {
84 *protections = permission & VM_PROT_ALL;
85 *mask_protections = permission & VM_PROT_IS_MASK;
86 *access = GET_MAP_MEM(permission);
87 *use_data_addr = ((permission & MAP_MEM_USE_DATA_ADDR) != 0);
88 *use_4K_compat = ((permission & MAP_MEM_4K_DATA_ADDR) != 0);
89 }
90
91 static inline vm_map_offset_t
vm_memory_entry_get_offset_in_page(vm_map_offset_t offset,vm_map_offset_t map_start,bool use_data_addr,bool use_4K_compat)92 vm_memory_entry_get_offset_in_page(
93 vm_map_offset_t offset,
94 vm_map_offset_t map_start,
95 bool use_data_addr,
96 bool use_4K_compat)
97 {
98 vm_map_offset_t offset_in_page;
99
100 if (use_data_addr || use_4K_compat) {
101 offset_in_page = offset - map_start;
102 if (use_4K_compat) {
103 offset_in_page &= ~((signed)(0xFFF));
104 }
105 } else {
106 offset_in_page = 0;
107 }
108
109 return offset_in_page;
110 }
111
112 static inline kern_return_t
mach_make_memory_entry_cleanup(kern_return_t kr,vm_map_t target_map __unused,memory_object_size_ut * size_u,vm_map_offset_ut offset_u __unused,vm_prot_t permission __unused,vm_named_entry_t user_entry __unused,ipc_port_t * object_handle)113 mach_make_memory_entry_cleanup(
114 kern_return_t kr,
115 vm_map_t target_map __unused,
116 memory_object_size_ut *size_u,
117 vm_map_offset_ut offset_u __unused,
118 vm_prot_t permission __unused,
119 vm_named_entry_t user_entry __unused,
120 ipc_port_t *object_handle)
121 {
122 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry "
123 "%p kr 0x%x\n", target_map, VM_SANITIZE_UNSAFE_UNWRAP(offset_u),
124 VM_SANITIZE_UNSAFE_UNWRAP(*size_u), permission, user_entry,
125 vm_sanitize_get_kr(kr));
126 /*
127 * Set safe size and object_handle value on failed return
128 */
129 *size_u = vm_sanitize_wrap_size(0);
130 *object_handle = IPC_PORT_NULL;
131 return vm_sanitize_get_kr(kr);
132 }
133
134 static __attribute__((always_inline, warn_unused_result))
135 kern_return_t
mach_make_memory_entry_mem_only_sanitize(vm_map_t target_map,memory_object_size_ut size_u,vm_map_offset_ut offset_u,vm_map_offset_t * map_start,vm_map_offset_t * map_end,vm_map_size_t * map_size)136 mach_make_memory_entry_mem_only_sanitize(
137 vm_map_t target_map,
138 memory_object_size_ut size_u,
139 vm_map_offset_ut offset_u,
140 vm_map_offset_t *map_start,
141 vm_map_offset_t *map_end,
142 vm_map_size_t *map_size)
143 {
144 /*
145 * This code path doesn't use offset and size. They don't need to be
146 * validated. However inorder to maintain backward compatibility some
147 * checks on offset and size have been left.
148 */
149 return vm_sanitize_addr_size(offset_u, size_u,
150 VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY,
151 target_map, VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH,
152 map_start, map_end, map_size);
153 }
154
155 static kern_return_t
mach_make_memory_entry_mem_only(vm_map_t target_map,memory_object_size_ut * size_u,memory_object_offset_ut offset_u,vm_prot_t permission,ipc_port_t * object_handle,vm_named_entry_t parent_entry)156 mach_make_memory_entry_mem_only(
157 vm_map_t target_map,
158 memory_object_size_ut *size_u,
159 memory_object_offset_ut offset_u,
160 vm_prot_t permission,
161 ipc_port_t *object_handle,
162 vm_named_entry_t parent_entry)
163 {
164 boolean_t parent_is_object;
165 vm_object_t object;
166 unsigned int access;
167 vm_prot_t protections;
168 bool mask_protections;
169 unsigned int wimg_mode;
170 bool use_data_addr;
171 bool use_4K_compat;
172 vm_named_entry_t user_entry __unused = NULL;
173 kern_return_t kr;
174 vm_map_size_t map_size;
175 vm_map_offset_t map_start, map_end;
176
177 /*
178 * Sanitize addr and size. Permimssions have been sanitized prior to
179 * dispatch
180 */
181 kr = mach_make_memory_entry_mem_only_sanitize(target_map,
182 *size_u,
183 offset_u,
184 &map_start,
185 &map_end,
186 &map_size);
187 if (__improbable(kr != KERN_SUCCESS)) {
188 return mach_make_memory_entry_cleanup(kr, target_map,
189 size_u, offset_u, permission, user_entry, object_handle);
190 }
191
192 vm_memory_entry_decode_perm(permission, &access, &protections,
193 &mask_protections, &use_data_addr, &use_4K_compat);
194
195 if (use_data_addr || use_4K_compat || parent_entry == NULL) {
196 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
197 size_u, offset_u, permission, user_entry, object_handle);
198 }
199
200 parent_is_object = parent_entry->is_object;
201 if (!parent_is_object) {
202 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
203 size_u, offset_u, permission, user_entry, object_handle);
204 }
205
206 if ((access != parent_entry->access) &&
207 !(parent_entry->protection & VM_PROT_WRITE)) {
208 return mach_make_memory_entry_cleanup(KERN_INVALID_RIGHT, target_map,
209 size_u, offset_u, permission, user_entry, object_handle);
210 }
211
212 object = vm_named_entry_to_vm_object(parent_entry);
213 if (parent_is_object && object != VM_OBJECT_NULL) {
214 wimg_mode = object->wimg_bits;
215 } else {
216 wimg_mode = VM_WIMG_USE_DEFAULT;
217 }
218 vm_prot_to_wimg(access, &wimg_mode);
219 if (parent_is_object && object &&
220 (access != MAP_MEM_NOOP) &&
221 (!(object->nophyscache))) {
222 if (object->wimg_bits != wimg_mode) {
223 vm_object_lock(object);
224 vm_object_change_wimg_mode(object, wimg_mode);
225 vm_object_unlock(object);
226 }
227 }
228 if (access != MAP_MEM_NOOP) {
229 parent_entry->access = access;
230 }
231 if (object_handle) {
232 *object_handle = IP_NULL;
233 }
234 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry "
235 "%p kr 0x%x\n", target_map, VM_SANITIZE_UNSAFE_UNWRAP(offset_u),
236 VM_SANITIZE_UNSAFE_UNWRAP(*size_u), permission, user_entry, KERN_SUCCESS);
237 /*
238 * TODO: Size isn't being set in this path
239 */
240 return KERN_SUCCESS;
241 }
242
243 #if CONFIG_PROB_GZALLOC
244 static inline vm_map_offset_ut
vm_memory_entry_pgz_decode_offset(vm_map_t target_map,vm_map_offset_ut offset_u,memory_object_size_ut * size_u __unused)245 vm_memory_entry_pgz_decode_offset(
246 vm_map_t target_map,
247 vm_map_offset_ut offset_u,
248 memory_object_size_ut *size_u __unused)
249 {
250 if (target_map == NULL || target_map->pmap == kernel_pmap) {
251 vm_map_offset_t pgz_offset;
252
253 /*
254 * It's ok to unsafe unwrap because PGZ does not ship to
255 * customers.
256 */
257 pgz_offset = pgz_decode(VM_SANITIZE_UNSAFE_UNWRAP(offset_u),
258 VM_SANITIZE_UNSAFE_UNWRAP(*size_u));
259 return vm_sanitize_wrap_addr(pgz_offset);
260 }
261 return offset_u;
262 }
263 #endif /* CONFIG_PROB_GZALLOC */
264
265 static __attribute__((always_inline, warn_unused_result))
266 kern_return_t
mach_make_memory_entry_generic_sanitize(vm_map_t target_map,memory_object_size_ut size_u,vm_map_offset_ut offset_u,vm_map_offset_t * map_start,vm_map_offset_t * map_end,vm_map_size_t * map_size,vm_map_offset_t * offset)267 mach_make_memory_entry_generic_sanitize(
268 vm_map_t target_map,
269 memory_object_size_ut size_u,
270 vm_map_offset_ut offset_u,
271 vm_map_offset_t *map_start,
272 vm_map_offset_t *map_end,
273 vm_map_size_t *map_size,
274 vm_map_offset_t *offset)
275 {
276 kern_return_t kr;
277
278 /*
279 * Validate start and end
280 */
281 kr = vm_sanitize_addr_size(offset_u, size_u,
282 VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY,
283 target_map, VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH,
284 map_start, map_end, map_size);
285 if (__improbable(kr != KERN_SUCCESS)) {
286 return kr;
287 }
288 /*
289 * Validate offset
290 */
291 kr = vm_sanitize_offset(offset_u, VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY,
292 *map_start, *map_end, offset);
293 if (__improbable(kr != KERN_SUCCESS)) {
294 return kr;
295 }
296
297 return KERN_SUCCESS;
298 }
299
300 static kern_return_t
mach_make_memory_entry_named_create(vm_map_t target_map,memory_object_size_ut * size_u,vm_map_offset_ut offset_u,vm_prot_t permission,vm_named_entry_kernel_flags_t vmne_kflags,ipc_port_t * object_handle)301 mach_make_memory_entry_named_create(
302 vm_map_t target_map,
303 memory_object_size_ut *size_u,
304 vm_map_offset_ut offset_u,
305 vm_prot_t permission,
306 vm_named_entry_kernel_flags_t vmne_kflags,
307 ipc_port_t *object_handle)
308 {
309 vm_object_t object;
310 unsigned int access;
311 vm_prot_t protections;
312 bool mask_protections;
313 unsigned int wimg_mode;
314 bool use_data_addr;
315 bool use_4K_compat;
316 int ledger_flags = 0;
317 task_t owner;
318 bool fully_owned = false;
319 vm_named_entry_t user_entry = NULL;
320 kern_return_t kr;
321 vm_map_size_t map_size;
322 vm_map_offset_t map_start, map_end, offset;
323
324 if (VM_SANITIZE_UNSAFE_IS_ZERO(*size_u)) {
325 return mach_make_memory_entry_cleanup(KERN_SUCCESS, target_map,
326 size_u, offset_u, permission, user_entry, object_handle);
327 }
328
329 #if CONFIG_PROB_GZALLOC
330 /*
331 * If offset is PGZ protected we need PGZ to fix it up to the right
332 * value prior to validation and use.
333 */
334 offset_u = vm_memory_entry_pgz_decode_offset(target_map, offset_u, size_u);
335 #endif /* CONFIG_PROB_GZALLOC */
336
337 /*
338 * Sanitize addr and size. Permimssions have been sanitized prior to
339 * dispatch
340 */
341 kr = mach_make_memory_entry_generic_sanitize(target_map,
342 *size_u,
343 offset_u,
344 &map_start,
345 &map_end,
346 &map_size,
347 &offset);
348 if (__improbable(kr != KERN_SUCCESS)) {
349 return mach_make_memory_entry_cleanup(kr, target_map,
350 size_u, offset_u, permission, user_entry, object_handle);
351 }
352
353 assert(map_size != 0);
354
355 vm_memory_entry_decode_perm(permission, &access, &protections,
356 &mask_protections, &use_data_addr, &use_4K_compat);
357
358 if (use_data_addr || use_4K_compat) {
359 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
360 size_u, offset_u, permission, user_entry, object_handle);
361 }
362
363 /*
364 * Force the creation of the VM object now.
365 */
366 #if __LP64__
367 if (map_size > ANON_MAX_SIZE) {
368 return mach_make_memory_entry_cleanup(KERN_FAILURE, target_map,
369 size_u, offset_u, permission, user_entry, object_handle);
370 }
371 #endif /* __LP64__ */
372
373 object = vm_object_allocate(map_size, vm_map_maybe_serial_id(target_map));
374 assert(object != VM_OBJECT_NULL);
375 vm_object_lock(object);
376
377 /*
378 * XXX
379 * We use this path when we want to make sure that
380 * nobody messes with the object (coalesce, for
381 * example) before we map it.
382 * We might want to use these objects for transposition via
383 * vm_object_transpose() too, so we don't want any copy or
384 * shadow objects either...
385 */
386 object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
387 VM_OBJECT_SET_TRUE_SHARE(object, TRUE);
388
389 owner = current_task();
390 if ((permission & MAP_MEM_PURGABLE) ||
391 vmne_kflags.vmnekf_ledger_tag) {
392 assert(object->vo_owner == NULL);
393 assert(object->resident_page_count == 0);
394 assert(object->wired_page_count == 0);
395 assert(owner != TASK_NULL);
396 if (vmne_kflags.vmnekf_ledger_no_footprint) {
397 ledger_flags |= VM_LEDGER_FLAG_NO_FOOTPRINT;
398 object->vo_no_footprint = TRUE;
399 }
400 if (permission & MAP_MEM_PURGABLE) {
401 if (!(permission & VM_PROT_WRITE)) {
402 /* if we can't write, we can't purge */
403 vm_object_unlock(object);
404 vm_object_deallocate(object);
405 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT,
406 target_map, size_u, offset_u, permission, user_entry,
407 object_handle);
408 }
409 VM_OBJECT_SET_PURGABLE(object, VM_PURGABLE_NONVOLATILE);
410 if (permission & MAP_MEM_PURGABLE_KERNEL_ONLY) {
411 VM_OBJECT_SET_PURGEABLE_ONLY_BY_KERNEL(object, TRUE);
412 }
413 #if __arm64__
414 if (owner->task_legacy_footprint) {
415 /*
416 * For ios11, we failed to account for
417 * this memory. Keep doing that for
418 * legacy apps (built before ios12),
419 * for backwards compatibility's sake...
420 */
421 owner = kernel_task;
422 }
423 #endif /* __arm64__ */
424 vm_purgeable_nonvolatile_enqueue(object, owner);
425 /* all memory in this named entry is "owned" */
426 fully_owned = true;
427 }
428 }
429
430 if (vmne_kflags.vmnekf_ledger_tag) {
431 /*
432 * Bill this object to the current task's
433 * ledgers for the given tag.
434 */
435 if (vmne_kflags.vmnekf_ledger_no_footprint) {
436 ledger_flags |= VM_LEDGER_FLAG_NO_FOOTPRINT;
437 }
438 kr = vm_object_ownership_change(
439 object,
440 vmne_kflags.vmnekf_ledger_tag,
441 owner, /* new owner */
442 ledger_flags,
443 FALSE); /* task_objq locked? */
444 if (kr != KERN_SUCCESS) {
445 vm_object_unlock(object);
446 vm_object_deallocate(object);
447 return mach_make_memory_entry_cleanup(kr, target_map,
448 size_u, offset_u, permission, user_entry, object_handle);
449 }
450 /* all memory in this named entry is "owned" */
451 fully_owned = true;
452 }
453
454 #if CONFIG_SECLUDED_MEMORY
455 if (secluded_for_iokit && /* global boot-arg */
456 ((permission & MAP_MEM_GRAB_SECLUDED))) {
457 object->can_grab_secluded = TRUE;
458 assert(!object->eligible_for_secluded);
459 }
460 #endif /* CONFIG_SECLUDED_MEMORY */
461
462 /*
463 * The VM object is brand new and nobody else knows about it,
464 * so we don't need to lock it.
465 */
466
467 wimg_mode = object->wimg_bits;
468 vm_prot_to_wimg(access, &wimg_mode);
469 if (access != MAP_MEM_NOOP) {
470 object->wimg_bits = wimg_mode;
471 }
472
473 vm_object_unlock(object);
474
475 /* the object has no pages, so no WIMG bits to update here */
476
477 user_entry = mach_memory_entry_allocate(object_handle);
478 vm_named_entry_associate_vm_object(
479 user_entry,
480 object,
481 0,
482 map_size,
483 (protections & VM_PROT_ALL));
484 user_entry->internal = TRUE;
485 user_entry->is_sub_map = FALSE;
486 user_entry->offset = 0;
487 user_entry->data_offset = 0;
488 user_entry->protection = protections;
489 user_entry->access = access;
490 user_entry->size = map_size;
491 user_entry->is_fully_owned = fully_owned;
492
493 /* user_object pager and internal fields are not used */
494 /* when the object field is filled in. */
495
496 *size_u = vm_sanitize_wrap_size(user_entry->size - user_entry->data_offset);
497 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry "
498 "%p kr 0x%x\n", target_map, offset, VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
499 permission, user_entry, KERN_SUCCESS);
500 return KERN_SUCCESS;
501 }
502
503 static kern_return_t
mach_make_memory_entry_copy(vm_map_t target_map,memory_object_size_ut * size_u,vm_map_offset_ut offset_u,vm_prot_t permission,__unused vm_named_entry_kernel_flags_t vmne_kflags,ipc_port_t * object_handle)504 mach_make_memory_entry_copy(
505 vm_map_t target_map,
506 memory_object_size_ut *size_u,
507 vm_map_offset_ut offset_u,
508 vm_prot_t permission,
509 __unused vm_named_entry_kernel_flags_t vmne_kflags,
510 ipc_port_t *object_handle)
511 {
512 unsigned int access;
513 vm_prot_t protections;
514 bool mask_protections;
515 bool use_data_addr;
516 bool use_4K_compat;
517 vm_named_entry_t user_entry = NULL;
518 vm_map_copy_t copy;
519 /*
520 * Stash the offset in the page for use by vm_map_enter_mem_object()
521 * in the VM_FLAGS_RETURN_DATA_ADDR/MAP_MEM_USE_DATA_ADDR case.
522 */
523 vm_object_offset_t offset_in_page;
524 kern_return_t kr;
525 vm_map_size_t map_size;
526 vm_map_offset_t map_start, map_end, offset;
527
528 if (VM_SANITIZE_UNSAFE_IS_ZERO(*size_u)) {
529 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
530 size_u, offset_u, permission, user_entry, object_handle);
531 }
532
533 #if CONFIG_PROB_GZALLOC
534 /*
535 * If offset is PGZ protected we need PGZ to fix it up to the right
536 * value prior to validation and use.
537 */
538 offset_u = vm_memory_entry_pgz_decode_offset(target_map, offset_u, size_u);
539 #endif /* CONFIG_PROB_GZALLOC */
540
541 /*
542 * Sanitize addr and size. Permimssions have been sanitized prior to
543 * dispatch
544 */
545 kr = mach_make_memory_entry_generic_sanitize(target_map,
546 *size_u,
547 offset_u,
548 &map_start,
549 &map_end,
550 &map_size,
551 &offset);
552 if (__improbable(kr != KERN_SUCCESS)) {
553 return mach_make_memory_entry_cleanup(kr, target_map,
554 size_u, offset_u, permission, user_entry, object_handle);
555 }
556
557 assert(map_size != 0);
558
559 vm_memory_entry_decode_perm(permission, &access, &protections,
560 &mask_protections, &use_data_addr, &use_4K_compat);
561
562 if (target_map == VM_MAP_NULL) {
563 return mach_make_memory_entry_cleanup(KERN_INVALID_TASK, target_map,
564 size_u, offset_u, permission, user_entry, object_handle);
565 }
566
567 offset_in_page = vm_memory_entry_get_offset_in_page(offset, map_start,
568 use_data_addr, use_4K_compat);
569
570 int copyin_flags = VM_MAP_COPYIN_ENTRY_LIST;
571 kr = vm_map_copyin_internal(target_map,
572 map_start,
573 map_size,
574 copyin_flags,
575 ©);
576 if (kr != KERN_SUCCESS) {
577 return mach_make_memory_entry_cleanup(kr, target_map,
578 size_u, offset_u, permission, user_entry, object_handle);
579 }
580 assert(copy != VM_MAP_COPY_NULL);
581
582 user_entry = mach_memory_entry_allocate(object_handle);
583 user_entry->backing.copy = copy;
584 user_entry->internal = FALSE;
585 user_entry->is_sub_map = FALSE;
586 user_entry->is_copy = TRUE;
587 user_entry->offset = 0;
588 user_entry->protection = protections;
589 user_entry->size = map_size;
590 user_entry->data_offset = offset_in_page;
591
592 /* is all memory in this named entry "owned"? */
593 vm_map_entry_t entry;
594 user_entry->is_fully_owned = TRUE;
595 for (entry = vm_map_copy_first_entry(copy);
596 entry != vm_map_copy_to_entry(copy);
597 entry = entry->vme_next) {
598 if (entry->is_sub_map ||
599 VME_OBJECT(entry) == VM_OBJECT_NULL ||
600 VM_OBJECT_OWNER(VME_OBJECT(entry)) == TASK_NULL) {
601 /* this memory is not "owned" */
602 user_entry->is_fully_owned = FALSE;
603 break;
604 }
605 }
606
607 *size_u = vm_sanitize_wrap_size(user_entry->size - user_entry->data_offset);
608 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> "
609 "entry %p kr 0x%x\n", target_map, offset, VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
610 permission, user_entry, KERN_SUCCESS);
611 return KERN_SUCCESS;
612 }
613
614 static kern_return_t
mach_make_memory_entry_share(vm_map_t target_map,memory_object_size_ut * size_u,vm_map_offset_ut offset_u,vm_prot_t permission,__unused vm_named_entry_kernel_flags_t vmne_kflags,ipc_port_t * object_handle,ipc_port_t parent_handle,vm_named_entry_t parent_entry)615 mach_make_memory_entry_share(
616 vm_map_t target_map,
617 memory_object_size_ut *size_u,
618 vm_map_offset_ut offset_u,
619 vm_prot_t permission,
620 __unused vm_named_entry_kernel_flags_t vmne_kflags,
621 ipc_port_t *object_handle,
622 ipc_port_t parent_handle,
623 vm_named_entry_t parent_entry)
624 {
625 vm_object_t object;
626 unsigned int access;
627 vm_prot_t protections;
628 bool mask_protections;
629 bool use_data_addr;
630 bool use_4K_compat;
631 vm_named_entry_t user_entry = NULL;
632 vm_map_copy_t copy;
633 vm_prot_t cur_prot, max_prot;
634 vm_map_kernel_flags_t vmk_flags;
635 vm_map_entry_t parent_copy_entry;
636 /*
637 * Stash the offset in the page for use by vm_map_enter_mem_object()
638 * in the VM_FLAGS_RETURN_DATA_ADDR/MAP_MEM_USE_DATA_ADDR case.
639 */
640 vm_object_offset_t offset_in_page;
641 unsigned int wimg_mode;
642 kern_return_t kr;
643 vm_map_size_t map_size;
644 vm_map_offset_t map_start, map_end, offset;
645
646 if (VM_SANITIZE_UNSAFE_IS_ZERO(*size_u)) {
647 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
648 size_u, offset_u, permission, user_entry, object_handle);
649 }
650
651 #if CONFIG_PROB_GZALLOC
652 /*
653 * If offset is PGZ protected we need PGZ to fix it up to the right
654 * value prior to validation and use.
655 */
656 offset_u = vm_memory_entry_pgz_decode_offset(target_map, offset_u, size_u);
657 #endif /* CONFIG_PROB_GZALLOC */
658
659 /*
660 * Sanitize addr and size. Permimssions have been sanitized prior to
661 * dispatch
662 */
663 kr = mach_make_memory_entry_generic_sanitize(target_map,
664 *size_u,
665 offset_u,
666 &map_start,
667 &map_end,
668 &map_size,
669 &offset);
670 if (__improbable(kr != KERN_SUCCESS)) {
671 return mach_make_memory_entry_cleanup(kr, target_map,
672 size_u, offset_u, permission, user_entry, object_handle);
673 }
674
675 assert(map_size != 0);
676
677 vm_memory_entry_decode_perm(permission, &access, &protections,
678 &mask_protections, &use_data_addr, &use_4K_compat);
679
680 if (target_map == VM_MAP_NULL) {
681 return mach_make_memory_entry_cleanup(KERN_INVALID_TASK, target_map,
682 size_u, offset_u, permission, user_entry, object_handle);
683 }
684
685 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
686 vmk_flags.vmkf_range_id = KMEM_RANGE_ID_DATA;
687 parent_copy_entry = VM_MAP_ENTRY_NULL;
688 if (!(permission & MAP_MEM_VM_SHARE)) {
689 vm_map_t tmp_map, real_map;
690 vm_map_version_t version;
691 vm_object_t tmp_object;
692 vm_object_offset_t obj_off;
693 vm_prot_t prot;
694 boolean_t wired;
695 bool contended;
696
697 /* resolve any pending submap copy-on-write... */
698 if (protections & VM_PROT_WRITE) {
699 tmp_map = target_map;
700 vm_map_lock_read(tmp_map);
701 kr = vm_map_lookup_and_lock_object(&tmp_map,
702 map_start,
703 protections | (mask_protections ? VM_PROT_IS_MASK : 0),
704 OBJECT_LOCK_EXCLUSIVE,
705 &version,
706 &tmp_object,
707 &obj_off,
708 &prot,
709 &wired,
710 NULL, /* fault_info */
711 &real_map,
712 &contended);
713 if (kr != KERN_SUCCESS) {
714 vm_map_unlock_read(tmp_map);
715 } else {
716 vm_object_unlock(tmp_object);
717 vm_map_unlock_read(tmp_map);
718 if (real_map != tmp_map) {
719 vm_map_unlock_read(real_map);
720 }
721 }
722 }
723 /* ... and carry on */
724
725 /* stop extracting if VM object changes */
726 vmk_flags.vmkf_copy_single_object = TRUE;
727 if ((permission & MAP_MEM_NAMED_REUSE) &&
728 parent_entry != NULL &&
729 parent_entry->is_object) {
730 vm_map_copy_t parent_copy;
731 parent_copy = parent_entry->backing.copy;
732 /*
733 * Assert that the vm_map_copy is coming from the right
734 * zone and hasn't been forged
735 */
736 vm_map_copy_require(parent_copy);
737 assert(parent_copy->cpy_hdr.nentries == 1);
738 parent_copy_entry = vm_map_copy_first_entry(parent_copy);
739 assert(!parent_copy_entry->is_sub_map);
740 }
741 }
742
743 offset_in_page = vm_memory_entry_get_offset_in_page(offset, map_start,
744 use_data_addr, use_4K_compat);
745
746 if (mask_protections) {
747 /*
748 * caller is asking for whichever proctections are
749 * available: no required protections.
750 */
751 cur_prot = VM_PROT_NONE;
752 max_prot = VM_PROT_NONE;
753 vmk_flags.vmkf_remap_legacy_mode = true;
754 } else {
755 /*
756 * Caller wants a memory entry with "protections".
757 * Make sure we extract only memory that matches that.
758 */
759 cur_prot = protections;
760 max_prot = protections;
761 }
762 if (target_map->pmap == kernel_pmap) {
763 /*
764 * Get "reserved" map entries to avoid deadlocking
765 * on the kernel map or a kernel submap if we
766 * run out of VM map entries and need to refill that
767 * zone.
768 */
769 vmk_flags.vmkf_copy_pageable = FALSE;
770 } else {
771 vmk_flags.vmkf_copy_pageable = TRUE;
772 }
773 vmk_flags.vmkf_copy_same_map = FALSE;
774 assert(map_size != 0);
775 kr = vm_map_copy_extract(target_map,
776 map_start,
777 map_size,
778 FALSE, /* copy */
779 ©,
780 &cur_prot,
781 &max_prot,
782 VM_INHERIT_SHARE,
783 vmk_flags);
784 if (kr != KERN_SUCCESS) {
785 return mach_make_memory_entry_cleanup(kr, target_map,
786 size_u, offset_u, permission, user_entry, object_handle);
787 }
788 assert(copy != VM_MAP_COPY_NULL);
789
790 if (mask_protections) {
791 /*
792 * We just want as much of "original_protections"
793 * as we can get out of the actual "cur_prot".
794 */
795 protections &= cur_prot;
796 if (protections == VM_PROT_NONE) {
797 /* no access at all: fail */
798 vm_map_copy_discard(copy);
799 return mach_make_memory_entry_cleanup(KERN_PROTECTION_FAILURE,
800 target_map, size_u, offset_u, permission, user_entry,
801 object_handle);
802 }
803 } else {
804 /*
805 * We want exactly "original_protections"
806 * out of "cur_prot".
807 */
808 assert((cur_prot & protections) == protections);
809 assert((max_prot & protections) == protections);
810 /* XXX FBDP TODO: no longer needed? */
811 if ((cur_prot & protections) != protections) {
812 vm_map_copy_discard(copy);
813 return mach_make_memory_entry_cleanup(KERN_PROTECTION_FAILURE,
814 target_map, size_u, offset_u, permission, user_entry,
815 object_handle);
816 }
817 }
818
819 if (!(permission & MAP_MEM_VM_SHARE)) {
820 vm_map_entry_t copy_entry;
821
822 /* limit size to what's actually covered by "copy" */
823 assert(copy->cpy_hdr.nentries == 1);
824 copy_entry = vm_map_copy_first_entry(copy);
825 map_size = copy_entry->vme_end - copy_entry->vme_start;
826
827 if ((permission & MAP_MEM_NAMED_REUSE) &&
828 parent_copy_entry != VM_MAP_ENTRY_NULL &&
829 VME_OBJECT(copy_entry) == VME_OBJECT(parent_copy_entry) &&
830 VME_OFFSET(copy_entry) == VME_OFFSET(parent_copy_entry) &&
831 parent_entry->offset == 0 &&
832 parent_entry->size == map_size &&
833 (parent_entry->data_offset == offset_in_page)) {
834 /* we have a match: re-use "parent_entry" */
835
836 /* release our new "copy" */
837 vm_map_copy_discard(copy);
838 /* get extra send right on handle */
839 parent_handle = ipc_port_copy_send_any(parent_handle);
840
841 *size_u = vm_sanitize_wrap_size(parent_entry->size -
842 parent_entry->data_offset);
843 *object_handle = parent_handle;
844 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> "
845 "entry %p kr 0x%x\n", target_map, offset, VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
846 permission, user_entry, KERN_SUCCESS);
847 return KERN_SUCCESS;
848 }
849
850 /* no match: we need to create a new entry */
851 object = VME_OBJECT(copy_entry);
852 vm_object_lock(object);
853 wimg_mode = object->wimg_bits;
854 if (!(object->nophyscache)) {
855 vm_prot_to_wimg(access, &wimg_mode);
856 }
857 if (object->wimg_bits != wimg_mode) {
858 vm_object_change_wimg_mode(object, wimg_mode);
859 }
860 vm_object_unlock(object);
861 }
862
863 user_entry = mach_memory_entry_allocate(object_handle);
864 user_entry->backing.copy = copy;
865 user_entry->is_sub_map = FALSE;
866 user_entry->is_object = FALSE;
867 user_entry->internal = FALSE;
868 user_entry->protection = protections;
869 user_entry->size = map_size;
870 user_entry->data_offset = offset_in_page;
871
872 if (permission & MAP_MEM_VM_SHARE) {
873 vm_map_entry_t copy_entry;
874
875 user_entry->is_copy = TRUE;
876 user_entry->offset = 0;
877
878 /* is all memory in this named entry "owned"? */
879 user_entry->is_fully_owned = TRUE;
880 for (copy_entry = vm_map_copy_first_entry(copy);
881 copy_entry != vm_map_copy_to_entry(copy);
882 copy_entry = copy_entry->vme_next) {
883 if (copy_entry->is_sub_map) {
884 /* submaps can't be owned */
885 user_entry->is_fully_owned = FALSE;
886 break;
887 }
888 if (VM_OBJECT_OWNER(VME_OBJECT(copy_entry)) == TASK_NULL) {
889 object = VME_OBJECT(copy_entry);
890 if (object && !object->internal) {
891 /* external objects can be "owned" */
892 continue;
893 }
894 /* this memory is not "owned" */
895 user_entry->is_fully_owned = FALSE;
896 break;
897 }
898 }
899 } else {
900 user_entry->is_object = TRUE;
901 user_entry->internal = object->internal;
902 user_entry->offset = VME_OFFSET(vm_map_copy_first_entry(copy));
903 user_entry->access = GET_MAP_MEM(permission);
904 /* is all memory in this named entry "owned"? */
905 user_entry->is_fully_owned = FALSE;
906 object = vm_named_entry_to_vm_object(user_entry);
907 if (VM_OBJECT_OWNER(object) != TASK_NULL) {
908 /* object is owned */
909 user_entry->is_fully_owned = TRUE;
910 } else if (object && !object->internal) {
911 /* external objects can become "owned" */
912 user_entry->is_fully_owned = TRUE;
913 }
914 }
915
916 *size_u = vm_sanitize_wrap_size(user_entry->size -
917 user_entry->data_offset);
918 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry "
919 "%p kr 0x%x\n", target_map, offset, VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
920 permission, user_entry, KERN_SUCCESS);
921 return KERN_SUCCESS;
922 }
923
924 static __attribute__((always_inline, warn_unused_result))
925 kern_return_t
mach_make_memory_entry_from_parent_entry_sanitize(vm_map_t target_map,memory_object_size_ut size_u,vm_map_offset_ut offset_u,vm_prot_t permission,vm_named_entry_t parent_entry,vm_map_offset_t * map_start,vm_map_offset_t * map_end,vm_map_size_t * map_size,vm_map_offset_t * offset,vm_map_offset_t * user_entry_offset)926 mach_make_memory_entry_from_parent_entry_sanitize(
927 vm_map_t target_map,
928 memory_object_size_ut size_u,
929 vm_map_offset_ut offset_u,
930 vm_prot_t permission,
931 vm_named_entry_t parent_entry,
932 vm_map_offset_t *map_start,
933 vm_map_offset_t *map_end,
934 vm_map_size_t *map_size,
935 vm_map_offset_t *offset,
936 vm_map_offset_t *user_entry_offset)
937 {
938 bool mask_protections;
939 unsigned int access;
940 vm_prot_t protections;
941 bool use_data_addr;
942 bool use_4K_compat;
943 vm_map_offset_t start_mask = vm_map_page_mask(target_map);
944 kern_return_t kr;
945
946 vm_memory_entry_decode_perm(permission, &access, &protections,
947 &mask_protections, &use_data_addr, &use_4K_compat);
948
949 if (use_data_addr || use_4K_compat) {
950 /*
951 * Validate offset doesn't overflow when added to parent entry's offset
952 */
953 if (vm_sanitize_add_overflow(offset_u, parent_entry->data_offset,
954 &offset_u)) {
955 return KERN_INVALID_ARGUMENT;
956 }
957 start_mask = PAGE_MASK;
958 }
959
960 /*
961 * Currently the map_start is truncated using page mask from target_map
962 * when use_data_addr || use_4K_compat is false, while map_end uses
963 * PAGE_MASK. In order to maintain that behavior, we
964 * request for unaligned values and perform the truncing/rounding
965 * explicitly.
966 */
967 kr = vm_sanitize_addr_size(offset_u, size_u,
968 VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY, PAGE_MASK,
969 VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH | VM_SANITIZE_FLAGS_GET_UNALIGNED_VALUES,
970 map_start, map_end, map_size);
971 if (__improbable(kr != KERN_SUCCESS)) {
972 return kr;
973 }
974
975 *map_start = vm_map_trunc_page_mask(*map_start, start_mask);
976 *map_end = vm_map_round_page_mask(*map_end, PAGE_MASK);
977 *map_size = *map_end - *map_start;
978
979 /*
980 * Additional checks to make sure explicitly computed aligned start and end
981 * still make sense.
982 */
983 if (__improbable(*map_end < *map_start) || (*map_end > parent_entry->size)) {
984 return KERN_INVALID_ARGUMENT;
985 }
986
987 /*
988 * Validate offset
989 */
990 kr = vm_sanitize_offset(offset_u, VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY,
991 *map_start, *map_end, offset);
992 if (__improbable(kr != KERN_SUCCESS)) {
993 return kr;
994 }
995
996 if (__improbable(os_add_overflow(parent_entry->offset, *map_start,
997 user_entry_offset))) {
998 return KERN_INVALID_ARGUMENT;
999 }
1000
1001 return KERN_SUCCESS;
1002 }
1003
1004 static kern_return_t
mach_make_memory_entry_from_parent_entry(vm_map_t target_map,memory_object_size_ut * size_u,vm_map_offset_ut offset_u,vm_prot_t permission,ipc_port_t * object_handle,vm_named_entry_t parent_entry)1005 mach_make_memory_entry_from_parent_entry(
1006 vm_map_t target_map,
1007 memory_object_size_ut *size_u,
1008 vm_map_offset_ut offset_u,
1009 vm_prot_t permission,
1010 ipc_port_t *object_handle,
1011 vm_named_entry_t parent_entry)
1012 {
1013 vm_object_t object;
1014 unsigned int access;
1015 vm_prot_t protections;
1016 bool mask_protections;
1017 bool use_data_addr;
1018 bool use_4K_compat;
1019 vm_named_entry_t user_entry = NULL;
1020 kern_return_t kr;
1021 /*
1022 * Stash the offset in the page for use by vm_map_enter_mem_object()
1023 * in the VM_FLAGS_RETURN_DATA_ADDR/MAP_MEM_USE_DATA_ADDR case.
1024 */
1025 vm_object_offset_t offset_in_page;
1026 vm_map_offset_t map_start, map_end;
1027 vm_map_size_t map_size;
1028 vm_map_offset_t user_entry_offset, offset;
1029
1030 vm_memory_entry_decode_perm(permission, &access, &protections,
1031 &mask_protections, &use_data_addr, &use_4K_compat);
1032
1033 /*
1034 * Sanitize addr and size. Permimssions have been sanitized prior to
1035 * dispatch
1036 */
1037 kr = mach_make_memory_entry_from_parent_entry_sanitize(target_map,
1038 *size_u,
1039 offset_u,
1040 permission,
1041 parent_entry,
1042 &map_start,
1043 &map_end,
1044 &map_size,
1045 &offset,
1046 &user_entry_offset);
1047 if (__improbable(kr != KERN_SUCCESS)) {
1048 return mach_make_memory_entry_cleanup(kr, target_map,
1049 size_u, offset_u, permission, user_entry, object_handle);
1050 }
1051
1052 if (use_data_addr || use_4K_compat) {
1053 /*
1054 * submaps and pagers should only be accessible from within
1055 * the kernel, which shouldn't use the data address flag, so can fail here.
1056 */
1057 if (parent_entry->is_sub_map) {
1058 panic("Shouldn't be using data address with a parent entry that is a submap.");
1059 }
1060 }
1061
1062 if (mask_protections) {
1063 /*
1064 * The caller asked us to use the "protections" as
1065 * a mask, so restrict "protections" to what this
1066 * mapping actually allows.
1067 */
1068 protections &= parent_entry->protection;
1069 }
1070 if ((protections & parent_entry->protection) != protections) {
1071 return mach_make_memory_entry_cleanup(KERN_PROTECTION_FAILURE, target_map,
1072 size_u, offset_u, permission, user_entry, object_handle);
1073 }
1074
1075 offset_in_page = vm_memory_entry_get_offset_in_page(offset, map_start,
1076 use_data_addr, use_4K_compat);
1077
1078 user_entry = mach_memory_entry_allocate(object_handle);
1079 user_entry->size = map_size;
1080 user_entry->offset = user_entry_offset;
1081 user_entry->data_offset = offset_in_page;
1082 user_entry->is_sub_map = parent_entry->is_sub_map;
1083 user_entry->is_copy = parent_entry->is_copy;
1084 user_entry->protection = protections;
1085
1086 if (access != MAP_MEM_NOOP) {
1087 user_entry->access = access;
1088 }
1089
1090 if (parent_entry->is_sub_map) {
1091 vm_map_t map = parent_entry->backing.map;
1092 vm_map_reference(map);
1093 user_entry->backing.map = map;
1094 } else {
1095 object = vm_named_entry_to_vm_object(parent_entry);
1096 assert(object != VM_OBJECT_NULL);
1097 assert(object->copy_strategy != MEMORY_OBJECT_COPY_SYMMETRIC);
1098 vm_named_entry_associate_vm_object(
1099 user_entry,
1100 object,
1101 user_entry->offset,
1102 user_entry->size,
1103 (user_entry->protection & VM_PROT_ALL));
1104 assert(user_entry->is_object);
1105 /* we now point to this object, hold on */
1106 vm_object_lock(object);
1107 vm_object_reference_locked(object);
1108 #if VM_OBJECT_TRACKING_OP_TRUESHARE
1109 if (!object->true_share &&
1110 vm_object_tracking_btlog) {
1111 btlog_record(vm_object_tracking_btlog, object,
1112 VM_OBJECT_TRACKING_OP_TRUESHARE,
1113 btref_get(__builtin_frame_address(0), 0));
1114 }
1115 #endif /* VM_OBJECT_TRACKING_OP_TRUESHARE */
1116
1117 VM_OBJECT_SET_TRUE_SHARE(object, TRUE);
1118 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC) {
1119 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
1120 }
1121 vm_object_unlock(object);
1122 }
1123 *size_u = vm_sanitize_wrap_size(user_entry->size -
1124 user_entry->data_offset);
1125 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry "
1126 "%p kr 0x%x\n", target_map, offset, VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
1127 permission, user_entry, KERN_SUCCESS);
1128 return KERN_SUCCESS;
1129 }
1130
1131 static inline kern_return_t
mach_make_memory_entry_sanitize_perm(vm_prot_ut permission_u,vm_prot_t * permission)1132 mach_make_memory_entry_sanitize_perm(
1133 vm_prot_ut permission_u,
1134 vm_prot_t *permission)
1135 {
1136 return vm_sanitize_memory_entry_perm(permission_u,
1137 VM_SANITIZE_CALLER_MACH_MAKE_MEMORY_ENTRY,
1138 VM_SANITIZE_FLAGS_CHECK_USER_MEM_MAP_FLAGS,
1139 VM_PROT_IS_MASK, permission);
1140 }
1141
1142 kern_return_t
mach_make_memory_entry_internal(vm_map_t target_map,memory_object_size_ut * size_u,memory_object_offset_ut offset_u,vm_prot_ut permission_u,vm_named_entry_kernel_flags_t vmne_kflags,ipc_port_t * object_handle,ipc_port_t parent_handle)1143 mach_make_memory_entry_internal(
1144 vm_map_t target_map,
1145 memory_object_size_ut *size_u,
1146 memory_object_offset_ut offset_u,
1147 vm_prot_ut permission_u,
1148 vm_named_entry_kernel_flags_t vmne_kflags,
1149 ipc_port_t *object_handle,
1150 ipc_port_t parent_handle)
1151 {
1152 vm_named_entry_t user_entry __unused = NULL;
1153 vm_named_entry_t parent_entry;
1154 kern_return_t kr;
1155 vm_prot_t permission;
1156
1157 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x\n",
1158 target_map, VM_SANITIZE_UNSAFE_UNWRAP(offset_u), VM_SANITIZE_UNSAFE_UNWRAP(*size_u),
1159 VM_SANITIZE_UNSAFE_UNWRAP(permission_u));
1160
1161 /*
1162 * Validate permissions as we need to dispatch the corresponding flavor
1163 */
1164 kr = mach_make_memory_entry_sanitize_perm(permission_u, &permission);
1165 if (__improbable(kr != KERN_SUCCESS)) {
1166 return mach_make_memory_entry_cleanup(kr, target_map,
1167 size_u, offset_u, permission, user_entry, object_handle);
1168 }
1169
1170 if (permission & MAP_MEM_LEDGER_TAGGED) {
1171 vmne_kflags.vmnekf_ledger_tag = VM_LEDGER_TAG_DEFAULT;
1172 }
1173
1174 parent_entry = mach_memory_entry_from_port(parent_handle);
1175 if (parent_entry && parent_entry->is_copy) {
1176 return mach_make_memory_entry_cleanup(KERN_INVALID_ARGUMENT, target_map,
1177 size_u, offset_u, permission, user_entry, object_handle);
1178 }
1179
1180 if (permission & MAP_MEM_ONLY) {
1181 return mach_make_memory_entry_mem_only(target_map, size_u, offset_u,
1182 permission, object_handle, parent_entry);
1183 }
1184
1185 if (permission & MAP_MEM_NAMED_CREATE) {
1186 return mach_make_memory_entry_named_create(target_map, size_u, offset_u,
1187 permission, vmne_kflags, object_handle);
1188 }
1189
1190 if (permission & MAP_MEM_VM_COPY) {
1191 return mach_make_memory_entry_copy(target_map, size_u, offset_u,
1192 permission, vmne_kflags, object_handle);
1193 }
1194
1195 if ((permission & MAP_MEM_VM_SHARE)
1196 || parent_entry == NULL
1197 || (permission & MAP_MEM_NAMED_REUSE)) {
1198 return mach_make_memory_entry_share(target_map, size_u, offset_u,
1199 permission, vmne_kflags, object_handle, parent_handle,
1200 parent_entry);
1201 }
1202
1203 /*
1204 * This function will compute map start, end and size by including the
1205 * parent entry's offset. Therefore redo validation.
1206 */
1207 return mach_make_memory_entry_from_parent_entry(target_map, size_u,
1208 offset_u, permission, object_handle, parent_entry);
1209 }
1210
1211 kern_return_t
_mach_make_memory_entry(vm_map_t target_map,memory_object_size_ut * size_u,memory_object_offset_ut offset_u,vm_prot_ut permission_u,ipc_port_t * object_handle,ipc_port_t parent_entry)1212 _mach_make_memory_entry(
1213 vm_map_t target_map,
1214 memory_object_size_ut *size_u,
1215 memory_object_offset_ut offset_u,
1216 vm_prot_ut permission_u,
1217 ipc_port_t *object_handle,
1218 ipc_port_t parent_entry)
1219 {
1220 return mach_make_memory_entry_64(target_map, size_u,
1221 offset_u, permission_u, object_handle, parent_entry);
1222 }
1223
1224 kern_return_t
mach_make_memory_entry(vm_map_t target_map,vm_size_ut * size_u,vm_offset_ut offset_u,vm_prot_ut permission_u,ipc_port_t * object_handle,ipc_port_t parent_entry)1225 mach_make_memory_entry(
1226 vm_map_t target_map,
1227 vm_size_ut *size_u,
1228 vm_offset_ut offset_u,
1229 vm_prot_ut permission_u,
1230 ipc_port_t *object_handle,
1231 ipc_port_t parent_entry)
1232 {
1233 kern_return_t kr;
1234
1235 kr = mach_make_memory_entry_64(target_map, size_u,
1236 offset_u, permission_u, object_handle, parent_entry);
1237 return kr;
1238 }
1239
1240 __private_extern__ vm_named_entry_t
mach_memory_entry_allocate(ipc_port_t * user_handle_p)1241 mach_memory_entry_allocate(ipc_port_t *user_handle_p)
1242 {
1243 vm_named_entry_t user_entry;
1244
1245 user_entry = kalloc_type(struct vm_named_entry,
1246 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1247 named_entry_lock_init(user_entry);
1248
1249 *user_handle_p = ipc_kobject_alloc_port((ipc_kobject_t)user_entry,
1250 IKOT_NAMED_ENTRY,
1251 IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
1252
1253 #if VM_NAMED_ENTRY_DEBUG
1254 /* backtrace at allocation time, for debugging only */
1255 user_entry->named_entry_bt = btref_get(__builtin_frame_address(0), 0);
1256 #endif /* VM_NAMED_ENTRY_DEBUG */
1257 return user_entry;
1258 }
1259
1260 static __attribute__((always_inline, warn_unused_result))
1261 kern_return_t
mach_memory_object_memory_entry_64_sanitize(vm_object_size_ut size_u,vm_prot_ut permission_u,vm_object_size_t * size,vm_prot_t * permission)1262 mach_memory_object_memory_entry_64_sanitize(
1263 vm_object_size_ut size_u,
1264 vm_prot_ut permission_u,
1265 vm_object_size_t *size,
1266 vm_prot_t *permission)
1267 {
1268 kern_return_t kr;
1269
1270 kr = vm_sanitize_object_size(size_u,
1271 VM_SANITIZE_CALLER_MACH_MEMORY_OBJECT_MEMORY_ENTRY,
1272 VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS, size);
1273 if (__improbable(kr != KERN_SUCCESS)) {
1274 return kr;
1275 }
1276 kr = vm_sanitize_memory_entry_perm(permission_u,
1277 VM_SANITIZE_CALLER_MACH_MEMORY_OBJECT_MEMORY_ENTRY,
1278 VM_SANITIZE_FLAGS_NONE, VM_PROT_NONE,
1279 permission);
1280 if (__improbable(kr != KERN_SUCCESS)) {
1281 return kr;
1282 }
1283
1284 return KERN_SUCCESS;
1285 }
1286
1287 /*
1288 * mach_memory_object_memory_entry_64
1289 *
1290 * Create a named entry backed by the provided pager.
1291 *
1292 */
1293 kern_return_t
mach_memory_object_memory_entry_64(host_t host,boolean_t internal,vm_object_size_ut size_u,vm_prot_ut permission_u,memory_object_t pager,ipc_port_t * entry_handle)1294 mach_memory_object_memory_entry_64(
1295 host_t host,
1296 boolean_t internal,
1297 vm_object_size_ut size_u,
1298 vm_prot_ut permission_u,
1299 memory_object_t pager,
1300 ipc_port_t *entry_handle)
1301 {
1302 vm_named_entry_t user_entry;
1303 ipc_port_t user_handle;
1304 vm_object_t object;
1305 vm_object_size_t size;
1306 vm_prot_t permission;
1307 kern_return_t kr;
1308
1309 if (host == HOST_NULL) {
1310 return KERN_INVALID_HOST;
1311 }
1312
1313 /*
1314 * Validate size and permission
1315 */
1316 kr = mach_memory_object_memory_entry_64_sanitize(size_u,
1317 permission_u,
1318 &size,
1319 &permission);
1320 if (__improbable(kr != KERN_SUCCESS)) {
1321 return vm_sanitize_get_kr(kr);
1322 }
1323
1324 if (pager == MEMORY_OBJECT_NULL && internal) {
1325 object = vm_object_allocate(size, VM_MAP_SERIAL_NONE);
1326 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC) {
1327 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
1328 }
1329 } else {
1330 object = memory_object_to_vm_object(pager);
1331 if (object != VM_OBJECT_NULL) {
1332 vm_object_reference(object);
1333 }
1334 }
1335 if (object == VM_OBJECT_NULL) {
1336 return KERN_INVALID_ARGUMENT;
1337 }
1338
1339 user_entry = mach_memory_entry_allocate(&user_handle);
1340 user_entry->size = size;
1341 user_entry->offset = 0;
1342 user_entry->protection = permission & VM_PROT_ALL;
1343 user_entry->access = GET_MAP_MEM(permission);
1344 user_entry->is_sub_map = FALSE;
1345
1346 vm_named_entry_associate_vm_object(user_entry, object, 0, size,
1347 (user_entry->protection & VM_PROT_ALL));
1348 user_entry->internal = object->internal;
1349 assert(object->internal == internal);
1350 if (VM_OBJECT_OWNER(object) != TASK_NULL) {
1351 /* all memory in this entry is "owned" */
1352 user_entry->is_fully_owned = TRUE;
1353 } else if (object && !object->internal) {
1354 /* external objects can become "owned" */
1355 user_entry->is_fully_owned = TRUE;
1356 }
1357
1358 *entry_handle = user_handle;
1359 return KERN_SUCCESS;
1360 }
1361
1362 kern_return_t
mach_memory_object_memory_entry(host_t host,boolean_t internal,vm_size_ut size_u,vm_prot_ut permission_u,memory_object_t pager,ipc_port_t * entry_handle)1363 mach_memory_object_memory_entry(
1364 host_t host,
1365 boolean_t internal,
1366 vm_size_ut size_u,
1367 vm_prot_ut permission_u,
1368 memory_object_t pager,
1369 ipc_port_t *entry_handle)
1370 {
1371 return mach_memory_object_memory_entry_64( host, internal,
1372 size_u, permission_u, pager, entry_handle);
1373 }
1374
1375 kern_return_t
mach_memory_entry_purgable_control(ipc_port_t entry_port,vm_purgable_t control,int * state)1376 mach_memory_entry_purgable_control(
1377 ipc_port_t entry_port,
1378 vm_purgable_t control,
1379 int *state)
1380 {
1381 if (control == VM_PURGABLE_SET_STATE_FROM_KERNEL) {
1382 /* not allowed from user-space */
1383 return KERN_INVALID_ARGUMENT;
1384 }
1385
1386 return memory_entry_purgeable_control_internal(entry_port, control, state);
1387 }
1388
1389 kern_return_t
memory_entry_purgeable_control_internal(ipc_port_t entry_port,vm_purgable_t control,int * state)1390 memory_entry_purgeable_control_internal(
1391 ipc_port_t entry_port,
1392 vm_purgable_t control,
1393 int *state)
1394 {
1395 kern_return_t kr;
1396 vm_named_entry_t mem_entry;
1397 vm_object_t object;
1398
1399 mem_entry = mach_memory_entry_from_port(entry_port);
1400 if (mem_entry == NULL) {
1401 return KERN_INVALID_ARGUMENT;
1402 }
1403
1404 if (control != VM_PURGABLE_SET_STATE &&
1405 control != VM_PURGABLE_GET_STATE &&
1406 control != VM_PURGABLE_SET_STATE_FROM_KERNEL) {
1407 return KERN_INVALID_ARGUMENT;
1408 }
1409
1410 if ((control == VM_PURGABLE_SET_STATE ||
1411 control == VM_PURGABLE_SET_STATE_FROM_KERNEL) &&
1412 (((*state & ~(VM_PURGABLE_ALL_MASKS)) != 0) ||
1413 ((*state & VM_PURGABLE_STATE_MASK) > VM_PURGABLE_STATE_MASK))) {
1414 return KERN_INVALID_ARGUMENT;
1415 }
1416
1417 named_entry_lock(mem_entry);
1418
1419 if (mem_entry->is_sub_map ||
1420 mem_entry->is_copy) {
1421 named_entry_unlock(mem_entry);
1422 return KERN_INVALID_ARGUMENT;
1423 }
1424
1425 assert(mem_entry->is_object);
1426 object = vm_named_entry_to_vm_object(mem_entry);
1427 if (object == VM_OBJECT_NULL) {
1428 named_entry_unlock(mem_entry);
1429 return KERN_INVALID_ARGUMENT;
1430 }
1431
1432 vm_object_lock(object);
1433
1434 /* check that named entry covers entire object ? */
1435 if (mem_entry->offset != 0 || object->vo_size != mem_entry->size) {
1436 vm_object_unlock(object);
1437 named_entry_unlock(mem_entry);
1438 return KERN_INVALID_ARGUMENT;
1439 }
1440
1441 named_entry_unlock(mem_entry);
1442
1443 kr = vm_object_purgable_control(object, control, state);
1444
1445 vm_object_unlock(object);
1446
1447 return kr;
1448 }
1449
1450 static kern_return_t
memory_entry_access_tracking_internal(ipc_port_t entry_port,int * access_tracking,uint32_t * access_tracking_reads,uint32_t * access_tracking_writes)1451 memory_entry_access_tracking_internal(
1452 ipc_port_t entry_port,
1453 int *access_tracking,
1454 uint32_t *access_tracking_reads,
1455 uint32_t *access_tracking_writes)
1456 {
1457 vm_named_entry_t mem_entry;
1458 vm_object_t object;
1459 kern_return_t kr;
1460
1461 mem_entry = mach_memory_entry_from_port(entry_port);
1462 if (mem_entry == NULL) {
1463 return KERN_INVALID_ARGUMENT;
1464 }
1465
1466 named_entry_lock(mem_entry);
1467
1468 if (mem_entry->is_sub_map ||
1469 mem_entry->is_copy) {
1470 named_entry_unlock(mem_entry);
1471 return KERN_INVALID_ARGUMENT;
1472 }
1473
1474 assert(mem_entry->is_object);
1475 object = vm_named_entry_to_vm_object(mem_entry);
1476 if (object == VM_OBJECT_NULL) {
1477 named_entry_unlock(mem_entry);
1478 return KERN_INVALID_ARGUMENT;
1479 }
1480
1481 #if VM_OBJECT_ACCESS_TRACKING
1482 vm_object_access_tracking(object,
1483 access_tracking,
1484 access_tracking_reads,
1485 access_tracking_writes);
1486 kr = KERN_SUCCESS;
1487 #else /* VM_OBJECT_ACCESS_TRACKING */
1488 (void) access_tracking;
1489 (void) access_tracking_reads;
1490 (void) access_tracking_writes;
1491 kr = KERN_NOT_SUPPORTED;
1492 #endif /* VM_OBJECT_ACCESS_TRACKING */
1493
1494 named_entry_unlock(mem_entry);
1495
1496 return kr;
1497 }
1498
1499 kern_return_t
mach_memory_entry_access_tracking(ipc_port_t entry_port,int * access_tracking,uint32_t * access_tracking_reads,uint32_t * access_tracking_writes)1500 mach_memory_entry_access_tracking(
1501 ipc_port_t entry_port,
1502 int *access_tracking,
1503 uint32_t *access_tracking_reads,
1504 uint32_t *access_tracking_writes)
1505 {
1506 return memory_entry_access_tracking_internal(entry_port,
1507 access_tracking,
1508 access_tracking_reads,
1509 access_tracking_writes);
1510 }
1511
1512 #if DEVELOPMENT || DEBUG
1513 /* For dtrace probe in mach_memory_entry_ownership */
1514 extern int proc_selfpid(void);
1515 extern char *proc_name_address(void *p);
1516 #endif /* DEVELOPMENT || DEBUG */
1517
1518 /* Kernel call only, MIG uses *_from_user() below */
1519 kern_return_t
mach_memory_entry_ownership(ipc_port_t entry_port,task_t owner,int ledger_tag,int ledger_flags)1520 mach_memory_entry_ownership(
1521 ipc_port_t entry_port,
1522 task_t owner,
1523 int ledger_tag,
1524 int ledger_flags)
1525 {
1526 task_t cur_task;
1527 kern_return_t kr;
1528 vm_named_entry_t mem_entry;
1529 vm_object_t object;
1530
1531 if (ledger_flags & ~VM_LEDGER_FLAGS_ALL) {
1532 /* reject unexpected flags */
1533 return KERN_INVALID_ARGUMENT;
1534 }
1535
1536 cur_task = current_task();
1537 if (cur_task == kernel_task) {
1538 /* kernel thread: no entitlement needed */
1539 } else if (ledger_flags & VM_LEDGER_FLAG_FROM_KERNEL) {
1540 /* call is from trusted kernel code: no entitlement needed */
1541 } else if ((owner != cur_task && owner != TASK_NULL) ||
1542 (ledger_flags & VM_LEDGER_FLAG_NO_FOOTPRINT) ||
1543 (ledger_flags & VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG) ||
1544 ledger_tag == VM_LEDGER_TAG_NETWORK) {
1545 bool transfer_ok = false;
1546
1547 /*
1548 * An entitlement is required to:
1549 * + tranfer memory ownership to someone else,
1550 * + request that the memory not count against the footprint,
1551 * + tag as "network" (since that implies "no footprint")
1552 *
1553 * Exception: task with task_no_footprint_for_debug == 1 on internal build
1554 */
1555 if (!cur_task->task_can_transfer_memory_ownership &&
1556 IOCurrentTaskHasEntitlement("com.apple.private.memory.ownership_transfer")) {
1557 cur_task->task_can_transfer_memory_ownership = TRUE;
1558 }
1559 if (cur_task->task_can_transfer_memory_ownership) {
1560 /* we're allowed to transfer ownership to any task */
1561 transfer_ok = true;
1562 }
1563 #if DEVELOPMENT || DEBUG
1564 if (!transfer_ok &&
1565 ledger_tag == VM_LEDGER_TAG_DEFAULT &&
1566 (ledger_flags & VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG) &&
1567 cur_task->task_no_footprint_for_debug) {
1568 int to_panic = 0;
1569 static bool init_bootarg = false;
1570
1571 /*
1572 * Allow performance tools running on internal builds to hide memory usage from phys_footprint even
1573 * WITHOUT an entitlement. This can be enabled by per task sysctl vm.task_no_footprint_for_debug=1
1574 * with the ledger tag VM_LEDGER_TAG_DEFAULT and flag VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG.
1575 *
1576 * If the boot-arg "panic_on_no_footprint_for_debug" is set, the kernel will
1577 * panic here in order to detect any abuse of this feature, which is intended solely for
1578 * memory debugging purpose.
1579 */
1580 if (!init_bootarg) {
1581 PE_parse_boot_argn("panic_on_no_footprint_for_debug", &to_panic, sizeof(to_panic));
1582 init_bootarg = true;
1583 }
1584 if (to_panic) {
1585 panic("%s: panic_on_no_footprint_for_debug is triggered by pid %d procname %s", __func__, proc_selfpid(), get_bsdtask_info(cur_task)? proc_name_address(get_bsdtask_info(cur_task)) : "?");
1586 }
1587
1588 /*
1589 * Flushing out user space processes using this interface:
1590 * $ dtrace -n 'task_no_footprint_for_debug {printf("%d[%s]\n", pid, execname); stack(); ustack();}'
1591 */
1592 DTRACE_VM(task_no_footprint_for_debug);
1593 transfer_ok = true;
1594 }
1595 #endif /* DEVELOPMENT || DEBUG */
1596 if (!transfer_ok) {
1597 #define TRANSFER_ENTITLEMENT_MAX_LENGTH 1024 /* XXX ? */
1598 const char *our_id, *their_id;
1599 our_id = IOTaskGetEntitlement(current_task(), "com.apple.developer.memory.transfer-send");
1600 their_id = IOTaskGetEntitlement(owner, "com.apple.developer.memory.transfer-accept");
1601 if (our_id && their_id &&
1602 !strncmp(our_id, their_id, TRANSFER_ENTITLEMENT_MAX_LENGTH)) {
1603 /* allow transfer between tasks that have matching entitlements */
1604 if (strnlen(our_id, TRANSFER_ENTITLEMENT_MAX_LENGTH) < TRANSFER_ENTITLEMENT_MAX_LENGTH &&
1605 strnlen(their_id, TRANSFER_ENTITLEMENT_MAX_LENGTH) < TRANSFER_ENTITLEMENT_MAX_LENGTH) {
1606 transfer_ok = true;
1607 } else {
1608 /* complain about entitlement(s) being too long... */
1609 assertf((strlen(our_id) <= TRANSFER_ENTITLEMENT_MAX_LENGTH &&
1610 strlen(their_id) <= TRANSFER_ENTITLEMENT_MAX_LENGTH),
1611 "our_id:%lu their_id:%lu",
1612 strlen(our_id), strlen(their_id));
1613 }
1614 }
1615 }
1616 if (!transfer_ok) {
1617 /* transfer denied */
1618 return KERN_NO_ACCESS;
1619 }
1620
1621 if (ledger_flags & VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG) {
1622 /*
1623 * We've made it past the checks above, so we either
1624 * have the entitlement or the sysctl.
1625 * Convert to VM_LEDGER_FLAG_NO_FOOTPRINT.
1626 */
1627 ledger_flags &= ~VM_LEDGER_FLAG_NO_FOOTPRINT_FOR_DEBUG;
1628 ledger_flags |= VM_LEDGER_FLAG_NO_FOOTPRINT;
1629 }
1630 }
1631
1632 if (ledger_tag == VM_LEDGER_TAG_UNCHANGED) {
1633 /* leave "ledger_tag" unchanged */
1634 } else if (ledger_tag < 0 ||
1635 ledger_tag > VM_LEDGER_TAG_MAX) {
1636 return KERN_INVALID_ARGUMENT;
1637 }
1638 if (owner == TASK_NULL) {
1639 /* leave "owner" unchanged */
1640 owner = VM_OBJECT_OWNER_UNCHANGED;
1641 }
1642
1643 mem_entry = mach_memory_entry_from_port(entry_port);
1644 if (mem_entry == NULL) {
1645 return KERN_INVALID_ARGUMENT;
1646 }
1647
1648 named_entry_lock(mem_entry);
1649
1650 if (mem_entry->is_sub_map ||
1651 !mem_entry->is_fully_owned) {
1652 named_entry_unlock(mem_entry);
1653 return KERN_INVALID_ARGUMENT;
1654 }
1655
1656 if (mem_entry->is_object) {
1657 object = vm_named_entry_to_vm_object(mem_entry);
1658 if (object == VM_OBJECT_NULL) {
1659 named_entry_unlock(mem_entry);
1660 return KERN_INVALID_ARGUMENT;
1661 }
1662 vm_object_lock(object);
1663 if (object->internal) {
1664 /* check that named entry covers entire object ? */
1665 if (mem_entry->offset != 0 ||
1666 object->vo_size != mem_entry->size) {
1667 vm_object_unlock(object);
1668 named_entry_unlock(mem_entry);
1669 return KERN_INVALID_ARGUMENT;
1670 }
1671 }
1672 named_entry_unlock(mem_entry);
1673 kr = vm_object_ownership_change(object,
1674 ledger_tag,
1675 owner,
1676 ledger_flags,
1677 FALSE); /* task_objq_locked */
1678 vm_object_unlock(object);
1679 } else if (mem_entry->is_copy) {
1680 vm_map_copy_t copy;
1681 vm_map_entry_t entry;
1682
1683 copy = mem_entry->backing.copy;
1684 named_entry_unlock(mem_entry);
1685 for (entry = vm_map_copy_first_entry(copy);
1686 entry != vm_map_copy_to_entry(copy);
1687 entry = entry->vme_next) {
1688 object = VME_OBJECT(entry);
1689 if (entry->is_sub_map ||
1690 object == VM_OBJECT_NULL) {
1691 kr = KERN_INVALID_ARGUMENT;
1692 break;
1693 }
1694 vm_object_lock(object);
1695 if (object->internal) {
1696 if (VME_OFFSET(entry) != 0 ||
1697 entry->vme_end - entry->vme_start != object->vo_size) {
1698 vm_object_unlock(object);
1699 kr = KERN_INVALID_ARGUMENT;
1700 break;
1701 }
1702 }
1703 kr = vm_object_ownership_change(object,
1704 ledger_tag,
1705 owner,
1706 ledger_flags,
1707 FALSE); /* task_objq_locked */
1708 vm_object_unlock(object);
1709 if (kr != KERN_SUCCESS) {
1710 kr = KERN_INVALID_ARGUMENT;
1711 break;
1712 }
1713 }
1714 } else {
1715 named_entry_unlock(mem_entry);
1716 return KERN_INVALID_ARGUMENT;
1717 }
1718
1719 return kr;
1720 }
1721
1722 /* MIG call from userspace */
1723 kern_return_t
mach_memory_entry_ownership_from_user(ipc_port_t entry_port,mach_port_t owner_port,int ledger_tag,int ledger_flags)1724 mach_memory_entry_ownership_from_user(
1725 ipc_port_t entry_port,
1726 mach_port_t owner_port,
1727 int ledger_tag,
1728 int ledger_flags)
1729 {
1730 task_t owner = TASK_NULL;
1731 kern_return_t kr;
1732
1733 if (ledger_flags & ~VM_LEDGER_FLAGS_USER) {
1734 return KERN_INVALID_ARGUMENT;
1735 }
1736
1737 if (IP_VALID(owner_port)) {
1738 if (ip_kotype(owner_port) == IKOT_TASK_ID_TOKEN) {
1739 task_id_token_t token = convert_port_to_task_id_token(owner_port);
1740 (void)task_identity_token_get_task_grp(token, &owner, TASK_GRP_MIG);
1741 task_id_token_release(token);
1742 /* token ref released */
1743 } else {
1744 owner = convert_port_to_task_mig(owner_port);
1745 }
1746 }
1747 /* hold task ref on owner (Nullable) */
1748
1749 if (owner && task_is_a_corpse(owner)) {
1750 /* identity token can represent a corpse, disallow it */
1751 task_deallocate_mig(owner);
1752 owner = TASK_NULL;
1753 }
1754
1755 /* mach_memory_entry_ownership() will handle TASK_NULL owner */
1756 kr = mach_memory_entry_ownership(entry_port, owner, /* Nullable */
1757 ledger_tag, ledger_flags);
1758
1759 if (owner) {
1760 task_deallocate_mig(owner);
1761 }
1762
1763 if (kr == KERN_SUCCESS) {
1764 /* MIG rule, consume port right on success */
1765 ipc_port_release_send(owner_port);
1766 }
1767 return kr;
1768 }
1769
1770 kern_return_t
mach_memory_entry_get_page_counts(ipc_port_t entry_port,unsigned int * resident_page_count,unsigned int * dirty_page_count)1771 mach_memory_entry_get_page_counts(
1772 ipc_port_t entry_port,
1773 unsigned int *resident_page_count,
1774 unsigned int *dirty_page_count)
1775 {
1776 kern_return_t kr;
1777 vm_named_entry_t mem_entry;
1778 vm_object_t object;
1779 vm_object_offset_t offset;
1780 vm_object_size_t size;
1781
1782 mem_entry = mach_memory_entry_from_port(entry_port);
1783 if (mem_entry == NULL) {
1784 return KERN_INVALID_ARGUMENT;
1785 }
1786
1787 named_entry_lock(mem_entry);
1788
1789 if (mem_entry->is_sub_map ||
1790 mem_entry->is_copy) {
1791 named_entry_unlock(mem_entry);
1792 return KERN_INVALID_ARGUMENT;
1793 }
1794
1795 assert(mem_entry->is_object);
1796 object = vm_named_entry_to_vm_object(mem_entry);
1797 if (object == VM_OBJECT_NULL) {
1798 named_entry_unlock(mem_entry);
1799 return KERN_INVALID_ARGUMENT;
1800 }
1801
1802 vm_object_lock(object);
1803
1804 offset = mem_entry->offset;
1805 size = mem_entry->size;
1806 size = vm_object_round_page(offset + size) - vm_object_trunc_page(offset);
1807 offset = vm_object_trunc_page(offset);
1808
1809 named_entry_unlock(mem_entry);
1810
1811 kr = vm_object_get_page_counts(object, offset, size, resident_page_count, dirty_page_count);
1812
1813 vm_object_unlock(object);
1814
1815 return kr;
1816 }
1817
1818 kern_return_t
mach_memory_entry_phys_page_offset(ipc_port_t entry_port,vm_object_offset_t * offset_p)1819 mach_memory_entry_phys_page_offset(
1820 ipc_port_t entry_port,
1821 vm_object_offset_t *offset_p)
1822 {
1823 vm_named_entry_t mem_entry;
1824 vm_object_t object;
1825 vm_object_offset_t offset;
1826 vm_object_offset_t data_offset;
1827
1828 mem_entry = mach_memory_entry_from_port(entry_port);
1829 if (mem_entry == NULL) {
1830 return KERN_INVALID_ARGUMENT;
1831 }
1832
1833 named_entry_lock(mem_entry);
1834
1835 if (mem_entry->is_sub_map ||
1836 mem_entry->is_copy) {
1837 named_entry_unlock(mem_entry);
1838 return KERN_INVALID_ARGUMENT;
1839 }
1840
1841 assert(mem_entry->is_object);
1842 object = vm_named_entry_to_vm_object(mem_entry);
1843 if (object == VM_OBJECT_NULL) {
1844 named_entry_unlock(mem_entry);
1845 return KERN_INVALID_ARGUMENT;
1846 }
1847
1848 offset = mem_entry->offset;
1849 data_offset = mem_entry->data_offset;
1850
1851 named_entry_unlock(mem_entry);
1852
1853 *offset_p = offset - vm_object_trunc_page(offset) + data_offset;
1854 return KERN_SUCCESS;
1855 }
1856
1857 static inline kern_return_t
mach_memory_entry_map_size_sanitize_locked(vm_map_t map,memory_object_offset_ut * offset_u,memory_object_size_ut size_u,vm_named_entry_t mem_entry,memory_object_offset_t * offset,memory_object_offset_t * end,mach_vm_size_t * map_size)1858 mach_memory_entry_map_size_sanitize_locked(
1859 vm_map_t map,
1860 memory_object_offset_ut *offset_u,
1861 memory_object_size_ut size_u,
1862 vm_named_entry_t mem_entry,
1863 memory_object_offset_t *offset,
1864 memory_object_offset_t *end,
1865 mach_vm_size_t *map_size)
1866 {
1867 kern_return_t kr;
1868
1869 if (mem_entry->is_object ||
1870 (mem_entry->is_copy &&
1871 (VM_MAP_COPY_PAGE_MASK(mem_entry->backing.copy) ==
1872 VM_MAP_PAGE_MASK(map)))) {
1873 if (__improbable(vm_sanitize_add_overflow(*offset_u, mem_entry->offset,
1874 offset_u))) {
1875 return KERN_INVALID_ARGUMENT;
1876 }
1877 }
1878
1879 if (__improbable(vm_sanitize_add_overflow(*offset_u, mem_entry->data_offset,
1880 offset_u))) {
1881 return KERN_INVALID_ARGUMENT;
1882 }
1883
1884 kr = vm_sanitize_addr_size(*offset_u, size_u,
1885 VM_SANITIZE_CALLER_MACH_MEMORY_ENTRY_MAP_SIZE, map,
1886 VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH, offset, end, map_size);
1887 if (__improbable(kr != KERN_SUCCESS)) {
1888 return vm_sanitize_get_kr(kr);
1889 }
1890
1891 return KERN_SUCCESS;
1892 }
1893
1894 kern_return_t
mach_memory_entry_map_size(ipc_port_t entry_port,vm_map_t map,memory_object_offset_ut offset_u,memory_object_size_ut size_u,mach_vm_size_t * map_size_out)1895 mach_memory_entry_map_size(
1896 ipc_port_t entry_port,
1897 vm_map_t map,
1898 memory_object_offset_ut offset_u,
1899 memory_object_size_ut size_u,
1900 mach_vm_size_t *map_size_out)
1901 {
1902 vm_named_entry_t mem_entry;
1903 vm_object_t object;
1904 vm_map_copy_t copy_map, target_copy_map;
1905 vm_map_offset_t overmap_start, overmap_end, trimmed_start;
1906 kern_return_t kr;
1907 memory_object_offset_t offset;
1908 memory_object_offset_t end;
1909 mach_vm_size_t map_size;
1910
1911 *map_size_out = 0;
1912
1913 mem_entry = mach_memory_entry_from_port(entry_port);
1914 if (mem_entry == NULL) {
1915 return KERN_INVALID_ARGUMENT;
1916 }
1917
1918 named_entry_lock(mem_entry);
1919
1920 if (mem_entry->is_sub_map) {
1921 named_entry_unlock(mem_entry);
1922 return KERN_INVALID_ARGUMENT;
1923 }
1924
1925 /*
1926 * Sanitize offset and size before use
1927 */
1928 kr = mach_memory_entry_map_size_sanitize_locked(map,
1929 &offset_u,
1930 size_u,
1931 mem_entry,
1932 &offset,
1933 &end,
1934 &map_size);
1935 if (__improbable(kr != KERN_SUCCESS)) {
1936 named_entry_unlock(mem_entry);
1937 return kr;
1938 }
1939
1940 if (mem_entry->is_object) {
1941 object = vm_named_entry_to_vm_object(mem_entry);
1942 if (object == VM_OBJECT_NULL) {
1943 named_entry_unlock(mem_entry);
1944 return KERN_INVALID_ARGUMENT;
1945 }
1946
1947 named_entry_unlock(mem_entry);
1948 *map_size_out = map_size;
1949 return KERN_SUCCESS;
1950 }
1951
1952 if (!mem_entry->is_copy) {
1953 panic("unsupported type of mem_entry %p", mem_entry);
1954 }
1955
1956 assert(mem_entry->is_copy);
1957 if (VM_MAP_COPY_PAGE_MASK(mem_entry->backing.copy) == VM_MAP_PAGE_MASK(map)) {
1958 DEBUG4K_SHARE("map %p (%d) mem_entry %p offset 0x%llx + 0x%llx + 0x%llx size 0x%llx -> map_size 0x%llx\n", map, VM_MAP_PAGE_MASK(map), mem_entry, mem_entry->offset, mem_entry->data_offset, offset, VM_SANITIZE_UNSAFE_UNWRAP(size_u), map_size);
1959 named_entry_unlock(mem_entry);
1960 *map_size_out = map_size;
1961 return KERN_SUCCESS;
1962 }
1963
1964 DEBUG4K_SHARE("mem_entry %p copy %p (%d) map %p (%d) offset 0x%llx size 0x%llx\n", mem_entry, mem_entry->backing.copy, VM_MAP_COPY_PAGE_SHIFT(mem_entry->backing.copy), map, VM_MAP_PAGE_SHIFT(map), offset, VM_SANITIZE_UNSAFE_UNWRAP(size_u));
1965 copy_map = mem_entry->backing.copy;
1966 target_copy_map = VM_MAP_COPY_NULL;
1967 DEBUG4K_ADJUST("adjusting...\n");
1968 kr = vm_map_copy_adjust_to_target(copy_map,
1969 offset_u,
1970 size_u,
1971 map,
1972 FALSE,
1973 &target_copy_map,
1974 &overmap_start,
1975 &overmap_end,
1976 &trimmed_start);
1977 if (kr == KERN_SUCCESS) {
1978 if (target_copy_map->size != copy_map->size) {
1979 DEBUG4K_ADJUST("copy %p (%d) map %p (%d) offset 0x%llx size 0x%llx overmap_start 0x%llx overmap_end 0x%llx trimmed_start 0x%llx map_size 0x%llx -> 0x%llx\n", copy_map, VM_MAP_COPY_PAGE_SHIFT(copy_map), map, VM_MAP_PAGE_SHIFT(map), (uint64_t)offset, (uint64_t)VM_SANITIZE_UNSAFE_UNWRAP(size_u), (uint64_t)overmap_start, (uint64_t)overmap_end, (uint64_t)trimmed_start, (uint64_t)copy_map->size, (uint64_t)target_copy_map->size);
1980 }
1981 *map_size_out = target_copy_map->size;
1982 if (target_copy_map != copy_map) {
1983 vm_map_copy_discard(target_copy_map);
1984 }
1985 target_copy_map = VM_MAP_COPY_NULL;
1986 }
1987 named_entry_unlock(mem_entry);
1988 return kr;
1989 }
1990
1991 /*
1992 * mach_memory_entry_port_release:
1993 *
1994 * Release a send right on a named entry port. This is the correct
1995 * way to destroy a named entry. When the last right on the port is
1996 * released, mach_memory_entry_no_senders() willl be called.
1997 */
1998 void
mach_memory_entry_port_release(ipc_port_t port)1999 mach_memory_entry_port_release(
2000 ipc_port_t port)
2001 {
2002 assert(ip_kotype(port) == IKOT_NAMED_ENTRY);
2003 ipc_port_release_send(port);
2004 }
2005
2006 vm_named_entry_t
mach_memory_entry_from_port(ipc_port_t port)2007 mach_memory_entry_from_port(ipc_port_t port)
2008 {
2009 if (IP_VALID(port)) {
2010 return ipc_kobject_get_stable(port, IKOT_NAMED_ENTRY);
2011 }
2012 return NULL;
2013 }
2014
2015 /*
2016 * mach_memory_entry_no_senders:
2017 *
2018 * Destroys the memory entry associated with a mach port.
2019 * Memory entries have the exact same lifetime as their owning port.
2020 *
2021 * Releasing a memory entry is done by calling
2022 * mach_memory_entry_port_release() on its owning port.
2023 */
2024 static void
mach_memory_entry_no_senders(ipc_port_t port,mach_port_mscount_t mscount)2025 mach_memory_entry_no_senders(ipc_port_t port, mach_port_mscount_t mscount)
2026 {
2027 vm_named_entry_t named_entry;
2028
2029 named_entry = ipc_kobject_dealloc_port(port, mscount, IKOT_NAMED_ENTRY);
2030
2031 if (named_entry->is_sub_map) {
2032 vm_map_deallocate(named_entry->backing.map);
2033 } else if (named_entry->is_copy) {
2034 vm_map_copy_discard(named_entry->backing.copy);
2035 } else if (named_entry->is_object) {
2036 assert(named_entry->backing.copy->cpy_hdr.nentries == 1);
2037 vm_map_copy_discard(named_entry->backing.copy);
2038 } else {
2039 assert(named_entry->backing.copy == VM_MAP_COPY_NULL);
2040 }
2041
2042 #if VM_NAMED_ENTRY_DEBUG
2043 btref_put(named_entry->named_entry_bt);
2044 #endif /* VM_NAMED_ENTRY_DEBUG */
2045
2046 named_entry_lock_destroy(named_entry);
2047 kfree_type(struct vm_named_entry, named_entry);
2048 }
2049
2050 #if XNU_PLATFORM_MacOSX
2051 /* Allow manipulation of individual page state. This is actually part of */
2052 /* the UPL regimen but takes place on the memory entry rather than on a UPL */
2053
2054 kern_return_t
mach_memory_entry_page_op(ipc_port_t entry_port,vm_object_offset_ut offset_u,int ops,ppnum_t * phys_entry,int * flags)2055 mach_memory_entry_page_op(
2056 ipc_port_t entry_port,
2057 vm_object_offset_ut offset_u,
2058 int ops,
2059 ppnum_t *phys_entry,
2060 int *flags)
2061 {
2062 vm_named_entry_t mem_entry;
2063 vm_object_t object;
2064 kern_return_t kr;
2065 /*
2066 * Unwrap offset as no mathematical operations are
2067 * performed on it.
2068 */
2069 vm_object_offset_t offset = VM_SANITIZE_UNSAFE_UNWRAP(offset_u);
2070
2071 mem_entry = mach_memory_entry_from_port(entry_port);
2072 if (mem_entry == NULL) {
2073 return KERN_INVALID_ARGUMENT;
2074 }
2075
2076 named_entry_lock(mem_entry);
2077
2078 if (mem_entry->is_sub_map ||
2079 mem_entry->is_copy) {
2080 named_entry_unlock(mem_entry);
2081 return KERN_INVALID_ARGUMENT;
2082 }
2083
2084 assert(mem_entry->is_object);
2085 object = vm_named_entry_to_vm_object(mem_entry);
2086 if (object == VM_OBJECT_NULL) {
2087 named_entry_unlock(mem_entry);
2088 return KERN_INVALID_ARGUMENT;
2089 }
2090
2091 vm_object_reference(object);
2092 named_entry_unlock(mem_entry);
2093
2094 kr = vm_object_page_op(object, offset, ops, phys_entry, flags);
2095
2096 vm_object_deallocate(object);
2097
2098 return kr;
2099 }
2100
2101 /*
2102 * mach_memory_entry_range_op offers performance enhancement over
2103 * mach_memory_entry_page_op for page_op functions which do not require page
2104 * level state to be returned from the call. Page_op was created to provide
2105 * a low-cost alternative to page manipulation via UPLs when only a single
2106 * page was involved. The range_op call establishes the ability in the _op
2107 * family of functions to work on multiple pages where the lack of page level
2108 * state handling allows the caller to avoid the overhead of the upl structures.
2109 */
2110
2111 kern_return_t
mach_memory_entry_range_op(ipc_port_t entry_port,vm_object_offset_ut offset_beg_u,vm_object_offset_ut offset_end_u,int ops,int * range)2112 mach_memory_entry_range_op(
2113 ipc_port_t entry_port,
2114 vm_object_offset_ut offset_beg_u,
2115 vm_object_offset_ut offset_end_u,
2116 int ops,
2117 int *range)
2118 {
2119 vm_named_entry_t mem_entry;
2120 vm_object_t object;
2121 kern_return_t kr;
2122 vm_object_offset_t offset_range;
2123 /*
2124 * Unwrap offset beginning and end as no mathematical operations are
2125 * performed on these quantities.
2126 */
2127 vm_object_offset_t offset_beg = VM_SANITIZE_UNSAFE_UNWRAP(offset_beg_u);
2128 vm_object_offset_t offset_end = VM_SANITIZE_UNSAFE_UNWRAP(offset_end_u);
2129
2130 mem_entry = mach_memory_entry_from_port(entry_port);
2131 if (mem_entry == NULL) {
2132 return KERN_INVALID_ARGUMENT;
2133 }
2134
2135 named_entry_lock(mem_entry);
2136
2137 if (__improbable(os_sub_overflow(offset_end, offset_beg, &offset_range) ||
2138 (offset_range > (uint32_t) -1))) {
2139 /* range is too big and would overflow "*range" */
2140 named_entry_unlock(mem_entry);
2141 return KERN_INVALID_ARGUMENT;
2142 }
2143
2144 if (mem_entry->is_sub_map ||
2145 mem_entry->is_copy) {
2146 named_entry_unlock(mem_entry);
2147 return KERN_INVALID_ARGUMENT;
2148 }
2149
2150 assert(mem_entry->is_object);
2151 object = vm_named_entry_to_vm_object(mem_entry);
2152 if (object == VM_OBJECT_NULL) {
2153 named_entry_unlock(mem_entry);
2154 return KERN_INVALID_ARGUMENT;
2155 }
2156
2157 vm_object_reference(object);
2158 named_entry_unlock(mem_entry);
2159
2160 kr = vm_object_range_op(object,
2161 offset_beg,
2162 offset_end,
2163 ops,
2164 (uint32_t *) range);
2165
2166 vm_object_deallocate(object);
2167
2168 return kr;
2169 }
2170 #endif /* XNU_PLATFORM_MacOSX */
2171
2172 kern_return_t
memory_entry_check_for_adjustment(vm_map_t src_map,ipc_port_t port,vm_map_offset_t * overmap_start,vm_map_offset_t * overmap_end)2173 memory_entry_check_for_adjustment(
2174 vm_map_t src_map,
2175 ipc_port_t port,
2176 vm_map_offset_t *overmap_start,
2177 vm_map_offset_t *overmap_end)
2178 {
2179 kern_return_t kr = KERN_SUCCESS;
2180 vm_map_copy_t copy_map = VM_MAP_COPY_NULL, target_copy_map = VM_MAP_COPY_NULL;
2181
2182 assert(port);
2183 assertf(ip_kotype(port) == IKOT_NAMED_ENTRY, "Port Type expected: %d...received:%d\n", IKOT_NAMED_ENTRY, ip_kotype(port));
2184
2185 vm_named_entry_t named_entry;
2186
2187 named_entry = mach_memory_entry_from_port(port);
2188 named_entry_lock(named_entry);
2189 copy_map = named_entry->backing.copy;
2190 target_copy_map = copy_map;
2191
2192 if (src_map && VM_MAP_PAGE_SHIFT(src_map) < PAGE_SHIFT) {
2193 vm_map_offset_t trimmed_start;
2194
2195 trimmed_start = 0;
2196 DEBUG4K_ADJUST("adjusting...\n");
2197 kr = vm_map_copy_adjust_to_target(
2198 copy_map,
2199 vm_sanitize_wrap_addr(0), /* offset */
2200 vm_sanitize_wrap_size(copy_map->size), /* size */
2201 src_map,
2202 FALSE, /* copy */
2203 &target_copy_map,
2204 overmap_start,
2205 overmap_end,
2206 &trimmed_start);
2207 assert(trimmed_start == 0);
2208 }
2209 named_entry_unlock(named_entry);
2210
2211 return kr;
2212 }
2213
2214 vm_object_t
vm_convert_port_to_copy_object(ipc_port_t port)2215 vm_convert_port_to_copy_object(
2216 ipc_port_t port)
2217 {
2218 /* Invalid / wrong port type? */
2219 if (!IP_VALID(port) || ip_kotype(port) != IKOT_NAMED_ENTRY) {
2220 return NULL;
2221 }
2222
2223 /* We expect the named entry to point to an object. */
2224 vm_named_entry_t named_entry = mach_memory_entry_from_port(port);
2225 if (!named_entry || !named_entry->is_object) {
2226 return NULL;
2227 }
2228
2229 /* Pull out the copy map object... */
2230 return vm_named_entry_to_vm_object(named_entry);
2231 }
2232