xref: /xnu-11417.140.69/osfmk/vm/vm_memory_entry.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
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 	    &copy);
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 	    &copy,
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