]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/vm_shared_region.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / vm / vm_shared_region.c
CommitLineData
2d21ac55 1/*
f427ee49 2 * Copyright (c) 2007-2020 Apple Inc. All rights reserved.
2d21ac55
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
0a7de745 12 *
2d21ac55
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
0a7de745 20 *
2d21ac55
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Shared region (... and comm page)
26 *
27 * This file handles the VM shared region and comm page.
28 *
29 */
30/*
31 * SHARED REGIONS
32 * --------------
33 *
34 * A shared region is a submap that contains the most common system shared
f427ee49
A
35 * libraries for a given environment which is defined by:
36 * - cpu-type
37 * - 64-bitness
38 * - root directory
39 * - Team ID - when we have pointer authentication.
2d21ac55
A
40 *
41 * The point of a shared region is to reduce the setup overhead when exec'ing
f427ee49
A
42 * a new process. A shared region uses a shared VM submap that gets mapped
43 * automatically at exec() time, see vm_map_exec(). The first process of a given
2d21ac55
A
44 * environment sets up the shared region and all further processes in that
45 * environment can re-use that shared region without having to re-create
46 * the same mappings in their VM map. All they need is contained in the shared
47 * region.
f427ee49
A
48 *
49 * The region can also share a pmap (mostly for read-only parts but also for the
0a7de745 50 * initial version of some writable parts), which gets "nested" into the
2d21ac55
A
51 * process's pmap. This reduces the number of soft faults: once one process
52 * brings in a page in the shared region, all the other processes can access
53 * it without having to enter it in their own pmap.
54 *
2d21ac55
A
55 * When a process is being exec'ed, vm_map_exec() calls vm_shared_region_enter()
56 * to map the appropriate shared region in the process's address space.
57 * We look up the appropriate shared region for the process's environment.
58 * If we can't find one, we create a new (empty) one and add it to the list.
59 * Otherwise, we just take an extra reference on the shared region we found.
60 *
f427ee49
A
61 * The "dyld" runtime, mapped into the process's address space at exec() time,
62 * will then use the shared_region_check_np() and shared_region_map_and_slide_np()
63 * system calls to validate and/or populate the shared region with the
2d21ac55
A
64 * appropriate dyld_shared_cache file.
65 *
66 * The shared region is inherited on fork() and the child simply takes an
67 * extra reference on its parent's shared region.
68 *
f427ee49 69 * When the task terminates, we release the reference on its shared region.
2d21ac55
A
70 * When the last reference is released, we destroy the shared region.
71 *
72 * After a chroot(), the calling process keeps using its original shared region,
73 * since that's what was mapped when it was started. But its children
74 * will use a different shared region, because they need to use the shared
75 * cache that's relative to the new root directory.
76 */
f427ee49 77
2d21ac55
A
78/*
79 * COMM PAGE
80 *
81 * A "comm page" is an area of memory that is populated by the kernel with
82 * the appropriate platform-specific version of some commonly used code.
83 * There is one "comm page" per platform (cpu-type, 64-bitness) but only
84 * for the native cpu-type. No need to overly optimize translated code
85 * for hardware that is not really there !
86 *
87 * The comm pages are created and populated at boot time.
88 *
89 * The appropriate comm page is mapped into a process's address space
f427ee49 90 * at exec() time, in vm_map_exec(). It is then inherited on fork().
2d21ac55
A
91 *
92 * The comm page is shared between the kernel and all applications of
f427ee49 93 * a given platform. Only the kernel can modify it.
2d21ac55
A
94 *
95 * Applications just branch to fixed addresses in the comm page and find
96 * the right version of the code for the platform. There is also some
97 * data provided and updated by the kernel for processes to retrieve easily
98 * without having to do a system call.
99 */
100
101#include <debug.h>
102
103#include <kern/ipc_tt.h>
104#include <kern/kalloc.h>
b0d623f7 105#include <kern/thread_call.h>
2d21ac55 106
4a3eedf9
A
107#include <mach/mach_vm.h>
108
2d21ac55
A
109#include <vm/vm_map.h>
110#include <vm/vm_shared_region.h>
111
112#include <vm/vm_protos.h>
113
114#include <machine/commpage.h>
115#include <machine/cpu_capabilities.h>
f427ee49 116#include <sys/random.h>
2d21ac55 117
d9a64523
A
118#if defined (__arm__) || defined(__arm64__)
119#include <arm/cpu_data_internal.h>
f427ee49 120#include <arm/misc_protos.h>
d9a64523
A
121#endif
122
123/*
124 * the following codes are used in the subclass
125 * of the DBG_MACH_SHAREDREGION class
126 */
0a7de745 127#define PROCESS_SHARED_CACHE_LAYOUT 0x00
d9a64523 128
f427ee49 129#if __has_feature(ptrauth_calls)
cb323159 130#include <ptrauth.h>
f427ee49 131#endif /* __has_feature(ptrauth_calls) */
d9a64523 132
2d21ac55
A
133/* "dyld" uses this to figure out what the kernel supports */
134int shared_region_version = 3;
135
2d21ac55
A
136/* trace level, output is sent to the system log file */
137int shared_region_trace_level = SHARED_REGION_TRACE_ERROR_LVL;
138
b0d623f7 139/* should local (non-chroot) shared regions persist when no task uses them ? */
0a7de745 140int shared_region_persistence = 0; /* no by default */
b0d623f7 141
f427ee49
A
142
143/* delay in seconds before reclaiming an unused shared region */
144TUNABLE_WRITEABLE(int, shared_region_destroy_delay, "vm_shared_region_destroy_delay", 120);
b0d623f7 145
c3c9b80d
A
146/*
147 * Cached pointer to the most recently mapped shared region from PID 1, which should
148 * be the most commonly mapped shared region in the system. There are many processes
149 * which do not use this, for a variety of reasons.
150 *
151 * The main consumer of this is stackshot.
152 */
153struct vm_shared_region *primary_system_shared_region = NULL;
d9a64523 154
c3c9b80d 155#if XNU_TARGET_OS_OSX
0a7de745 156/*
39236c6e 157 * Only one cache gets to slide on Desktop, since we can't
0a7de745 158 * tear down slide info properly today and the desktop actually
39236c6e
A
159 * produces lots of shared caches.
160 */
6d2010ae 161boolean_t shared_region_completed_slide = FALSE;
c3c9b80d 162#endif /* XNU_TARGET_OS_OSX */
6d2010ae 163
2d21ac55 164/* this lock protects all the shared region data structures */
f427ee49
A
165static LCK_GRP_DECLARE(vm_shared_region_lck_grp, "vm shared region");
166static LCK_MTX_DECLARE(vm_shared_region_lock, &vm_shared_region_lck_grp);
2d21ac55
A
167
168#define vm_shared_region_lock() lck_mtx_lock(&vm_shared_region_lock)
169#define vm_shared_region_unlock() lck_mtx_unlock(&vm_shared_region_lock)
0a7de745
A
170#define vm_shared_region_sleep(event, interruptible) \
171 lck_mtx_sleep(&vm_shared_region_lock, \
172 LCK_SLEEP_DEFAULT, \
173 (event_t) (event), \
174 (interruptible))
2d21ac55
A
175
176/* the list of currently available shared regions (one per environment) */
f427ee49
A
177queue_head_t vm_shared_region_queue = QUEUE_HEAD_INITIALIZER(vm_shared_region_queue);
178int vm_shared_region_count = 0;
179int vm_shared_region_peak = 0;
180
181/*
182 * the number of times an event has forced the recalculation of the reslide
183 * shared region slide.
184 */
185#if __has_feature(ptrauth_calls)
186int vm_shared_region_reslide_count = 0;
187#endif /* __has_feature(ptrauth_calls) */
2d21ac55
A
188
189static void vm_shared_region_reference_locked(vm_shared_region_t shared_region);
190static vm_shared_region_t vm_shared_region_create(
0a7de745
A
191 void *root_dir,
192 cpu_type_t cputype,
193 cpu_subtype_t cpu_subtype,
f427ee49
A
194 boolean_t is_64bit,
195 boolean_t reslide);
2d21ac55
A
196static void vm_shared_region_destroy(vm_shared_region_t shared_region);
197
f427ee49 198static kern_return_t vm_shared_region_slide_sanity_check(vm_shared_region_slide_info_entry_t entry, mach_vm_size_t size);
b0d623f7 199static void vm_shared_region_timeout(thread_call_param_t param0,
0a7de745 200 thread_call_param_t param1);
f427ee49 201static kern_return_t vm_shared_region_slide_mapping(
d9a64523 202 vm_shared_region_t sr,
f427ee49
A
203 user_addr_t slide_info_addr,
204 mach_vm_size_t slide_info_size,
205 mach_vm_offset_t start,
206 mach_vm_size_t size,
207 mach_vm_offset_t slid_mapping,
208 uint32_t slide,
209 memory_object_control_t,
210 vm_prot_t prot); /* forward */
b0d623f7
A
211
212static int __commpage_setup = 0;
c3c9b80d 213#if XNU_TARGET_OS_OSX
0a7de745 214static int __system_power_source = 1; /* init to extrnal power source */
b0d623f7 215static void post_sys_powersource_internal(int i, int internal);
c3c9b80d 216#endif /* XNU_TARGET_OS_OSX */
b0d623f7 217
f427ee49 218extern u_int32_t random(void);
2d21ac55
A
219
220/*
0a7de745
A
221 * Retrieve a task's shared region and grab an extra reference to
222 * make sure it doesn't disappear while the caller is using it.
2d21ac55
A
223 * The caller is responsible for consuming that extra reference if
224 * necessary.
225 */
226vm_shared_region_t
227vm_shared_region_get(
0a7de745 228 task_t task)
2d21ac55 229{
0a7de745 230 vm_shared_region_t shared_region;
2d21ac55
A
231
232 SHARED_REGION_TRACE_DEBUG(
233 ("shared_region: -> get(%p)\n",
0a7de745 234 (void *)VM_KERNEL_ADDRPERM(task)));
2d21ac55
A
235
236 task_lock(task);
237 vm_shared_region_lock();
238 shared_region = task->shared_region;
239 if (shared_region) {
240 assert(shared_region->sr_ref_count > 0);
241 vm_shared_region_reference_locked(shared_region);
242 }
243 vm_shared_region_unlock();
244 task_unlock(task);
245
246 SHARED_REGION_TRACE_DEBUG(
247 ("shared_region: get(%p) <- %p\n",
0a7de745
A
248 (void *)VM_KERNEL_ADDRPERM(task),
249 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
250
251 return shared_region;
252}
253
d9a64523
A
254vm_map_t
255vm_shared_region_vm_map(
0a7de745 256 vm_shared_region_t shared_region)
d9a64523 257{
0a7de745
A
258 ipc_port_t sr_handle;
259 vm_named_entry_t sr_mem_entry;
260 vm_map_t sr_map;
d9a64523
A
261
262 SHARED_REGION_TRACE_DEBUG(
263 ("shared_region: -> vm_map(%p)\n",
0a7de745 264 (void *)VM_KERNEL_ADDRPERM(shared_region)));
c3c9b80d 265 assert(shared_region->sr_ref_count > 0);
d9a64523
A
266
267 sr_handle = shared_region->sr_mem_entry;
ea3f0419 268 sr_mem_entry = (vm_named_entry_t) ip_get_kobject(sr_handle);
d9a64523
A
269 sr_map = sr_mem_entry->backing.map;
270 assert(sr_mem_entry->is_sub_map);
271
272 SHARED_REGION_TRACE_DEBUG(
273 ("shared_region: vm_map(%p) <- %p\n",
0a7de745
A
274 (void *)VM_KERNEL_ADDRPERM(shared_region),
275 (void *)VM_KERNEL_ADDRPERM(sr_map)));
d9a64523
A
276 return sr_map;
277}
39236c6e 278
2d21ac55
A
279/*
280 * Set the shared region the process should use.
281 * A NULL new shared region means that we just want to release the old
282 * shared region.
283 * The caller should already have an extra reference on the new shared region
284 * (if any). We release a reference on the old shared region (if any).
285 */
286void
287vm_shared_region_set(
0a7de745
A
288 task_t task,
289 vm_shared_region_t new_shared_region)
2d21ac55 290{
0a7de745 291 vm_shared_region_t old_shared_region;
2d21ac55
A
292
293 SHARED_REGION_TRACE_DEBUG(
294 ("shared_region: -> set(%p, %p)\n",
0a7de745
A
295 (void *)VM_KERNEL_ADDRPERM(task),
296 (void *)VM_KERNEL_ADDRPERM(new_shared_region)));
2d21ac55
A
297
298 task_lock(task);
299 vm_shared_region_lock();
300
301 old_shared_region = task->shared_region;
302 if (new_shared_region) {
303 assert(new_shared_region->sr_ref_count > 0);
304 }
305
306 task->shared_region = new_shared_region;
307
308 vm_shared_region_unlock();
309 task_unlock(task);
310
311 if (old_shared_region) {
312 assert(old_shared_region->sr_ref_count > 0);
313 vm_shared_region_deallocate(old_shared_region);
314 }
315
316 SHARED_REGION_TRACE_DEBUG(
317 ("shared_region: set(%p) <- old=%p new=%p\n",
0a7de745
A
318 (void *)VM_KERNEL_ADDRPERM(task),
319 (void *)VM_KERNEL_ADDRPERM(old_shared_region),
320 (void *)VM_KERNEL_ADDRPERM(new_shared_region)));
2d21ac55
A
321}
322
323/*
324 * Lookup up the shared region for the desired environment.
325 * If none is found, create a new (empty) one.
326 * Grab an extra reference on the returned shared region, to make sure
327 * it doesn't get destroyed before the caller is done with it. The caller
328 * is responsible for consuming that extra reference if necessary.
329 */
330vm_shared_region_t
331vm_shared_region_lookup(
0a7de745
A
332 void *root_dir,
333 cpu_type_t cputype,
334 cpu_subtype_t cpu_subtype,
f427ee49
A
335 boolean_t is_64bit,
336 boolean_t reslide)
2d21ac55 337{
0a7de745
A
338 vm_shared_region_t shared_region;
339 vm_shared_region_t new_shared_region;
2d21ac55
A
340
341 SHARED_REGION_TRACE_DEBUG(
f427ee49 342 ("shared_region: -> lookup(root=%p,cpu=<%d,%d>,64bit=%d,reslide=%d)\n",
0a7de745 343 (void *)VM_KERNEL_ADDRPERM(root_dir),
f427ee49 344 cputype, cpu_subtype, is_64bit, reslide));
2d21ac55
A
345
346 shared_region = NULL;
347 new_shared_region = NULL;
348
349 vm_shared_region_lock();
350 for (;;) {
351 queue_iterate(&vm_shared_region_queue,
0a7de745
A
352 shared_region,
353 vm_shared_region_t,
354 sr_q) {
2d21ac55
A
355 assert(shared_region->sr_ref_count > 0);
356 if (shared_region->sr_cpu_type == cputype &&
f427ee49 357#if !__has_feature(ptrauth_calls) /* arm64e/arm64 use same region */
d9a64523 358 shared_region->sr_cpu_subtype == cpu_subtype &&
f427ee49 359#endif /* !__has_feature(ptrauth_calls) */
2d21ac55 360 shared_region->sr_root_dir == root_dir &&
f427ee49
A
361 shared_region->sr_64bit == is_64bit &&
362#if __has_feature(ptrauth_calls)
363 shared_region->sr_reslide == reslide &&
364#endif /* __has_feature(ptrauth_calls) */
365 !shared_region->sr_stale) {
2d21ac55
A
366 /* found a match ! */
367 vm_shared_region_reference_locked(shared_region);
368 goto done;
369 }
370 }
371 if (new_shared_region == NULL) {
372 /* no match: create a new one */
373 vm_shared_region_unlock();
374 new_shared_region = vm_shared_region_create(root_dir,
0a7de745
A
375 cputype,
376 cpu_subtype,
f427ee49
A
377 is_64bit,
378 reslide);
2d21ac55
A
379 /* do the lookup again, in case we lost a race */
380 vm_shared_region_lock();
381 continue;
382 }
383 /* still no match: use our new one */
384 shared_region = new_shared_region;
385 new_shared_region = NULL;
386 queue_enter(&vm_shared_region_queue,
0a7de745
A
387 shared_region,
388 vm_shared_region_t,
389 sr_q);
f427ee49
A
390 vm_shared_region_count++;
391 if (vm_shared_region_count > vm_shared_region_peak) {
392 vm_shared_region_peak = vm_shared_region_count;
393 }
2d21ac55
A
394 break;
395 }
396
397done:
398 vm_shared_region_unlock();
399
400 if (new_shared_region) {
401 /*
402 * We lost a race with someone else to create a new shared
f427ee49 403 * region for that environment. Get rid of our unused one.
2d21ac55
A
404 */
405 assert(new_shared_region->sr_ref_count == 1);
406 new_shared_region->sr_ref_count--;
407 vm_shared_region_destroy(new_shared_region);
408 new_shared_region = NULL;
409 }
410
411 SHARED_REGION_TRACE_DEBUG(
f427ee49 412 ("shared_region: lookup(root=%p,cpu=<%d,%d>,64bit=%d,reslide=%d) <- %p\n",
0a7de745 413 (void *)VM_KERNEL_ADDRPERM(root_dir),
f427ee49 414 cputype, cpu_subtype, is_64bit, reslide,
0a7de745 415 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
416
417 assert(shared_region->sr_ref_count > 0);
418 return shared_region;
419}
420
421/*
422 * Take an extra reference on a shared region.
423 * The vm_shared_region_lock should already be held by the caller.
424 */
425static void
426vm_shared_region_reference_locked(
0a7de745 427 vm_shared_region_t shared_region)
2d21ac55 428{
39037602 429 LCK_MTX_ASSERT(&vm_shared_region_lock, LCK_MTX_ASSERT_OWNED);
2d21ac55
A
430
431 SHARED_REGION_TRACE_DEBUG(
432 ("shared_region: -> reference_locked(%p)\n",
0a7de745 433 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
434 assert(shared_region->sr_ref_count > 0);
435 shared_region->sr_ref_count++;
f427ee49 436 assert(shared_region->sr_ref_count != 0);
b0d623f7
A
437
438 if (shared_region->sr_timer_call != NULL) {
439 boolean_t cancelled;
440
441 /* cancel and free any pending timeout */
442 cancelled = thread_call_cancel(shared_region->sr_timer_call);
443 if (cancelled) {
444 thread_call_free(shared_region->sr_timer_call);
445 shared_region->sr_timer_call = NULL;
446 /* release the reference held by the cancelled timer */
447 shared_region->sr_ref_count--;
448 } else {
449 /* the timer will drop the reference and free itself */
450 }
451 }
452
2d21ac55
A
453 SHARED_REGION_TRACE_DEBUG(
454 ("shared_region: reference_locked(%p) <- %d\n",
0a7de745
A
455 (void *)VM_KERNEL_ADDRPERM(shared_region),
456 shared_region->sr_ref_count));
2d21ac55
A
457}
458
f427ee49
A
459/*
460 * Take a reference on a shared region.
461 */
462void
463vm_shared_region_reference(vm_shared_region_t shared_region)
464{
465 SHARED_REGION_TRACE_DEBUG(
466 ("shared_region: -> reference(%p)\n",
467 (void *)VM_KERNEL_ADDRPERM(shared_region)));
468
469 vm_shared_region_lock();
470 vm_shared_region_reference_locked(shared_region);
471 vm_shared_region_unlock();
472
473 SHARED_REGION_TRACE_DEBUG(
474 ("shared_region: reference(%p) <- %d\n",
475 (void *)VM_KERNEL_ADDRPERM(shared_region),
476 shared_region->sr_ref_count));
477}
478
2d21ac55
A
479/*
480 * Release a reference on the shared region.
481 * Destroy it if there are no references left.
482 */
483void
484vm_shared_region_deallocate(
0a7de745 485 vm_shared_region_t shared_region)
2d21ac55
A
486{
487 SHARED_REGION_TRACE_DEBUG(
488 ("shared_region: -> deallocate(%p)\n",
0a7de745 489 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
490
491 vm_shared_region_lock();
0a7de745 492
2d21ac55
A
493 assert(shared_region->sr_ref_count > 0);
494
495 if (shared_region->sr_root_dir == NULL) {
496 /*
497 * Local (i.e. based on the boot volume) shared regions
498 * can persist or not based on the "shared_region_persistence"
499 * sysctl.
500 * Make sure that this one complies.
39236c6e
A
501 *
502 * See comments in vm_shared_region_slide() for notes about
503 * shared regions we have slid (which are not torn down currently).
2d21ac55
A
504 */
505 if (shared_region_persistence &&
506 !shared_region->sr_persists) {
507 /* make this one persistent */
508 shared_region->sr_ref_count++;
509 shared_region->sr_persists = TRUE;
510 } else if (!shared_region_persistence &&
0a7de745 511 shared_region->sr_persists) {
2d21ac55
A
512 /* make this one no longer persistent */
513 assert(shared_region->sr_ref_count > 1);
514 shared_region->sr_ref_count--;
515 shared_region->sr_persists = FALSE;
516 }
517 }
518
519 assert(shared_region->sr_ref_count > 0);
520 shared_region->sr_ref_count--;
521 SHARED_REGION_TRACE_DEBUG(
522 ("shared_region: deallocate(%p): ref now %d\n",
0a7de745
A
523 (void *)VM_KERNEL_ADDRPERM(shared_region),
524 shared_region->sr_ref_count));
2d21ac55
A
525
526 if (shared_region->sr_ref_count == 0) {
b0d623f7
A
527 uint64_t deadline;
528
f427ee49
A
529 /*
530 * Even though a shared region is unused, delay a while before
531 * tearing it down, in case a new app launch can use it.
532 */
533 if (shared_region->sr_timer_call == NULL &&
534 shared_region_destroy_delay != 0 &&
535 !shared_region->sr_stale) {
b0d623f7 536 /* hold one reference for the timer */
0a7de745 537 assert(!shared_region->sr_mapping_in_progress);
b0d623f7
A
538 shared_region->sr_ref_count++;
539
540 /* set up the timer */
541 shared_region->sr_timer_call = thread_call_allocate(
542 (thread_call_func_t) vm_shared_region_timeout,
543 (thread_call_param_t) shared_region);
544
545 /* schedule the timer */
546 clock_interval_to_deadline(shared_region_destroy_delay,
f427ee49 547 NSEC_PER_SEC,
0a7de745 548 &deadline);
b0d623f7 549 thread_call_enter_delayed(shared_region->sr_timer_call,
0a7de745 550 deadline);
b0d623f7
A
551
552 SHARED_REGION_TRACE_DEBUG(
553 ("shared_region: deallocate(%p): armed timer\n",
0a7de745 554 (void *)VM_KERNEL_ADDRPERM(shared_region)));
b0d623f7
A
555
556 vm_shared_region_unlock();
557 } else {
558 /* timer expired: let go of this shared region */
559
c3c9b80d
A
560 /* Make sure there's no cached pointer to the region. */
561 if (primary_system_shared_region == shared_region) {
562 primary_system_shared_region = NULL;
563 }
564
b0d623f7
A
565 /*
566 * Remove it from the queue first, so no one can find
567 * it...
568 */
569 queue_remove(&vm_shared_region_queue,
0a7de745
A
570 shared_region,
571 vm_shared_region_t,
572 sr_q);
f427ee49 573 vm_shared_region_count--;
b0d623f7 574 vm_shared_region_unlock();
39236c6e 575
b0d623f7
A
576 /* ... and destroy it */
577 vm_shared_region_destroy(shared_region);
578 shared_region = NULL;
579 }
2d21ac55
A
580 } else {
581 vm_shared_region_unlock();
582 }
583
584 SHARED_REGION_TRACE_DEBUG(
585 ("shared_region: deallocate(%p) <-\n",
0a7de745 586 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
587}
588
b0d623f7
A
589void
590vm_shared_region_timeout(
0a7de745
A
591 thread_call_param_t param0,
592 __unused thread_call_param_t param1)
b0d623f7 593{
0a7de745 594 vm_shared_region_t shared_region;
b0d623f7
A
595
596 shared_region = (vm_shared_region_t) param0;
597
598 vm_shared_region_deallocate(shared_region);
599}
600
f427ee49 601
2d21ac55
A
602/*
603 * Create a new (empty) shared region for a new environment.
604 */
605static vm_shared_region_t
606vm_shared_region_create(
0a7de745
A
607 void *root_dir,
608 cpu_type_t cputype,
609 cpu_subtype_t cpu_subtype,
f427ee49
A
610 boolean_t is_64bit,
611#if !__has_feature(ptrauth_calls)
612 __unused
613#endif /* __has_feature(ptrauth_calls) */
614 boolean_t reslide)
2d21ac55 615{
0a7de745
A
616 kern_return_t kr;
617 vm_named_entry_t mem_entry;
618 ipc_port_t mem_entry_port;
619 vm_shared_region_t shared_region;
0a7de745
A
620 vm_map_t sub_map;
621 mach_vm_offset_t base_address, pmap_nesting_start;
622 mach_vm_size_t size, pmap_nesting_size;
2d21ac55 623
d9a64523 624 SHARED_REGION_TRACE_INFO(
f427ee49 625 ("shared_region: -> create(root=%p,cpu=<%d,%d>,64bit=%d,reslide=%d)\n",
0a7de745 626 (void *)VM_KERNEL_ADDRPERM(root_dir),
f427ee49 627 cputype, cpu_subtype, is_64bit, reslide));
2d21ac55
A
628
629 base_address = 0;
630 size = 0;
631 mem_entry = NULL;
632 mem_entry_port = IPC_PORT_NULL;
633 sub_map = VM_MAP_NULL;
634
635 /* create a new shared region structure... */
0a7de745 636 shared_region = kalloc(sizeof(*shared_region));
2d21ac55
A
637 if (shared_region == NULL) {
638 SHARED_REGION_TRACE_ERROR(
639 ("shared_region: create: couldn't allocate\n"));
640 goto done;
641 }
642
643 /* figure out the correct settings for the desired environment */
644 if (is_64bit) {
645 switch (cputype) {
5ba3f43e
A
646#if defined(__arm64__)
647 case CPU_TYPE_ARM64:
648 base_address = SHARED_REGION_BASE_ARM64;
649 size = SHARED_REGION_SIZE_ARM64;
650 pmap_nesting_start = SHARED_REGION_NESTING_BASE_ARM64;
651 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_ARM64;
652 break;
653#elif !defined(__arm__)
2d21ac55
A
654 case CPU_TYPE_I386:
655 base_address = SHARED_REGION_BASE_X86_64;
656 size = SHARED_REGION_SIZE_X86_64;
657 pmap_nesting_start = SHARED_REGION_NESTING_BASE_X86_64;
658 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_X86_64;
659 break;
660 case CPU_TYPE_POWERPC:
661 base_address = SHARED_REGION_BASE_PPC64;
662 size = SHARED_REGION_SIZE_PPC64;
663 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC64;
664 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC64;
665 break;
5ba3f43e 666#endif
2d21ac55
A
667 default:
668 SHARED_REGION_TRACE_ERROR(
669 ("shared_region: create: unknown cpu type %d\n",
0a7de745
A
670 cputype));
671 kfree(shared_region, sizeof(*shared_region));
2d21ac55
A
672 shared_region = NULL;
673 goto done;
674 }
675 } else {
676 switch (cputype) {
5ba3f43e
A
677#if defined(__arm__) || defined(__arm64__)
678 case CPU_TYPE_ARM:
5ba3f43e
A
679 base_address = SHARED_REGION_BASE_ARM;
680 size = SHARED_REGION_SIZE_ARM;
681 pmap_nesting_start = SHARED_REGION_NESTING_BASE_ARM;
682 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_ARM;
683 break;
684#else
2d21ac55
A
685 case CPU_TYPE_I386:
686 base_address = SHARED_REGION_BASE_I386;
687 size = SHARED_REGION_SIZE_I386;
688 pmap_nesting_start = SHARED_REGION_NESTING_BASE_I386;
689 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_I386;
690 break;
691 case CPU_TYPE_POWERPC:
692 base_address = SHARED_REGION_BASE_PPC;
693 size = SHARED_REGION_SIZE_PPC;
694 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC;
695 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC;
696 break;
5ba3f43e 697#endif
2d21ac55
A
698 default:
699 SHARED_REGION_TRACE_ERROR(
700 ("shared_region: create: unknown cpu type %d\n",
0a7de745
A
701 cputype));
702 kfree(shared_region, sizeof(*shared_region));
2d21ac55
A
703 shared_region = NULL;
704 goto done;
2d21ac55
A
705 }
706 }
707
708 /* create a memory entry structure and a Mach port handle */
f427ee49 709 kr = mach_memory_entry_allocate(&mem_entry, &mem_entry_port);
2d21ac55 710 if (kr != KERN_SUCCESS) {
0a7de745 711 kfree(shared_region, sizeof(*shared_region));
2d21ac55
A
712 shared_region = NULL;
713 SHARED_REGION_TRACE_ERROR(
714 ("shared_region: create: "
0a7de745 715 "couldn't allocate mem_entry\n"));
2d21ac55
A
716 goto done;
717 }
718
0a7de745 719#if defined(__arm__) || defined(__arm64__)
5ba3f43e
A
720 {
721 struct pmap *pmap_nested;
f427ee49
A
722 int pmap_flags = 0;
723 pmap_flags |= is_64bit ? PMAP_CREATE_64BIT : 0;
724
5ba3f43e 725
f427ee49 726 pmap_nested = pmap_create_options(NULL, 0, pmap_flags);
5ba3f43e
A
727 if (pmap_nested != PMAP_NULL) {
728 pmap_set_nested(pmap_nested);
f427ee49 729 sub_map = vm_map_create(pmap_nested, 0, (vm_map_offset_t)size, TRUE);
5ba3f43e
A
730#if defined(__arm64__)
731 if (is_64bit ||
732 page_shift_user32 == SIXTEENK_PAGE_SHIFT) {
733 /* enforce 16KB alignment of VM map entries */
734 vm_map_set_page_shift(sub_map,
0a7de745 735 SIXTEENK_PAGE_SHIFT);
5ba3f43e 736 }
f427ee49 737
cb323159 738#elif (__ARM_ARCH_7K__ >= 2)
5ba3f43e
A
739 /* enforce 16KB alignment for watch targets with new ABI */
740 vm_map_set_page_shift(sub_map, SIXTEENK_PAGE_SHIFT);
741#endif /* __arm64__ */
742 } else {
743 sub_map = VM_MAP_NULL;
744 }
745 }
746#else
2d21ac55 747 /* create a VM sub map and its pmap */
f427ee49 748 sub_map = vm_map_create(pmap_create_options(NULL, 0, is_64bit), 0, size, TRUE);
5ba3f43e 749#endif
2d21ac55
A
750 if (sub_map == VM_MAP_NULL) {
751 ipc_port_release_send(mem_entry_port);
0a7de745 752 kfree(shared_region, sizeof(*shared_region));
2d21ac55 753 shared_region = NULL;
f427ee49 754 SHARED_REGION_TRACE_ERROR(("shared_region: create: couldn't allocate map\n"));
2d21ac55
A
755 goto done;
756 }
757
f427ee49
A
758 /* shared regions should always enforce code-signing */
759 vm_map_cs_enforcement_set(sub_map, true);
760 assert(vm_map_cs_enforcement(sub_map));
761 assert(pmap_get_vm_map_cs_enforced(vm_map_pmap(sub_map)));
762
39037602
A
763 assert(!sub_map->disable_vmentry_reuse);
764 sub_map->is_nested_map = TRUE;
765
2d21ac55
A
766 /* make the memory entry point to the VM sub map */
767 mem_entry->is_sub_map = TRUE;
768 mem_entry->backing.map = sub_map;
769 mem_entry->size = size;
770 mem_entry->protection = VM_PROT_ALL;
771
772 /* make the shared region point at the memory entry */
773 shared_region->sr_mem_entry = mem_entry_port;
774
775 /* fill in the shared region's environment and settings */
776 shared_region->sr_base_address = base_address;
777 shared_region->sr_size = size;
778 shared_region->sr_pmap_nesting_start = pmap_nesting_start;
779 shared_region->sr_pmap_nesting_size = pmap_nesting_size;
780 shared_region->sr_cpu_type = cputype;
d9a64523 781 shared_region->sr_cpu_subtype = cpu_subtype;
f427ee49 782 shared_region->sr_64bit = (uint8_t)is_64bit;
2d21ac55
A
783 shared_region->sr_root_dir = root_dir;
784
785 queue_init(&shared_region->sr_q);
786 shared_region->sr_mapping_in_progress = FALSE;
39236c6e 787 shared_region->sr_slide_in_progress = FALSE;
2d21ac55 788 shared_region->sr_persists = FALSE;
f427ee49 789 shared_region->sr_stale = FALSE;
b0d623f7 790 shared_region->sr_timer_call = NULL;
2d21ac55
A
791 shared_region->sr_first_mapping = (mach_vm_offset_t) -1;
792
793 /* grab a reference for the caller */
794 shared_region->sr_ref_count = 1;
795
f427ee49 796 shared_region->sr_slide = 0; /* not slid yet */
39236c6e 797
d9a64523 798 /* Initialize UUID and other metadata */
5ba3f43e
A
799 memset(&shared_region->sr_uuid, '\0', sizeof(shared_region->sr_uuid));
800 shared_region->sr_uuid_copied = FALSE;
d9a64523
A
801 shared_region->sr_images_count = 0;
802 shared_region->sr_images = NULL;
f427ee49
A
803#if __has_feature(ptrauth_calls)
804 shared_region->sr_reslide = reslide;
805 shared_region->sr_num_auth_section = 0;
806 for (uint_t i = 0; i < NUM_SR_AUTH_SECTIONS; ++i) {
807 shared_region->sr_auth_section[i] = NULL;
808 }
809 shared_region->sr_num_auth_section = 0;
810#endif /* __has_feature(ptrauth_calls) */
811
2d21ac55
A
812done:
813 if (shared_region) {
814 SHARED_REGION_TRACE_INFO(
f427ee49 815 ("shared_region: create(root=%p,cpu=<%d,%d>,64bit=%d,reslide=%d"
0a7de745
A
816 "base=0x%llx,size=0x%llx) <- "
817 "%p mem=(%p,%p) map=%p pmap=%p\n",
818 (void *)VM_KERNEL_ADDRPERM(root_dir),
f427ee49 819 cputype, cpu_subtype, is_64bit, reslide,
0a7de745
A
820 (long long)base_address,
821 (long long)size,
822 (void *)VM_KERNEL_ADDRPERM(shared_region),
823 (void *)VM_KERNEL_ADDRPERM(mem_entry_port),
824 (void *)VM_KERNEL_ADDRPERM(mem_entry),
825 (void *)VM_KERNEL_ADDRPERM(sub_map),
826 (void *)VM_KERNEL_ADDRPERM(sub_map->pmap)));
2d21ac55
A
827 } else {
828 SHARED_REGION_TRACE_INFO(
d9a64523 829 ("shared_region: create(root=%p,cpu=<%d,%d>,64bit=%d,"
0a7de745
A
830 "base=0x%llx,size=0x%llx) <- NULL",
831 (void *)VM_KERNEL_ADDRPERM(root_dir),
832 cputype, cpu_subtype, is_64bit,
833 (long long)base_address,
834 (long long)size));
2d21ac55
A
835 }
836 return shared_region;
837}
838
839/*
840 * Destroy a now-unused shared region.
841 * The shared region is no longer in the queue and can not be looked up.
842 */
843static void
844vm_shared_region_destroy(
0a7de745 845 vm_shared_region_t shared_region)
2d21ac55 846{
0a7de745
A
847 vm_named_entry_t mem_entry;
848 vm_map_t map;
2d21ac55
A
849
850 SHARED_REGION_TRACE_INFO(
d9a64523 851 ("shared_region: -> destroy(%p) (root=%p,cpu=<%d,%d>,64bit=%d)\n",
0a7de745
A
852 (void *)VM_KERNEL_ADDRPERM(shared_region),
853 (void *)VM_KERNEL_ADDRPERM(shared_region->sr_root_dir),
854 shared_region->sr_cpu_type,
855 shared_region->sr_cpu_subtype,
856 shared_region->sr_64bit));
2d21ac55
A
857
858 assert(shared_region->sr_ref_count == 0);
859 assert(!shared_region->sr_persists);
860
ea3f0419 861 mem_entry = (vm_named_entry_t) ip_get_kobject(shared_region->sr_mem_entry);
2d21ac55
A
862 assert(mem_entry->is_sub_map);
863 assert(!mem_entry->internal);
39236c6e 864 assert(!mem_entry->is_copy);
2d21ac55
A
865 map = mem_entry->backing.map;
866
867 /*
868 * Clean up the pmap first. The virtual addresses that were
869 * entered in this possibly "nested" pmap may have different values
870 * than the VM map's min and max offsets, if the VM sub map was
871 * mapped at a non-zero offset in the processes' main VM maps, which
872 * is usually the case, so the clean-up we do in vm_map_destroy() would
873 * not be enough.
874 */
875 if (map->pmap) {
876 pmap_remove(map->pmap,
f427ee49
A
877 (vm_map_offset_t)shared_region->sr_base_address,
878 (vm_map_offset_t)(shared_region->sr_base_address + shared_region->sr_size));
2d21ac55
A
879 }
880
881 /*
882 * Release our (one and only) handle on the memory entry.
883 * This will generate a no-senders notification, which will be processed
884 * by ipc_kobject_notify(), which will release the one and only
885 * reference on the memory entry and cause it to be destroyed, along
886 * with the VM sub map and its pmap.
887 */
888 mach_memory_entry_port_release(shared_region->sr_mem_entry);
889 mem_entry = NULL;
890 shared_region->sr_mem_entry = IPC_PORT_NULL;
891
b0d623f7
A
892 if (shared_region->sr_timer_call) {
893 thread_call_free(shared_region->sr_timer_call);
894 }
895
f427ee49 896#if __has_feature(ptrauth_calls)
0a7de745 897 /*
f427ee49 898 * Free the cached copies of slide_info for the AUTH regions.
39236c6e 899 */
f427ee49
A
900 for (uint_t i = 0; i < shared_region->sr_num_auth_section; ++i) {
901 vm_shared_region_slide_info_t si = shared_region->sr_auth_section[i];
902 if (si != NULL) {
903 vm_object_deallocate(si->si_slide_object);
904 kheap_free(KHEAP_DATA_BUFFERS, si->si_slide_info_entry, si->si_slide_info_size);
905 kfree(si, sizeof *si);
906 shared_region->sr_auth_section[i] = NULL;
907 }
6d2010ae 908 }
f427ee49
A
909 shared_region->sr_num_auth_section = 0;
910#endif /* __has_feature(ptrauth_calls) */
6d2010ae 911
2d21ac55 912 /* release the shared region structure... */
0a7de745 913 kfree(shared_region, sizeof(*shared_region));
6d2010ae 914
2d21ac55
A
915 SHARED_REGION_TRACE_DEBUG(
916 ("shared_region: destroy(%p) <-\n",
0a7de745 917 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55 918 shared_region = NULL;
2d21ac55
A
919}
920
921/*
922 * Gets the address of the first (in time) mapping in the shared region.
c3c9b80d 923 * If used during initial task setup by dyld, task should non-NULL.
2d21ac55
A
924 */
925kern_return_t
926vm_shared_region_start_address(
0a7de745 927 vm_shared_region_t shared_region,
c3c9b80d
A
928 mach_vm_offset_t *start_address,
929 task_t task)
2d21ac55 930{
0a7de745
A
931 kern_return_t kr;
932 mach_vm_offset_t sr_base_address;
933 mach_vm_offset_t sr_first_mapping;
2d21ac55
A
934
935 SHARED_REGION_TRACE_DEBUG(
936 ("shared_region: -> start_address(%p)\n",
0a7de745 937 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55
A
938
939 vm_shared_region_lock();
940
941 /*
942 * Wait if there's another thread establishing a mapping
943 * in this shared region right when we're looking at it.
944 * We want a consistent view of the map...
945 */
946 while (shared_region->sr_mapping_in_progress) {
947 /* wait for our turn... */
2d21ac55 948 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
0a7de745 949 THREAD_UNINT);
2d21ac55 950 }
0a7de745 951 assert(!shared_region->sr_mapping_in_progress);
c3c9b80d 952 assert(shared_region->sr_ref_count > 0);
0a7de745 953
2d21ac55
A
954 sr_base_address = shared_region->sr_base_address;
955 sr_first_mapping = shared_region->sr_first_mapping;
956
957 if (sr_first_mapping == (mach_vm_offset_t) -1) {
958 /* shared region is empty */
959 kr = KERN_INVALID_ADDRESS;
960 } else {
961 kr = KERN_SUCCESS;
962 *start_address = sr_base_address + sr_first_mapping;
963 }
964
f427ee49 965
c3c9b80d
A
966 uint32_t slide = shared_region->sr_slide;
967
2d21ac55 968 vm_shared_region_unlock();
0a7de745 969
c3c9b80d
A
970 /*
971 * Cache shared region info in the task for telemetry gathering, if we're
972 * passed in the task. No task lock here as we're still in intial task set up.
973 */
974 if (kr == KERN_SUCCESS && task != NULL && task->task_shared_region_slide == -1) {
975 uint_t sc_header_uuid_offset = offsetof(struct _dyld_cache_header, uuid);
976 if (copyin((user_addr_t)(*start_address + sc_header_uuid_offset),
977 (char *)&task->task_shared_region_uuid,
978 sizeof(task->task_shared_region_uuid)) == 0) {
979 task->task_shared_region_slide = slide;
980 }
981 }
982
2d21ac55
A
983 SHARED_REGION_TRACE_DEBUG(
984 ("shared_region: start_address(%p) <- 0x%llx\n",
0a7de745
A
985 (void *)VM_KERNEL_ADDRPERM(shared_region),
986 (long long)shared_region->sr_base_address));
2d21ac55
A
987
988 return kr;
989}
6d2010ae 990
f427ee49
A
991/*
992 * Look up a pre-existing mapping in shared region, for replacement.
993 * Takes an extra object reference if found.
994 */
995static kern_return_t
996find_mapping_to_slide(vm_map_t map, vm_map_address_t addr, vm_map_entry_t entry)
997{
998 vm_map_entry_t found;
999
1000 /* find the shared region's map entry to slide */
1001 vm_map_lock_read(map);
1002 if (!vm_map_lookup_entry(map, addr, &found)) {
1003 /* no mapping there */
1004 vm_map_unlock(map);
1005 return KERN_INVALID_ARGUMENT;
1006 }
1007
1008 *entry = *found;
1009 /* extra ref to keep object alive while map is unlocked */
1010 vm_object_reference(VME_OBJECT(found));
1011 vm_map_unlock_read(map);
1012 return KERN_SUCCESS;
1013}
1014
1015#if __has_feature(ptrauth_calls)
1016
1017/*
1018 * Determine if this task is actually using pointer signing.
1019 */
1020static boolean_t
1021task_sign_pointers(task_t task)
1022{
1023 if (task->map &&
1024 task->map->pmap &&
1025 !task->map->pmap->disable_jop) {
1026 return TRUE;
1027 }
1028 return FALSE;
1029}
1030
1031/*
1032 * If the shared region contains mappings that are authenticated, then
1033 * remap them into the task private map.
1034 *
1035 * Failures are possible in this routine when jetsam kills a process
1036 * just as dyld is trying to set it up. The vm_map and task shared region
1037 * info get torn down w/o waiting for this thread to finish up.
1038 */
1039__attribute__((noinline))
1040kern_return_t
1041vm_shared_region_auth_remap(vm_shared_region_t sr)
1042{
1043 memory_object_t sr_pager = MEMORY_OBJECT_NULL;
1044 task_t task = current_task();
1045 vm_shared_region_slide_info_t si;
1046 uint_t i;
1047 vm_object_t object;
1048 vm_map_t sr_map;
1049 struct vm_map_entry tmp_entry_store = {0};
1050 vm_map_entry_t tmp_entry = NULL;
1051 int vm_flags;
1052 vm_map_kernel_flags_t vmk_flags;
1053 vm_map_offset_t map_addr;
1054 kern_return_t kr = KERN_SUCCESS;
1055 boolean_t use_ptr_auth = task_sign_pointers(task);
1056
1057 /*
1058 * Don't do this more than once and avoid any race conditions in finishing it.
1059 */
1060 vm_shared_region_lock();
1061 while (sr->sr_mapping_in_progress) {
1062 /* wait for our turn... */
1063 vm_shared_region_sleep(&sr->sr_mapping_in_progress, THREAD_UNINT);
1064 }
1065 assert(!sr->sr_mapping_in_progress);
c3c9b80d 1066 assert(sr->sr_ref_count > 0);
f427ee49
A
1067
1068 /* Just return if already done. */
1069 if (task->shared_region_auth_remapped) {
1070 vm_shared_region_unlock();
1071 return KERN_SUCCESS;
1072 }
1073
1074 /* let others know to wait while we're working in this shared region */
1075 sr->sr_mapping_in_progress = TRUE;
1076 vm_shared_region_unlock();
1077
1078 /*
1079 * Remap any sections with pointer authentications into the private map.
1080 */
1081 for (i = 0; i < sr->sr_num_auth_section; ++i) {
1082 si = sr->sr_auth_section[i];
1083 assert(si != NULL);
1084 assert(si->si_ptrauth);
1085
1086 /*
1087 * We have mapping that needs to be private.
1088 * Look for an existing slid mapping's pager with matching
1089 * object, offset, slide info and shared_region_id to reuse.
1090 */
1091 object = si->si_slide_object;
1092 sr_pager = shared_region_pager_match(object, si->si_start, si,
1093 use_ptr_auth ? task->jop_pid : 0);
1094 if (sr_pager == MEMORY_OBJECT_NULL) {
1095 kr = KERN_FAILURE;
1096 goto done;
1097 }
1098
1099 /*
1100 * verify matching jop_pid for this task and this pager
1101 */
1102 if (use_ptr_auth) {
1103 shared_region_pager_match_task_key(sr_pager, task);
1104 }
1105
1106 sr_map = vm_shared_region_vm_map(sr);
1107 tmp_entry = NULL;
1108
1109 kr = find_mapping_to_slide(sr_map, si->si_slid_address - sr->sr_base_address, &tmp_entry_store);
1110 if (kr != KERN_SUCCESS) {
1111 goto done;
1112 }
1113 tmp_entry = &tmp_entry_store;
1114
1115 /*
1116 * Check that the object exactly covers the region to slide.
1117 */
c3c9b80d 1118 if (tmp_entry->vme_end - tmp_entry->vme_start != si->si_end - si->si_start) {
f427ee49
A
1119 kr = KERN_FAILURE;
1120 goto done;
1121 }
1122
1123 /*
1124 * map the pager over the portion of the mapping that needs sliding
1125 */
1126 vm_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
1127 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
1128 vmk_flags.vmkf_overwrite_immutable = TRUE;
1129 map_addr = si->si_slid_address;
1130 kr = vm_map_enter_mem_object(task->map,
1131 &map_addr,
1132 si->si_end - si->si_start,
1133 (mach_vm_offset_t) 0,
1134 vm_flags,
1135 vmk_flags,
1136 VM_KERN_MEMORY_NONE,
1137 (ipc_port_t)(uintptr_t) sr_pager,
1138 0,
1139 TRUE,
1140 tmp_entry->protection,
1141 tmp_entry->max_protection,
1142 tmp_entry->inheritance);
1143 memory_object_deallocate(sr_pager);
1144 sr_pager = MEMORY_OBJECT_NULL;
1145 if (kr != KERN_SUCCESS) {
1146 goto done;
1147 }
1148 assertf(map_addr == si->si_slid_address,
1149 "map_addr=0x%llx si_slid_address=0x%llx tmp_entry=%p\n",
1150 (uint64_t)map_addr,
1151 (uint64_t)si->si_slid_address,
1152 tmp_entry);
1153
1154 /* Drop the ref count grabbed by find_mapping_to_slide */
1155 vm_object_deallocate(VME_OBJECT(tmp_entry));
1156 tmp_entry = NULL;
1157 }
1158
1159done:
1160 if (tmp_entry) {
1161 /* Drop the ref count grabbed by find_mapping_to_slide */
1162 vm_object_deallocate(VME_OBJECT(tmp_entry));
1163 tmp_entry = NULL;
1164 }
1165
1166 /*
1167 * Drop any extra reference to the pager in case we're quitting due to an error above.
1168 */
1169 if (sr_pager != MEMORY_OBJECT_NULL) {
1170 memory_object_deallocate(sr_pager);
1171 }
1172
1173 /*
1174 * Mark the region as having it's auth sections remapped.
1175 */
1176 vm_shared_region_lock();
1177 task->shared_region_auth_remapped = TRUE;
1178 sr->sr_mapping_in_progress = FALSE;
1179 thread_wakeup((event_t)&sr->sr_mapping_in_progress);
1180 vm_shared_region_unlock();
1181 return kr;
1182}
1183#endif /* __has_feature(ptrauth_calls) */
1184
6d2010ae
A
1185void
1186vm_shared_region_undo_mappings(
f427ee49
A
1187 vm_map_t sr_map,
1188 mach_vm_offset_t sr_base_address,
1189 struct _sr_file_mappings *srf_mappings,
1190 struct _sr_file_mappings *srf_mappings_current,
1191 unsigned int srf_current_mappings_count)
6d2010ae 1192{
f427ee49
A
1193 unsigned int j = 0;
1194 vm_shared_region_t shared_region = NULL;
1195 boolean_t reset_shared_region_state = FALSE;
1196 struct _sr_file_mappings *srfmp;
1197 unsigned int mappings_count;
1198 struct shared_file_mapping_slide_np *mappings;
316670eb 1199
6d2010ae
A
1200 shared_region = vm_shared_region_get(current_task());
1201 if (shared_region == NULL) {
316670eb 1202 printf("Failed to undo mappings because of NULL shared region.\n");
6d2010ae
A
1203 return;
1204 }
0a7de745 1205
6d2010ae 1206 if (sr_map == NULL) {
0a7de745
A
1207 ipc_port_t sr_handle;
1208 vm_named_entry_t sr_mem_entry;
6d2010ae
A
1209
1210 vm_shared_region_lock();
c3c9b80d 1211 assert(shared_region->sr_ref_count > 0);
6d2010ae
A
1212
1213 while (shared_region->sr_mapping_in_progress) {
1214 /* wait for our turn... */
1215 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
0a7de745 1216 THREAD_UNINT);
6d2010ae 1217 }
0a7de745 1218 assert(!shared_region->sr_mapping_in_progress);
c3c9b80d 1219 assert(shared_region->sr_ref_count > 0);
6d2010ae
A
1220 /* let others know we're working in this shared region */
1221 shared_region->sr_mapping_in_progress = TRUE;
1222
1223 vm_shared_region_unlock();
1224
1225 reset_shared_region_state = TRUE;
1226
1227 /* no need to lock because this data is never modified... */
1228 sr_handle = shared_region->sr_mem_entry;
ea3f0419 1229 sr_mem_entry = (vm_named_entry_t) ip_get_kobject(sr_handle);
6d2010ae
A
1230 sr_map = sr_mem_entry->backing.map;
1231 sr_base_address = shared_region->sr_base_address;
1232 }
1233 /*
1234 * Undo the mappings we've established so far.
1235 */
f427ee49
A
1236 for (srfmp = &srf_mappings[0];
1237 srfmp <= srf_mappings_current;
1238 srfmp++) {
1239 mappings = srfmp->mappings;
1240 mappings_count = srfmp->mappings_count;
1241 if (srfmp == srf_mappings_current) {
1242 mappings_count = srf_current_mappings_count;
1243 }
6d2010ae 1244
f427ee49
A
1245 for (j = 0; j < mappings_count; j++) {
1246 kern_return_t kr2;
1247
1248 if (mappings[j].sms_size == 0) {
1249 /*
1250 * We didn't establish this
1251 * mapping, so nothing to undo.
1252 */
1253 continue;
1254 }
1255 SHARED_REGION_TRACE_INFO(
1256 ("shared_region: mapping[%d]: "
1257 "address:0x%016llx "
1258 "size:0x%016llx "
1259 "offset:0x%016llx "
1260 "maxprot:0x%x prot:0x%x: "
1261 "undoing...\n",
1262 j,
1263 (long long)mappings[j].sms_address,
1264 (long long)mappings[j].sms_size,
1265 (long long)mappings[j].sms_file_offset,
1266 mappings[j].sms_max_prot,
1267 mappings[j].sms_init_prot));
1268 kr2 = mach_vm_deallocate(
1269 sr_map,
1270 (mappings[j].sms_address -
1271 sr_base_address),
1272 mappings[j].sms_size);
1273 assert(kr2 == KERN_SUCCESS);
6d2010ae 1274 }
6d2010ae
A
1275 }
1276
6d2010ae
A
1277 if (reset_shared_region_state) {
1278 vm_shared_region_lock();
c3c9b80d 1279 assert(shared_region->sr_ref_count > 0);
6d2010ae
A
1280 assert(shared_region->sr_mapping_in_progress);
1281 /* we're done working on that shared region */
1282 shared_region->sr_mapping_in_progress = FALSE;
1283 thread_wakeup((event_t) &shared_region->sr_mapping_in_progress);
1284 vm_shared_region_unlock();
1285 reset_shared_region_state = FALSE;
1286 }
1287
1288 vm_shared_region_deallocate(shared_region);
1289}
1290
2d21ac55 1291/*
c3c9b80d
A
1292 * For now we only expect to see at most 4 regions to relocate/authenticate
1293 * per file. One that's RW VM_PROT_SLIDE and one VM_PROT_SLIDE | VM_PROT_NOAUTH.
1294 * And then RO VM_PROT_SLIDE and one VM_PROT_SLIDE | VM_PROT_NOAUTH.
2d21ac55 1295 */
c3c9b80d 1296#define VMSR_NUM_SLIDES 4
f427ee49
A
1297
1298/*
1299 * First part of vm_shared_region_map_file(). Split out to
1300 * avoid kernel stack overflow.
1301 */
1302__attribute__((noinline))
1303static kern_return_t
1304vm_shared_region_map_file_setup(
0a7de745 1305 vm_shared_region_t shared_region,
f427ee49
A
1306 int sr_file_mappings_count,
1307 struct _sr_file_mappings *sr_file_mappings,
1308 unsigned int *mappings_to_slide_cnt,
1309 struct shared_file_mapping_slide_np **mappings_to_slide,
1310 mach_vm_offset_t *slid_mappings,
1311 memory_object_control_t *slid_file_controls,
1312 mach_vm_offset_t *first_mapping,
1313 mach_vm_offset_t *file_first_mappings,
1314 mach_vm_offset_t *sfm_min_address,
1315 mach_vm_offset_t *sfm_max_address,
1316 vm_map_t *sr_map_ptr,
1317 vm_map_offset_t *lowest_unnestable_addr_ptr)
2d21ac55 1318{
f427ee49
A
1319 kern_return_t kr = KERN_SUCCESS;
1320 memory_object_control_t file_control;
0a7de745
A
1321 vm_object_t file_object;
1322 ipc_port_t sr_handle;
1323 vm_named_entry_t sr_mem_entry;
1324 vm_map_t sr_map;
1325 mach_vm_offset_t sr_base_address;
f427ee49 1326 unsigned int i = 0;
0a7de745
A
1327 mach_port_t map_port;
1328 vm_map_offset_t target_address;
1329 vm_object_t object;
1330 vm_object_size_t obj_size;
0a7de745
A
1331 vm_map_offset_t lowest_unnestable_addr = 0;
1332 vm_map_kernel_flags_t vmk_flags;
cb323159 1333 mach_vm_offset_t sfm_end;
f427ee49
A
1334 uint32_t mappings_count;
1335 struct shared_file_mapping_slide_np *mappings;
1336 struct _sr_file_mappings *srfmp;
1337 unsigned int current_file_index = 0;
2d21ac55
A
1338
1339 vm_shared_region_lock();
c3c9b80d 1340 assert(shared_region->sr_ref_count > 0);
2d21ac55 1341
2d21ac55
A
1342 /*
1343 * Make sure we handle only one mapping at a time in a given
1344 * shared region, to avoid race conditions. This should not
1345 * happen frequently...
1346 */
1347 while (shared_region->sr_mapping_in_progress) {
1348 /* wait for our turn... */
1349 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
0a7de745 1350 THREAD_UNINT);
2d21ac55 1351 }
0a7de745 1352 assert(!shared_region->sr_mapping_in_progress);
c3c9b80d 1353 assert(shared_region->sr_ref_count > 0);
2d21ac55
A
1354 /* let others know we're working in this shared region */
1355 shared_region->sr_mapping_in_progress = TRUE;
1356
1357 vm_shared_region_unlock();
1358
1359 /* no need to lock because this data is never modified... */
1360 sr_handle = shared_region->sr_mem_entry;
ea3f0419 1361 sr_mem_entry = (vm_named_entry_t) ip_get_kobject(sr_handle);
2d21ac55
A
1362 sr_map = sr_mem_entry->backing.map;
1363 sr_base_address = shared_region->sr_base_address;
1364
1365 SHARED_REGION_TRACE_DEBUG(
f427ee49
A
1366 ("shared_region: -> map(%p)\n",
1367 (void *)VM_KERNEL_ADDRPERM(shared_region)));
2d21ac55 1368
f427ee49
A
1369 mappings_count = 0;
1370 mappings = NULL;
1371 srfmp = NULL;
2d21ac55 1372
f427ee49
A
1373 /* process all the files to be mapped */
1374 for (srfmp = &sr_file_mappings[0];
1375 srfmp < &sr_file_mappings[sr_file_mappings_count];
1376 srfmp++) {
1377 mappings_count = srfmp->mappings_count;
1378 mappings = srfmp->mappings;
1379 file_control = srfmp->file_control;
5ba3f43e 1380
f427ee49
A
1381 if (mappings_count == 0) {
1382 /* no mappings here... */
1383 continue;
d9a64523
A
1384 }
1385
f427ee49
A
1386 /*
1387 * The code below can only correctly "slide" (perform relocations) for one
1388 * value of the slide amount. So if a file has a non-zero slide, it has to
1389 * match any previous value. A zero slide value is ok for things that are
1390 * just directly mapped.
1391 */
1392 if (shared_region->sr_slide == 0 && srfmp->slide != 0) {
1393 shared_region->sr_slide = srfmp->slide;
1394 } else if (shared_region->sr_slide != 0 &&
1395 srfmp->slide != 0 &&
1396 shared_region->sr_slide != srfmp->slide) {
1397 SHARED_REGION_TRACE_ERROR(
1398 ("shared_region: more than 1 non-zero slide value amount "
1399 "slide 1:0x%x slide 2:0x%x\n ",
1400 shared_region->sr_slide, srfmp->slide));
cb323159
A
1401 kr = KERN_INVALID_ARGUMENT;
1402 break;
1403 }
d9a64523 1404
f427ee49
A
1405#if __arm64__
1406 if ((shared_region->sr_64bit ||
1407 page_shift_user32 == SIXTEENK_PAGE_SHIFT) &&
1408 ((srfmp->slide & SIXTEENK_PAGE_MASK) != 0)) {
1409 printf("FOURK_COMPAT: %s: rejecting mis-aligned slide 0x%x\n",
1410 __FUNCTION__, srfmp->slide);
1411 kr = KERN_INVALID_ARGUMENT;
1412 break;
2d21ac55 1413 }
f427ee49 1414#endif /* __arm64__ */
0a7de745 1415
f427ee49
A
1416 /* get the VM object associated with the file to be mapped */
1417 file_object = memory_object_control_to_vm_object(file_control);
1418 assert(file_object);
1419
1420 /* establish the mappings for that file */
1421 for (i = 0; i < mappings_count; i++) {
1422 SHARED_REGION_TRACE_INFO(
1423 ("shared_region: mapping[%d]: "
1424 "address:0x%016llx size:0x%016llx offset:0x%016llx "
1425 "maxprot:0x%x prot:0x%x\n",
1426 i,
1427 (long long)mappings[i].sms_address,
1428 (long long)mappings[i].sms_size,
1429 (long long)mappings[i].sms_file_offset,
1430 mappings[i].sms_max_prot,
1431 mappings[i].sms_init_prot));
1432
1433 if (mappings[i].sms_address < *sfm_min_address) {
1434 *sfm_min_address = mappings[i].sms_address;
6d2010ae 1435 }
2d21ac55 1436
f427ee49
A
1437 if (os_add_overflow(mappings[i].sms_address,
1438 mappings[i].sms_size,
1439 &sfm_end) ||
1440 (vm_map_round_page(sfm_end, VM_MAP_PAGE_MASK(sr_map)) <
1441 mappings[i].sms_address)) {
1442 /* overflow */
1443 kr = KERN_INVALID_ARGUMENT;
1444 break;
1445 }
1446 if (sfm_end > *sfm_max_address) {
1447 *sfm_max_address = sfm_end;
1448 }
2d21ac55 1449
f427ee49
A
1450 if (mappings[i].sms_init_prot & VM_PROT_ZF) {
1451 /* zero-filled memory */
1452 map_port = MACH_PORT_NULL;
1453 } else {
1454 /* file-backed memory */
1455 __IGNORE_WCASTALIGN(map_port = (ipc_port_t) file_object->pager);
1456 }
5ba3f43e 1457
4a3eedf9 1458 /*
f427ee49 1459 * Remember which mappings need sliding.
4a3eedf9 1460 */
f427ee49
A
1461 if (mappings[i].sms_max_prot & VM_PROT_SLIDE) {
1462 if (*mappings_to_slide_cnt == VMSR_NUM_SLIDES) {
1463 SHARED_REGION_TRACE_INFO(
1464 ("shared_region: mapping[%d]: "
1465 "address:0x%016llx size:0x%016llx "
1466 "offset:0x%016llx "
1467 "maxprot:0x%x prot:0x%x "
1468 "too many mappings to slide...\n",
1469 i,
1470 (long long)mappings[i].sms_address,
1471 (long long)mappings[i].sms_size,
1472 (long long)mappings[i].sms_file_offset,
1473 mappings[i].sms_max_prot,
1474 mappings[i].sms_init_prot));
1475 } else {
1476 mappings_to_slide[*mappings_to_slide_cnt] = &mappings[i];
1477 *mappings_to_slide_cnt += 1;
1478 }
1479 }
1480
1481 /* mapping's address is relative to the shared region base */
1482 target_address = (vm_map_offset_t)(mappings[i].sms_address - sr_base_address);
1483
1484 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
1485 vmk_flags.vmkf_already = TRUE;
1486 /* no copy-on-read for mapped binaries */
1487 vmk_flags.vmkf_no_copy_on_read = 1;
1488
1489
1490 /* establish that mapping, OK if it's "already" there */
1491 if (map_port == MACH_PORT_NULL) {
1492 /*
1493 * We want to map some anonymous memory in a shared region.
1494 * We have to create the VM object now, so that it can be mapped "copy-on-write".
1495 */
1496 obj_size = vm_map_round_page(mappings[i].sms_size, VM_MAP_PAGE_MASK(sr_map));
1497 object = vm_object_allocate(obj_size);
1498 if (object == VM_OBJECT_NULL) {
1499 kr = KERN_RESOURCE_SHORTAGE;
1500 } else {
1501 kr = vm_map_enter(
1502 sr_map,
1503 &target_address,
1504 vm_map_round_page(mappings[i].sms_size,
1505 VM_MAP_PAGE_MASK(sr_map)),
1506 0,
1507 VM_FLAGS_FIXED,
1508 vmk_flags,
1509 VM_KERN_MEMORY_NONE,
1510 object,
1511 0,
1512 TRUE,
1513 mappings[i].sms_init_prot & VM_PROT_ALL,
1514 mappings[i].sms_max_prot & VM_PROT_ALL,
1515 VM_INHERIT_DEFAULT);
1516 }
4a3eedf9 1517 } else {
f427ee49
A
1518 object = VM_OBJECT_NULL; /* no anonymous memory here */
1519 kr = vm_map_enter_mem_object(
4a3eedf9
A
1520 sr_map,
1521 &target_address,
f427ee49 1522 vm_map_round_page(mappings[i].sms_size,
0a7de745 1523 VM_MAP_PAGE_MASK(sr_map)),
4a3eedf9 1524 0,
5ba3f43e
A
1525 VM_FLAGS_FIXED,
1526 vmk_flags,
1527 VM_KERN_MEMORY_NONE,
f427ee49
A
1528 map_port,
1529 mappings[i].sms_file_offset,
4a3eedf9 1530 TRUE,
f427ee49
A
1531 mappings[i].sms_init_prot & VM_PROT_ALL,
1532 mappings[i].sms_max_prot & VM_PROT_ALL,
4a3eedf9
A
1533 VM_INHERIT_DEFAULT);
1534 }
d9a64523 1535
f427ee49 1536 if (kr == KERN_SUCCESS) {
4a3eedf9 1537 /*
f427ee49
A
1538 * Record the first (chronologically) successful
1539 * mapping in this shared region.
1540 * We're protected by "sr_mapping_in_progress" here,
1541 * so no need to lock "shared_region".
4a3eedf9 1542 */
f427ee49
A
1543 assert(current_file_index < VMSR_NUM_SLIDES);
1544 if (file_first_mappings[current_file_index] == (mach_vm_offset_t) -1) {
1545 file_first_mappings[current_file_index] = target_address;
1546 }
1547
1548 if (*mappings_to_slide_cnt > 0 &&
1549 mappings_to_slide[*mappings_to_slide_cnt - 1] == &mappings[i]) {
1550 slid_mappings[*mappings_to_slide_cnt - 1] = target_address;
1551 slid_file_controls[*mappings_to_slide_cnt - 1] = file_control;
1552 }
1553
4a3eedf9 1554 /*
f427ee49
A
1555 * Record the lowest writable address in this
1556 * sub map, to log any unexpected unnesting below
1557 * that address (see log_unnest_badness()).
4a3eedf9 1558 */
f427ee49
A
1559 if ((mappings[i].sms_init_prot & VM_PROT_WRITE) &&
1560 sr_map->is_nested_map &&
1561 (lowest_unnestable_addr == 0 ||
1562 (target_address < lowest_unnestable_addr))) {
1563 lowest_unnestable_addr = target_address;
1564 }
4a3eedf9 1565 } else {
f427ee49
A
1566 if (map_port == MACH_PORT_NULL) {
1567 /*
1568 * Get rid of the VM object we just created
1569 * but failed to map.
1570 */
1571 vm_object_deallocate(object);
1572 object = VM_OBJECT_NULL;
1573 }
1574 if (kr == KERN_MEMORY_PRESENT) {
1575 /*
1576 * This exact mapping was already there:
1577 * that's fine.
1578 */
1579 SHARED_REGION_TRACE_INFO(
1580 ("shared_region: mapping[%d]: "
1581 "address:0x%016llx size:0x%016llx "
1582 "offset:0x%016llx "
1583 "maxprot:0x%x prot:0x%x "
1584 "already mapped...\n",
1585 i,
1586 (long long)mappings[i].sms_address,
1587 (long long)mappings[i].sms_size,
1588 (long long)mappings[i].sms_file_offset,
1589 mappings[i].sms_max_prot,
1590 mappings[i].sms_init_prot));
1591 /*
1592 * We didn't establish this mapping ourselves;
1593 * let's reset its size, so that we do not
1594 * attempt to undo it if an error occurs later.
1595 */
1596 mappings[i].sms_size = 0;
1597 kr = KERN_SUCCESS;
1598 } else {
1599 break;
1600 }
4a3eedf9 1601 }
4a3eedf9 1602 }
f427ee49
A
1603
1604 if (kr != KERN_SUCCESS) {
1605 break;
1606 }
1607
1608 ++current_file_index;
1609 }
1610
1611 if (file_first_mappings[0] != (mach_vm_offset_t)-1) {
1612 *first_mapping = file_first_mappings[0];
15129b1c
A
1613 }
1614
f427ee49 1615
cb323159
A
1616 if (kr != KERN_SUCCESS) {
1617 /* the last mapping we tried (mappings[i]) failed ! */
1618 assert(i < mappings_count);
1619 SHARED_REGION_TRACE_ERROR(
1620 ("shared_region: mapping[%d]: "
1621 "address:0x%016llx size:0x%016llx "
1622 "offset:0x%016llx "
1623 "maxprot:0x%x prot:0x%x failed 0x%x\n",
1624 i,
f427ee49
A
1625 (long long)mappings[i].sms_address,
1626 (long long)mappings[i].sms_size,
1627 (long long)mappings[i].sms_file_offset,
1628 mappings[i].sms_max_prot,
1629 mappings[i].sms_init_prot,
cb323159 1630 kr));
f427ee49
A
1631
1632 /*
1633 * Respect the design of vm_shared_region_undo_mappings
1634 * as we are holding the sr_mapping_in_progress == true here.
1635 * So don't allow sr_map == NULL otherwise vm_shared_region_undo_mappings
1636 * will be blocked at waiting sr_mapping_in_progress to be false.
1637 */
1638 assert(sr_map != NULL);
cb323159 1639 /* undo all the previous mappings */
f427ee49
A
1640 vm_shared_region_undo_mappings(sr_map, sr_base_address, sr_file_mappings, srfmp, i);
1641 return kr;
1642 }
1643
1644 *lowest_unnestable_addr_ptr = lowest_unnestable_addr;
1645 *sr_map_ptr = sr_map;
1646 return KERN_SUCCESS;
1647}
1648
1649/* forwared declaration */
1650__attribute__((noinline))
1651static void
1652vm_shared_region_map_file_final(
1653 vm_shared_region_t shared_region,
1654 vm_map_t sr_map,
1655 mach_vm_offset_t sfm_min_address,
1656 mach_vm_offset_t sfm_max_address,
1657 mach_vm_offset_t *file_first_mappings);
1658
1659/*
1660 * Establish some mappings of a file in the shared region.
1661 * This is used by "dyld" via the shared_region_map_np() system call
1662 * to populate the shared region with the appropriate shared cache.
1663 *
1664 * One could also call it several times to incrementally load several
1665 * libraries, as long as they do not overlap.
1666 * It will return KERN_SUCCESS if the mappings were successfully established
1667 * or if they were already established identically by another process.
1668 */
1669__attribute__((noinline))
1670kern_return_t
1671vm_shared_region_map_file(
1672 vm_shared_region_t shared_region,
f427ee49
A
1673 int sr_file_mappings_count,
1674 struct _sr_file_mappings *sr_file_mappings)
1675{
1676 kern_return_t kr = KERN_SUCCESS;
1677 unsigned int i;
1678 unsigned int mappings_to_slide_cnt = 0;
1679 struct shared_file_mapping_slide_np *mappings_to_slide[VMSR_NUM_SLIDES] = {};
1680 mach_vm_offset_t slid_mappings[VMSR_NUM_SLIDES];
1681 memory_object_control_t slid_file_controls[VMSR_NUM_SLIDES];
1682 mach_vm_offset_t first_mapping = (mach_vm_offset_t)-1;
1683 mach_vm_offset_t sfm_min_address = (mach_vm_offset_t)-1;
1684 mach_vm_offset_t sfm_max_address = 0;
1685 vm_map_t sr_map = NULL;
1686 vm_map_offset_t lowest_unnestable_addr = 0;
c3c9b80d
A
1687 mach_vm_offset_t file_first_mappings[VMSR_NUM_SLIDES];
1688 for (i = 0; i < VMSR_NUM_SLIDES; ++i) {
1689 file_first_mappings[i] = (mach_vm_offset_t) -1;
1690 }
f427ee49 1691
2a1bd2d3 1692 kr = vm_shared_region_map_file_setup(shared_region, sr_file_mappings_count, sr_file_mappings,
f427ee49
A
1693 &mappings_to_slide_cnt, &mappings_to_slide[0], slid_mappings, slid_file_controls,
1694 &first_mapping, &file_first_mappings[0],
1695 &sfm_min_address, &sfm_max_address, &sr_map, &lowest_unnestable_addr);
1696 if (kr != KERN_SUCCESS) {
1697 vm_shared_region_lock();
1698 goto done;
1699 }
1700
1701 /*
1702 * The call above installed direct mappings to the shared cache file.
1703 * Now we go back and overwrite the mappings that need relocation
1704 * with a special shared region pager.
1705 */
1706 for (i = 0; i < mappings_to_slide_cnt; ++i) {
1707 kr = vm_shared_region_slide(shared_region->sr_slide,
1708 mappings_to_slide[i]->sms_file_offset,
1709 mappings_to_slide[i]->sms_size,
1710 mappings_to_slide[i]->sms_slide_start,
1711 mappings_to_slide[i]->sms_slide_size,
1712 slid_mappings[i],
1713 slid_file_controls[i],
1714 mappings_to_slide[i]->sms_max_prot);
0a7de745 1715 if (kr != KERN_SUCCESS) {
15129b1c
A
1716 SHARED_REGION_TRACE_ERROR(
1717 ("shared_region: region_slide("
0a7de745
A
1718 "slide:0x%x start:0x%016llx "
1719 "size:0x%016llx) failed 0x%x\n",
f427ee49
A
1720 shared_region->sr_slide,
1721 (long long)mappings_to_slide[i]->sms_slide_start,
1722 (long long)mappings_to_slide[i]->sms_slide_size,
0a7de745 1723 kr));
f427ee49
A
1724 vm_shared_region_lock();
1725 goto done;
2d21ac55
A
1726 }
1727 }
1728
f427ee49
A
1729 assert(kr == KERN_SUCCESS);
1730
1731 /* adjust the map's "lowest_unnestable_start" */
1732 lowest_unnestable_addr &= ~(pmap_shared_region_size_min(sr_map->pmap) - 1);
1733 if (lowest_unnestable_addr != sr_map->lowest_unnestable_start) {
1734 vm_map_lock(sr_map);
1735 sr_map->lowest_unnestable_start = lowest_unnestable_addr;
1736 vm_map_unlock(sr_map);
39037602
A
1737 }
1738
2d21ac55 1739 vm_shared_region_lock();
c3c9b80d 1740 assert(shared_region->sr_ref_count > 0);
2d21ac55 1741 assert(shared_region->sr_mapping_in_progress);
d9a64523 1742
0a7de745 1743 /* set "sr_first_mapping"; dyld uses it to validate the shared cache */
f427ee49 1744 if (shared_region->sr_first_mapping == (mach_vm_offset_t) -1) {
15129b1c
A
1745 shared_region->sr_first_mapping = first_mapping;
1746 }
5ba3f43e 1747
f427ee49
A
1748 vm_shared_region_map_file_final(shared_region, sr_map, sfm_min_address, sfm_max_address,
1749 &file_first_mappings[0]);
1750
1751done:
1752 /*
1753 * We're done working on that shared region.
1754 * Wake up any waiting threads.
1755 */
1756 shared_region->sr_mapping_in_progress = FALSE;
1757 thread_wakeup((event_t) &shared_region->sr_mapping_in_progress);
1758 vm_shared_region_unlock();
1759
1760#if __has_feature(ptrauth_calls)
1761 if (kr == KERN_SUCCESS) {
1762 /*
1763 * Since authenticated mappings were just added to the shared region,
1764 * go back and remap them into private mappings for this task.
1765 */
1766 kr = vm_shared_region_auth_remap(shared_region);
1767 }
1768#endif /* __has_feature(ptrauth_calls) */
1769
c3c9b80d
A
1770 /* Cache shared region info needed for telemetry in the task */
1771 task_t task;
1772 if (kr == KERN_SUCCESS && (task = current_task())->task_shared_region_slide == -1) {
1773 mach_vm_offset_t start_address;
1774 (void)vm_shared_region_start_address(shared_region, &start_address, task);
1775 }
1776
f427ee49
A
1777 SHARED_REGION_TRACE_DEBUG(
1778 ("shared_region: map(%p) <- 0x%x \n",
1779 (void *)VM_KERNEL_ADDRPERM(shared_region), kr));
1780 return kr;
1781}
1782
1783/*
1784 * Final part of vm_shared_region_map_file().
1785 * Kept in separate function to avoid blowing out the stack.
1786 */
1787__attribute__((noinline))
1788static void
1789vm_shared_region_map_file_final(
1790 vm_shared_region_t shared_region,
1791 vm_map_t sr_map,
1792 mach_vm_offset_t sfm_min_address,
1793 mach_vm_offset_t sfm_max_address,
1794 __unused mach_vm_offset_t *file_first_mappings)
1795{
1796 struct _dyld_cache_header sr_cache_header;
1797 int error;
1798 size_t image_array_length;
1799 struct _dyld_cache_image_text_info *sr_image_layout;
c3c9b80d 1800 boolean_t locally_built = FALSE;
f427ee49
A
1801
1802
d9a64523
A
1803 /*
1804 * copy in the shared region UUID to the shared region structure.
1805 * we do this indirectly by first copying in the shared cache header
1806 * and then copying the UUID from there because we'll need to look
1807 * at other content from the shared cache header.
1808 */
f427ee49
A
1809 if (!shared_region->sr_uuid_copied) {
1810 error = copyin((user_addr_t)(shared_region->sr_base_address + shared_region->sr_first_mapping),
0a7de745
A
1811 (char *)&sr_cache_header,
1812 sizeof(sr_cache_header));
d9a64523
A
1813 if (error == 0) {
1814 memcpy(&shared_region->sr_uuid, &sr_cache_header.uuid, sizeof(shared_region->sr_uuid));
5ba3f43e 1815 shared_region->sr_uuid_copied = TRUE;
c3c9b80d 1816 locally_built = sr_cache_header.locallyBuiltCache;
d9a64523 1817 } else {
5ba3f43e 1818#if DEVELOPMENT || DEBUG
d9a64523 1819 panic("shared_region: copyin shared_cache_header(sr_base_addr:0x%016llx sr_first_mapping:0x%016llx "
0a7de745
A
1820 "offset:0 size:0x%016llx) failed with %d\n",
1821 (long long)shared_region->sr_base_address,
1822 (long long)shared_region->sr_first_mapping,
1823 (long long)sizeof(sr_cache_header),
1824 error);
5ba3f43e
A
1825#endif /* DEVELOPMENT || DEBUG */
1826 shared_region->sr_uuid_copied = FALSE;
0a7de745 1827 }
5ba3f43e
A
1828 }
1829
d9a64523 1830 /*
c3c9b80d
A
1831 * We save a pointer to the shared cache mapped by the "init task", i.e. launchd. This is used by
1832 * the stackshot code to reduce output size in the common case that everything maps the same shared cache.
1833 * One gotcha is that "userspace reboots" can occur which can cause a new shared region to be the primary
1834 * region. In that case, launchd re-exec's itself, so we may go through this path multiple times. We
1835 * let the most recent one win.
1836 *
1837 * Check whether the shared cache is a custom built one and copy in the shared cache layout accordingly.
d9a64523 1838 */
c3c9b80d 1839 bool is_init_task = (task_pid(current_task()) == 1);
d9a64523
A
1840 if (shared_region->sr_uuid_copied && is_init_task) {
1841 /* Copy in the shared cache layout if we're running with a locally built shared cache */
c3c9b80d 1842 if (locally_built) {
d9a64523 1843 KDBG((MACHDBG_CODE(DBG_MACH_SHAREDREGION, PROCESS_SHARED_CACHE_LAYOUT)) | DBG_FUNC_START);
f427ee49
A
1844 image_array_length = (size_t)(sr_cache_header.imagesTextCount * sizeof(struct _dyld_cache_image_text_info));
1845 sr_image_layout = kheap_alloc(KHEAP_DATA_BUFFERS, image_array_length, Z_WAITOK);
1846 error = copyin((user_addr_t)(shared_region->sr_base_address + shared_region->sr_first_mapping +
0a7de745 1847 sr_cache_header.imagesTextOffset), (char *)sr_image_layout, image_array_length);
d9a64523 1848 if (error == 0) {
c3c9b80d
A
1849 if (sr_cache_header.imagesTextCount >= UINT32_MAX) {
1850 panic("shared_region: sr_cache_header.imagesTextCount >= UINT32_MAX");
1851 }
f427ee49 1852 shared_region->sr_images = kalloc((vm_size_t)(sr_cache_header.imagesTextCount * sizeof(struct dyld_uuid_info_64)));
d9a64523
A
1853 for (size_t index = 0; index < sr_cache_header.imagesTextCount; index++) {
1854 memcpy((char *)&shared_region->sr_images[index].imageUUID, (char *)&sr_image_layout[index].uuid,
0a7de745 1855 sizeof(shared_region->sr_images[index].imageUUID));
d9a64523
A
1856 shared_region->sr_images[index].imageLoadAddress = sr_image_layout[index].loadAddress;
1857 }
1858
d9a64523
A
1859 shared_region->sr_images_count = (uint32_t) sr_cache_header.imagesTextCount;
1860 } else {
1861#if DEVELOPMENT || DEBUG
1862 panic("shared_region: copyin shared_cache_layout(sr_base_addr:0x%016llx sr_first_mapping:0x%016llx "
0a7de745
A
1863 "offset:0x%016llx size:0x%016llx) failed with %d\n",
1864 (long long)shared_region->sr_base_address,
1865 (long long)shared_region->sr_first_mapping,
1866 (long long)sr_cache_header.imagesTextOffset,
1867 (long long)image_array_length,
1868 error);
d9a64523
A
1869#endif /* DEVELOPMENT || DEBUG */
1870 }
1871 KDBG((MACHDBG_CODE(DBG_MACH_SHAREDREGION, PROCESS_SHARED_CACHE_LAYOUT)) | DBG_FUNC_END, shared_region->sr_images_count);
f427ee49 1872 kheap_free(KHEAP_DATA_BUFFERS, sr_image_layout, image_array_length);
d9a64523
A
1873 sr_image_layout = NULL;
1874 }
c3c9b80d 1875 primary_system_shared_region = shared_region;
d9a64523
A
1876 }
1877
f427ee49
A
1878 /*
1879 * If we succeeded, we know the bounds of the shared region.
1880 * Trim our pmaps to only cover this range (if applicable to
1881 * this platform).
1882 */
1883 if (VM_MAP_PAGE_SHIFT(current_map()) == VM_MAP_PAGE_SHIFT(sr_map)) {
1884 pmap_trim(current_map()->pmap, sr_map->pmap, sfm_min_address, sfm_max_address - sfm_min_address);
d9a64523 1885 }
2d21ac55
A
1886}
1887
d9a64523
A
1888/*
1889 * Retrieve a task's shared region and grab an extra reference to
1890 * make sure it doesn't disappear while the caller is using it.
1891 * The caller is responsible for consuming that extra reference if
1892 * necessary.
1893 *
1894 * This also tries to trim the pmap for the shared region.
1895 */
1896vm_shared_region_t
1897vm_shared_region_trim_and_get(task_t task)
1898{
1899 vm_shared_region_t shared_region;
1900 ipc_port_t sr_handle;
1901 vm_named_entry_t sr_mem_entry;
1902 vm_map_t sr_map;
1903
1904 /* Get the shared region and the map. */
1905 shared_region = vm_shared_region_get(task);
1906 if (shared_region == NULL) {
1907 return NULL;
1908 }
1909
1910 sr_handle = shared_region->sr_mem_entry;
ea3f0419 1911 sr_mem_entry = (vm_named_entry_t) ip_get_kobject(sr_handle);
d9a64523
A
1912 sr_map = sr_mem_entry->backing.map;
1913
1914 /* Trim the pmap if possible. */
f427ee49
A
1915 if (VM_MAP_PAGE_SHIFT(task->map) == VM_MAP_PAGE_SHIFT(sr_map)) {
1916 pmap_trim(task->map->pmap, sr_map->pmap, 0, 0);
1917 }
d9a64523
A
1918
1919 return shared_region;
1920}
1921
2d21ac55
A
1922/*
1923 * Enter the appropriate shared region into "map" for "task".
1924 * This involves looking up the shared region (and possibly creating a new
1925 * one) for the desired environment, then mapping the VM sub map into the
1926 * task's VM "map", with the appropriate level of pmap-nesting.
1927 */
1928kern_return_t
1929vm_shared_region_enter(
0a7de745
A
1930 struct _vm_map *map,
1931 struct task *task,
1932 boolean_t is_64bit,
1933 void *fsroot,
1934 cpu_type_t cpu,
f427ee49
A
1935 cpu_subtype_t cpu_subtype,
1936 boolean_t reslide)
2d21ac55 1937{
0a7de745
A
1938 kern_return_t kr;
1939 vm_shared_region_t shared_region;
1940 vm_map_offset_t sr_address, sr_offset, target_address;
1941 vm_map_size_t sr_size, mapping_size;
1942 vm_map_offset_t sr_pmap_nesting_start;
1943 vm_map_size_t sr_pmap_nesting_size;
1944 ipc_port_t sr_handle;
1945 vm_prot_t cur_prot, max_prot;
2d21ac55
A
1946
1947 SHARED_REGION_TRACE_DEBUG(
1948 ("shared_region: -> "
0a7de745
A
1949 "enter(map=%p,task=%p,root=%p,cpu=<%d,%d>,64bit=%d)\n",
1950 (void *)VM_KERNEL_ADDRPERM(map),
1951 (void *)VM_KERNEL_ADDRPERM(task),
1952 (void *)VM_KERNEL_ADDRPERM(fsroot),
1953 cpu, cpu_subtype, is_64bit));
2d21ac55
A
1954
1955 /* lookup (create if needed) the shared region for this environment */
f427ee49 1956 shared_region = vm_shared_region_lookup(fsroot, cpu, cpu_subtype, is_64bit, reslide);
2d21ac55
A
1957 if (shared_region == NULL) {
1958 /* this should not happen ! */
1959 SHARED_REGION_TRACE_ERROR(
1960 ("shared_region: -> "
f427ee49 1961 "enter(map=%p,task=%p,root=%p,cpu=<%d,%d>,64bit=%d,reslide=%d): "
0a7de745
A
1962 "lookup failed !\n",
1963 (void *)VM_KERNEL_ADDRPERM(map),
1964 (void *)VM_KERNEL_ADDRPERM(task),
1965 (void *)VM_KERNEL_ADDRPERM(fsroot),
f427ee49 1966 cpu, cpu_subtype, is_64bit, reslide));
2d21ac55
A
1967 //panic("shared_region_enter: lookup failed\n");
1968 return KERN_FAILURE;
1969 }
0a7de745 1970
2d21ac55
A
1971 kr = KERN_SUCCESS;
1972 /* no need to lock since this data is never modified */
f427ee49
A
1973 sr_address = (vm_map_offset_t)shared_region->sr_base_address;
1974 sr_size = (vm_map_size_t)shared_region->sr_size;
2d21ac55 1975 sr_handle = shared_region->sr_mem_entry;
f427ee49
A
1976 sr_pmap_nesting_start = (vm_map_offset_t)shared_region->sr_pmap_nesting_start;
1977 sr_pmap_nesting_size = (vm_map_size_t)shared_region->sr_pmap_nesting_size;
2d21ac55 1978
39037602 1979 cur_prot = VM_PROT_READ;
f427ee49
A
1980 if (VM_MAP_POLICY_WRITABLE_SHARED_REGION(map)) {
1981 /*
1982 * XXX BINARY COMPATIBILITY
1983 * java6 apparently needs to modify some code in the
1984 * dyld shared cache and needs to be allowed to add
1985 * write access...
1986 */
1987 max_prot = VM_PROT_ALL;
1988 } else {
1989 max_prot = VM_PROT_READ;
1990 }
1991
2d21ac55
A
1992 /*
1993 * Start mapping the shared region's VM sub map into the task's VM map.
1994 */
1995 sr_offset = 0;
1996
1997 if (sr_pmap_nesting_start > sr_address) {
1998 /* we need to map a range without pmap-nesting first */
1999 target_address = sr_address;
2000 mapping_size = sr_pmap_nesting_start - sr_address;
2001 kr = vm_map_enter_mem_object(
2002 map,
2003 &target_address,
2004 mapping_size,
2005 0,
2006 VM_FLAGS_FIXED,
5ba3f43e
A
2007 VM_MAP_KERNEL_FLAGS_NONE,
2008 VM_KERN_MEMORY_NONE,
2d21ac55
A
2009 sr_handle,
2010 sr_offset,
2011 TRUE,
39037602
A
2012 cur_prot,
2013 max_prot,
2d21ac55
A
2014 VM_INHERIT_SHARE);
2015 if (kr != KERN_SUCCESS) {
2016 SHARED_REGION_TRACE_ERROR(
d9a64523 2017 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2018 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2019 (void *)VM_KERNEL_ADDRPERM(map),
2020 (void *)VM_KERNEL_ADDRPERM(task),
2021 (void *)VM_KERNEL_ADDRPERM(fsroot),
2022 cpu, cpu_subtype, is_64bit,
2023 (long long)target_address,
2024 (long long)mapping_size,
2025 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2026 goto done;
2027 }
2028 SHARED_REGION_TRACE_DEBUG(
d9a64523 2029 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2030 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2031 (void *)VM_KERNEL_ADDRPERM(map),
2032 (void *)VM_KERNEL_ADDRPERM(task),
2033 (void *)VM_KERNEL_ADDRPERM(fsroot),
2034 cpu, cpu_subtype, is_64bit,
2035 (long long)target_address, (long long)mapping_size,
2036 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2037 sr_offset += mapping_size;
2038 sr_size -= mapping_size;
2039 }
2040 /*
2041 * We may need to map several pmap-nested portions, due to platform
2042 * specific restrictions on pmap nesting.
cb323159 2043 * The pmap-nesting is triggered by the "vmkf_nested_pmap" flag...
2d21ac55
A
2044 */
2045 for (;
0a7de745
A
2046 sr_pmap_nesting_size > 0;
2047 sr_offset += mapping_size,
2048 sr_size -= mapping_size,
2049 sr_pmap_nesting_size -= mapping_size) {
cb323159
A
2050 vm_map_kernel_flags_t vmk_flags;
2051
2d21ac55
A
2052 target_address = sr_address + sr_offset;
2053 mapping_size = sr_pmap_nesting_size;
f427ee49
A
2054 if (mapping_size > pmap_nesting_size_max(map->pmap)) {
2055 mapping_size = (vm_map_offset_t) pmap_nesting_size_max(map->pmap);
2d21ac55 2056 }
cb323159
A
2057 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
2058 vmk_flags.vmkf_nested_pmap = TRUE;
2d21ac55
A
2059 kr = vm_map_enter_mem_object(
2060 map,
2061 &target_address,
2062 mapping_size,
2063 0,
5ba3f43e 2064 VM_FLAGS_FIXED,
cb323159 2065 vmk_flags,
5ba3f43e 2066 VM_MEMORY_SHARED_PMAP,
2d21ac55
A
2067 sr_handle,
2068 sr_offset,
2069 TRUE,
39037602
A
2070 cur_prot,
2071 max_prot,
2d21ac55
A
2072 VM_INHERIT_SHARE);
2073 if (kr != KERN_SUCCESS) {
2074 SHARED_REGION_TRACE_ERROR(
d9a64523 2075 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2076 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2077 (void *)VM_KERNEL_ADDRPERM(map),
2078 (void *)VM_KERNEL_ADDRPERM(task),
2079 (void *)VM_KERNEL_ADDRPERM(fsroot),
2080 cpu, cpu_subtype, is_64bit,
2081 (long long)target_address,
2082 (long long)mapping_size,
2083 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2084 goto done;
2085 }
2086 SHARED_REGION_TRACE_DEBUG(
d9a64523 2087 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2088 "nested vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2089 (void *)VM_KERNEL_ADDRPERM(map),
2090 (void *)VM_KERNEL_ADDRPERM(task),
2091 (void *)VM_KERNEL_ADDRPERM(fsroot),
2092 cpu, cpu_subtype, is_64bit,
2093 (long long)target_address, (long long)mapping_size,
2094 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2095 }
2096 if (sr_size > 0) {
2097 /* and there's some left to be mapped without pmap-nesting */
2098 target_address = sr_address + sr_offset;
2099 mapping_size = sr_size;
2100 kr = vm_map_enter_mem_object(
2101 map,
2102 &target_address,
2103 mapping_size,
2104 0,
2105 VM_FLAGS_FIXED,
5ba3f43e
A
2106 VM_MAP_KERNEL_FLAGS_NONE,
2107 VM_KERN_MEMORY_NONE,
2d21ac55
A
2108 sr_handle,
2109 sr_offset,
2110 TRUE,
39037602
A
2111 cur_prot,
2112 max_prot,
2d21ac55
A
2113 VM_INHERIT_SHARE);
2114 if (kr != KERN_SUCCESS) {
2115 SHARED_REGION_TRACE_ERROR(
d9a64523 2116 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2117 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2118 (void *)VM_KERNEL_ADDRPERM(map),
2119 (void *)VM_KERNEL_ADDRPERM(task),
2120 (void *)VM_KERNEL_ADDRPERM(fsroot),
2121 cpu, cpu_subtype, is_64bit,
2122 (long long)target_address,
2123 (long long)mapping_size,
2124 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2125 goto done;
2126 }
2127 SHARED_REGION_TRACE_DEBUG(
d9a64523 2128 ("shared_region: enter(%p,%p,%p,%d,%d,%d): "
0a7de745
A
2129 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
2130 (void *)VM_KERNEL_ADDRPERM(map),
2131 (void *)VM_KERNEL_ADDRPERM(task),
2132 (void *)VM_KERNEL_ADDRPERM(fsroot),
2133 cpu, cpu_subtype, is_64bit,
2134 (long long)target_address, (long long)mapping_size,
2135 (void *)VM_KERNEL_ADDRPERM(sr_handle), kr));
2d21ac55
A
2136 sr_offset += mapping_size;
2137 sr_size -= mapping_size;
2138 }
2139 assert(sr_size == 0);
2140
2141done:
d9a64523
A
2142 if (kr == KERN_SUCCESS) {
2143 /* let the task use that shared region */
2144 vm_shared_region_set(task, shared_region);
2145 } else {
2146 /* drop our reference since we're not using it */
2147 vm_shared_region_deallocate(shared_region);
2148 vm_shared_region_set(task, NULL);
2149 }
2150
2d21ac55 2151 SHARED_REGION_TRACE_DEBUG(
d9a64523 2152 ("shared_region: enter(%p,%p,%p,%d,%d,%d) <- 0x%x\n",
0a7de745
A
2153 (void *)VM_KERNEL_ADDRPERM(map),
2154 (void *)VM_KERNEL_ADDRPERM(task),
2155 (void *)VM_KERNEL_ADDRPERM(fsroot),
f427ee49
A
2156 cpu, cpu_subtype, is_64bit,
2157 kr));
2d21ac55
A
2158 return kr;
2159}
2160
0a7de745
A
2161#define SANE_SLIDE_INFO_SIZE (2560*1024) /*Can be changed if needed*/
2162struct vm_shared_region_slide_info slide_info;
6d2010ae
A
2163
2164kern_return_t
0a7de745 2165vm_shared_region_sliding_valid(uint32_t slide)
39236c6e 2166{
6d2010ae 2167 kern_return_t kr = KERN_SUCCESS;
39236c6e 2168 vm_shared_region_t sr = vm_shared_region_get(current_task());
6d2010ae 2169
39236c6e
A
2170 /* No region yet? we're fine. */
2171 if (sr == NULL) {
2172 return kr;
2173 }
2174
f427ee49
A
2175 if (sr->sr_slide != 0 && slide != 0) {
2176 if (slide == sr->sr_slide) {
6d2010ae
A
2177 /*
2178 * Request for sliding when we've
2179 * already done it with exactly the
2180 * same slide value before.
2181 * This isn't wrong technically but
2182 * we don't want to slide again and
2183 * so we return this value.
2184 */
0a7de745 2185 kr = KERN_INVALID_ARGUMENT;
f427ee49
A
2186 } else {
2187 printf("Mismatched shared region slide\n");
2188 kr = KERN_FAILURE;
6d2010ae
A
2189 }
2190 }
39236c6e 2191 vm_shared_region_deallocate(sr);
6d2010ae
A
2192 return kr;
2193}
2194
f427ee49
A
2195/*
2196 * Actually create (really overwrite) the mapping to part of the shared cache which
2197 * undergoes relocation. This routine reads in the relocation info from dyld and
2198 * verifies it. It then creates a (or finds a matching) shared region pager which
2199 * handles the actual modification of the page contents and installs the mapping
2200 * using that pager.
2201 */
6d2010ae 2202kern_return_t
d9a64523 2203vm_shared_region_slide_mapping(
0a7de745 2204 vm_shared_region_t sr,
f427ee49 2205 user_addr_t slide_info_addr,
0a7de745
A
2206 mach_vm_size_t slide_info_size,
2207 mach_vm_offset_t start,
2208 mach_vm_size_t size,
2209 mach_vm_offset_t slid_mapping,
2210 uint32_t slide,
f427ee49
A
2211 memory_object_control_t sr_file_control,
2212 vm_prot_t prot)
6d2010ae 2213{
0a7de745 2214 kern_return_t kr;
f427ee49
A
2215 vm_object_t object = VM_OBJECT_NULL;
2216 vm_shared_region_slide_info_t si = NULL;
2217 vm_map_entry_t tmp_entry = VM_MAP_ENTRY_NULL;
0a7de745 2218 struct vm_map_entry tmp_entry_store;
f427ee49 2219 memory_object_t sr_pager = MEMORY_OBJECT_NULL;
0a7de745
A
2220 vm_map_t sr_map;
2221 int vm_flags;
2222 vm_map_kernel_flags_t vmk_flags;
2223 vm_map_offset_t map_addr;
f427ee49
A
2224 void *slide_info_entry = NULL;
2225 int error;
6d2010ae 2226
39236c6e 2227 assert(sr->sr_slide_in_progress);
6d2010ae 2228
d9a64523
A
2229 if (sr_file_control == MEMORY_OBJECT_CONTROL_NULL) {
2230 return KERN_INVALID_ARGUMENT;
2231 }
f427ee49
A
2232
2233 /*
2234 * Copy in and verify the relocation information.
2235 */
2236 if (slide_info_size < MIN_SLIDE_INFO_SIZE) {
2237 printf("Slide_info_size too small: %lx\n", (uintptr_t)slide_info_size);
2238 return KERN_FAILURE;
2239 }
6d2010ae 2240 if (slide_info_size > SANE_SLIDE_INFO_SIZE) {
316670eb 2241 printf("Slide_info_size too large: %lx\n", (uintptr_t)slide_info_size);
d9a64523 2242 return KERN_FAILURE;
6d2010ae
A
2243 }
2244
f427ee49
A
2245 slide_info_entry = kheap_alloc(KHEAP_DATA_BUFFERS, (vm_size_t)slide_info_size, Z_WAITOK);
2246 if (slide_info_entry == NULL) {
2247 return KERN_RESOURCE_SHORTAGE;
2248 }
2249 error = copyin(slide_info_addr, slide_info_entry, (size_t)slide_info_size);
2250 if (error) {
2251 printf("copyin of slide_info failed\n");
2252 kr = KERN_INVALID_ADDRESS;
2253 goto done;
2254 }
2255
2256 if ((kr = vm_shared_region_slide_sanity_check(slide_info_entry, slide_info_size)) != KERN_SUCCESS) {
2257 printf("Sanity Check failed for slide_info\n");
2258 goto done;
39236c6e
A
2259 }
2260
f427ee49
A
2261 /*
2262 * Allocate and fill in a vm_shared_region_slide_info.
2263 * This will either be used by a new pager, or used to find
2264 * a pre-existing matching pager.
2265 */
d9a64523
A
2266 object = memory_object_control_to_vm_object(sr_file_control);
2267 if (object == VM_OBJECT_NULL || object->internal) {
2268 object = VM_OBJECT_NULL;
2269 kr = KERN_INVALID_ADDRESS;
2270 goto done;
2271 }
6d2010ae 2272
f427ee49
A
2273 si = kalloc(sizeof(*si));
2274 if (si == NULL) {
2275 kr = KERN_RESOURCE_SHORTAGE;
2276 goto done;
2277 }
d9a64523 2278 vm_object_lock(object);
f427ee49 2279
0a7de745 2280 vm_object_reference_locked(object); /* for si->slide_object */
d9a64523
A
2281 object->object_is_shared_cache = TRUE;
2282 vm_object_unlock(object);
6d2010ae 2283
f427ee49
A
2284 si->si_slide_info_entry = slide_info_entry;
2285 si->si_slide_info_size = slide_info_size;
d9a64523
A
2286
2287 assert(slid_mapping != (mach_vm_offset_t) -1);
f427ee49
A
2288 si->si_slid_address = slid_mapping + sr->sr_base_address;
2289 si->si_slide_object = object;
2290 si->si_start = start;
2291 si->si_end = si->si_start + size;
2292 si->si_slide = slide;
2293#if __has_feature(ptrauth_calls)
2294 /*
2295 * If there is authenticated pointer data in this slid mapping,
2296 * then just add the information needed to create new pagers for
2297 * different shared_region_id's later.
2298 */
cb323159 2299 if (sr->sr_cpu_type == CPU_TYPE_ARM64 &&
f427ee49
A
2300 sr->sr_cpu_subtype == CPU_SUBTYPE_ARM64E &&
2301 !(prot & VM_PROT_NOAUTH)) {
2302 if (sr->sr_num_auth_section == NUM_SR_AUTH_SECTIONS) {
2303 printf("Too many auth/private sections for shared region!!\n");
2304 kr = KERN_INVALID_ARGUMENT;
2305 goto done;
2306 }
cb323159 2307 si->si_ptrauth = TRUE;
f427ee49
A
2308 sr->sr_auth_section[sr->sr_num_auth_section++] = si;
2309 /*
2310 * Remember the shared region, since that's where we'll
2311 * stash this info for all auth pagers to share. Each pager
2312 * will need to take a reference to it.
2313 */
2314 si->si_shared_region = sr;
2315 kr = KERN_SUCCESS;
2316 goto done;
cb323159 2317 }
f427ee49
A
2318 si->si_shared_region = NULL;
2319 si->si_ptrauth = FALSE;
2320#else /* __has_feature(ptrauth_calls) */
2321 (void)prot; /* silence unused warning */
2322#endif /* __has_feature(ptrauth_calls) */
d9a64523 2323
f427ee49
A
2324 /*
2325 * find the pre-existing shared region's map entry to slide
2326 */
d9a64523 2327 sr_map = vm_shared_region_vm_map(sr);
f427ee49
A
2328 kr = find_mapping_to_slide(sr_map, (vm_map_address_t)slid_mapping, &tmp_entry_store);
2329 if (kr != KERN_SUCCESS) {
d9a64523
A
2330 goto done;
2331 }
f427ee49
A
2332 tmp_entry = &tmp_entry_store;
2333
d9a64523 2334 /*
f427ee49 2335 * The object must exactly cover the region to slide.
d9a64523 2336 */
f427ee49
A
2337 assert(VME_OFFSET(tmp_entry) == start);
2338 assert(tmp_entry->vme_end - tmp_entry->vme_start == size);
d9a64523
A
2339
2340 /* create a "shared_region" sliding pager */
f427ee49
A
2341 sr_pager = shared_region_pager_setup(VME_OBJECT(tmp_entry), VME_OFFSET(tmp_entry), si, 0);
2342 if (sr_pager == MEMORY_OBJECT_NULL) {
d9a64523
A
2343 kr = KERN_RESOURCE_SHORTAGE;
2344 goto done;
6d2010ae 2345 }
39236c6e 2346
d9a64523
A
2347 /* map that pager over the portion of the mapping that needs sliding */
2348 vm_flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
2349 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
2350 vmk_flags.vmkf_overwrite_immutable = TRUE;
2351 map_addr = tmp_entry->vme_start;
2352 kr = vm_map_enter_mem_object(sr_map,
0a7de745 2353 &map_addr,
f427ee49 2354 (tmp_entry->vme_end - tmp_entry->vme_start),
0a7de745
A
2355 (mach_vm_offset_t) 0,
2356 vm_flags,
2357 vmk_flags,
2358 VM_KERN_MEMORY_NONE,
2359 (ipc_port_t)(uintptr_t) sr_pager,
2360 0,
2361 TRUE,
2362 tmp_entry->protection,
2363 tmp_entry->max_protection,
2364 tmp_entry->inheritance);
d9a64523
A
2365 assertf(kr == KERN_SUCCESS, "kr = 0x%x\n", kr);
2366 assertf(map_addr == tmp_entry->vme_start,
0a7de745
A
2367 "map_addr=0x%llx vme_start=0x%llx tmp_entry=%p\n",
2368 (uint64_t)map_addr,
2369 (uint64_t) tmp_entry->vme_start,
2370 tmp_entry);
d9a64523
A
2371
2372 /* success! */
2373 kr = KERN_SUCCESS;
39236c6e 2374
d9a64523 2375done:
f427ee49 2376 if (sr_pager != NULL) {
39236c6e 2377 /*
f427ee49
A
2378 * Release the sr_pager reference obtained by shared_region_pager_setup().
2379 * The mapping, if it succeeded, is now holding a reference on the memory object.
39236c6e 2380 */
d9a64523
A
2381 memory_object_deallocate(sr_pager);
2382 sr_pager = MEMORY_OBJECT_NULL;
6d2010ae 2383 }
f427ee49 2384 if (tmp_entry != NULL) {
d9a64523
A
2385 /* release extra ref on tmp_entry's VM object */
2386 vm_object_deallocate(VME_OBJECT(tmp_entry));
2387 tmp_entry = VM_MAP_ENTRY_NULL;
6d2010ae 2388 }
6d2010ae 2389
39236c6e 2390 if (kr != KERN_SUCCESS) {
d9a64523 2391 /* cleanup */
f427ee49
A
2392 if (si != NULL) {
2393 if (si->si_slide_object) {
2394 vm_object_deallocate(si->si_slide_object);
2395 si->si_slide_object = VM_OBJECT_NULL;
2396 }
2397 kfree(si, sizeof(*si));
2398 si = NULL;
d9a64523 2399 }
f427ee49
A
2400 if (slide_info_entry != NULL) {
2401 kheap_free(KHEAP_DATA_BUFFERS, slide_info_entry, (vm_size_t)slide_info_size);
2402 slide_info_entry = NULL;
d9a64523 2403 }
39236c6e
A
2404 }
2405 return kr;
6d2010ae
A
2406}
2407
39037602 2408static kern_return_t
f427ee49
A
2409vm_shared_region_slide_sanity_check_v2(
2410 vm_shared_region_slide_info_entry_v2_t s_info,
2411 mach_vm_size_t slide_info_size)
6d2010ae 2412{
f427ee49
A
2413 if (slide_info_size < sizeof(struct vm_shared_region_slide_info_entry_v2)) {
2414 printf("%s bad slide_info_size: %lx\n", __func__, (uintptr_t)slide_info_size);
2415 return KERN_FAILURE;
39037602 2416 }
39037602
A
2417 if (s_info->page_size != PAGE_SIZE_FOR_SR_SLIDE) {
2418 return KERN_FAILURE;
2419 }
2420
2421 /* Ensure that the slide info doesn't reference any data outside of its bounds. */
2422
2423 uint32_t page_starts_count = s_info->page_starts_count;
2424 uint32_t page_extras_count = s_info->page_extras_count;
2425 mach_vm_size_t num_trailing_entries = page_starts_count + page_extras_count;
2426 if (num_trailing_entries < page_starts_count) {
2427 return KERN_FAILURE;
2428 }
2429
2430 /* Scale by sizeof(uint16_t). Hard-coding the size simplifies the overflow check. */
2431 mach_vm_size_t trailing_size = num_trailing_entries << 1;
2432 if (trailing_size >> 1 != num_trailing_entries) {
2433 return KERN_FAILURE;
2434 }
2435
2436 mach_vm_size_t required_size = sizeof(*s_info) + trailing_size;
2437 if (required_size < sizeof(*s_info)) {
2438 return KERN_FAILURE;
2439 }
2440
2441 if (required_size > slide_info_size) {
2442 return KERN_FAILURE;
2443 }
2444
2445 return KERN_SUCCESS;
2446}
2447
d9a64523 2448static kern_return_t
f427ee49
A
2449vm_shared_region_slide_sanity_check_v3(
2450 vm_shared_region_slide_info_entry_v3_t s_info,
2451 mach_vm_size_t slide_info_size)
d9a64523 2452{
f427ee49
A
2453 if (slide_info_size < sizeof(struct vm_shared_region_slide_info_entry_v3)) {
2454 printf("%s bad slide_info_size: %lx\n", __func__, (uintptr_t)slide_info_size);
2455 return KERN_FAILURE;
2456 }
d9a64523
A
2457 if (s_info->page_size != PAGE_SIZE_FOR_SR_SLIDE) {
2458 printf("vm_shared_region_slide_sanity_check_v3: s_info->page_size != PAGE_SIZE_FOR_SR_SL 0x%llx != 0x%llx\n", (uint64_t)s_info->page_size, (uint64_t)PAGE_SIZE_FOR_SR_SLIDE);
2459 return KERN_FAILURE;
2460 }
2461
2462 uint32_t page_starts_count = s_info->page_starts_count;
2463 mach_vm_size_t num_trailing_entries = page_starts_count;
2464 mach_vm_size_t trailing_size = num_trailing_entries << 1;
2465 mach_vm_size_t required_size = sizeof(*s_info) + trailing_size;
2466 if (required_size < sizeof(*s_info)) {
2467 printf("vm_shared_region_slide_sanity_check_v3: required_size != sizeof(*s_info) 0x%llx != 0x%llx\n", (uint64_t)required_size, (uint64_t)sizeof(*s_info));
2468 return KERN_FAILURE;
2469 }
2470
2471 if (required_size > slide_info_size) {
2472 printf("vm_shared_region_slide_sanity_check_v3: required_size != slide_info_size 0x%llx != 0x%llx\n", (uint64_t)required_size, (uint64_t)slide_info_size);
2473 return KERN_FAILURE;
2474 }
2475
2476 return KERN_SUCCESS;
2477}
2478
2479static kern_return_t
f427ee49
A
2480vm_shared_region_slide_sanity_check_v4(
2481 vm_shared_region_slide_info_entry_v4_t s_info,
2482 mach_vm_size_t slide_info_size)
d9a64523 2483{
f427ee49
A
2484 if (slide_info_size < sizeof(struct vm_shared_region_slide_info_entry_v4)) {
2485 printf("%s bad slide_info_size: %lx\n", __func__, (uintptr_t)slide_info_size);
2486 return KERN_FAILURE;
2487 }
0a7de745
A
2488 if (s_info->page_size != PAGE_SIZE_FOR_SR_SLIDE) {
2489 return KERN_FAILURE;
2490 }
2491
2492 /* Ensure that the slide info doesn't reference any data outside of its bounds. */
2493
2494 uint32_t page_starts_count = s_info->page_starts_count;
2495 uint32_t page_extras_count = s_info->page_extras_count;
2496 mach_vm_size_t num_trailing_entries = page_starts_count + page_extras_count;
2497 if (num_trailing_entries < page_starts_count) {
2498 return KERN_FAILURE;
2499 }
2500
2501 /* Scale by sizeof(uint16_t). Hard-coding the size simplifies the overflow check. */
2502 mach_vm_size_t trailing_size = num_trailing_entries << 1;
2503 if (trailing_size >> 1 != num_trailing_entries) {
2504 return KERN_FAILURE;
2505 }
2506
2507 mach_vm_size_t required_size = sizeof(*s_info) + trailing_size;
2508 if (required_size < sizeof(*s_info)) {
2509 return KERN_FAILURE;
2510 }
2511
2512 if (required_size > slide_info_size) {
2513 return KERN_FAILURE;
2514 }
2515
2516 return KERN_SUCCESS;
d9a64523
A
2517}
2518
2519
39037602 2520static kern_return_t
f427ee49
A
2521vm_shared_region_slide_sanity_check(
2522 vm_shared_region_slide_info_entry_t s_info,
2523 mach_vm_size_t s_info_size)
6d2010ae 2524{
f427ee49 2525 kern_return_t kr;
0a7de745 2526
f427ee49
A
2527 switch (s_info->version) {
2528 case 2:
2529 kr = vm_shared_region_slide_sanity_check_v2(&s_info->v2, s_info_size);
2530 break;
2531 case 3:
2532 kr = vm_shared_region_slide_sanity_check_v3(&s_info->v3, s_info_size);
2533 break;
2534 case 4:
2535 kr = vm_shared_region_slide_sanity_check_v4(&s_info->v4, s_info_size);
2536 break;
2537 default:
2538 kr = KERN_FAILURE;
6d2010ae 2539 }
f427ee49 2540 return kr;
6d2010ae
A
2541}
2542
39037602
A
2543static kern_return_t
2544rebase_chain_32(
2545 uint8_t *page_content,
2546 uint16_t start_offset,
2547 uint32_t slide_amount,
2548 vm_shared_region_slide_info_entry_v2_t s_info)
2549{
2550 const uint32_t last_page_offset = PAGE_SIZE_FOR_SR_SLIDE - sizeof(uint32_t);
2551
2552 const uint32_t delta_mask = (uint32_t)(s_info->delta_mask);
2553 const uint32_t value_mask = ~delta_mask;
2554 const uint32_t value_add = (uint32_t)(s_info->value_add);
2555 const uint32_t delta_shift = __builtin_ctzll(delta_mask) - 2;
2556
2557 uint32_t page_offset = start_offset;
2558 uint32_t delta = 1;
2559
2560 while (delta != 0 && page_offset <= last_page_offset) {
2561 uint8_t *loc;
2562 uint32_t value;
2563
2564 loc = page_content + page_offset;
2565 memcpy(&value, loc, sizeof(value));
2566 delta = (value & delta_mask) >> delta_shift;
2567 value &= value_mask;
2568
2569 if (value != 0) {
2570 value += value_add;
2571 value += slide_amount;
2572 }
2573 memcpy(loc, &value, sizeof(value));
2574 page_offset += delta;
2575 }
2576
2577 /* If the offset went past the end of the page, then the slide data is invalid. */
2578 if (page_offset > last_page_offset) {
2579 return KERN_FAILURE;
2580 }
2581 return KERN_SUCCESS;
2582}
2583
2584static kern_return_t
2585rebase_chain_64(
2586 uint8_t *page_content,
2587 uint16_t start_offset,
2588 uint32_t slide_amount,
2589 vm_shared_region_slide_info_entry_v2_t s_info)
2590{
2591 const uint32_t last_page_offset = PAGE_SIZE_FOR_SR_SLIDE - sizeof(uint64_t);
2592
2593 const uint64_t delta_mask = s_info->delta_mask;
2594 const uint64_t value_mask = ~delta_mask;
2595 const uint64_t value_add = s_info->value_add;
2596 const uint64_t delta_shift = __builtin_ctzll(delta_mask) - 2;
2597
2598 uint32_t page_offset = start_offset;
2599 uint32_t delta = 1;
2600
2601 while (delta != 0 && page_offset <= last_page_offset) {
2602 uint8_t *loc;
2603 uint64_t value;
2604
2605 loc = page_content + page_offset;
2606 memcpy(&value, loc, sizeof(value));
2607 delta = (uint32_t)((value & delta_mask) >> delta_shift);
2608 value &= value_mask;
2609
2610 if (value != 0) {
2611 value += value_add;
2612 value += slide_amount;
2613 }
2614 memcpy(loc, &value, sizeof(value));
2615 page_offset += delta;
2616 }
2617
2618 if (page_offset + sizeof(uint32_t) == PAGE_SIZE_FOR_SR_SLIDE) {
2619 /* If a pointer straddling the page boundary needs to be adjusted, then
2620 * add the slide to the lower half. The encoding guarantees that the upper
2621 * half on the next page will need no masking.
2622 *
2623 * This assumes a little-endian machine and that the region being slid
2624 * never crosses a 4 GB boundary. */
2625
2626 uint8_t *loc = page_content + page_offset;
2627 uint32_t value;
2628
2629 memcpy(&value, loc, sizeof(value));
2630 value += slide_amount;
2631 memcpy(loc, &value, sizeof(value));
2632 } else if (page_offset > last_page_offset) {
2633 return KERN_FAILURE;
2634 }
2635
2636 return KERN_SUCCESS;
2637}
2638
2639static kern_return_t
2640rebase_chain(
2641 boolean_t is_64,
2642 uint32_t pageIndex,
2643 uint8_t *page_content,
2644 uint16_t start_offset,
2645 uint32_t slide_amount,
2646 vm_shared_region_slide_info_entry_v2_t s_info)
2647{
2648 kern_return_t kr;
2649 if (is_64) {
2650 kr = rebase_chain_64(page_content, start_offset, slide_amount, s_info);
2651 } else {
2652 kr = rebase_chain_32(page_content, start_offset, slide_amount, s_info);
2653 }
2654
2655 if (kr != KERN_SUCCESS) {
2656 printf("vm_shared_region_slide_page() offset overflow: pageIndex=%u, start_offset=%u, slide_amount=%u\n",
0a7de745 2657 pageIndex, start_offset, slide_amount);
39037602
A
2658 }
2659 return kr;
2660}
2661
2662static kern_return_t
2663vm_shared_region_slide_page_v2(vm_shared_region_slide_info_t si, vm_offset_t vaddr, uint32_t pageIndex)
2664{
f427ee49
A
2665 vm_shared_region_slide_info_entry_v2_t s_info = &si->si_slide_info_entry->v2;
2666 const uint32_t slide_amount = si->si_slide;
39037602
A
2667
2668 /* The high bits of the delta_mask field are nonzero precisely when the shared
2669 * cache is 64-bit. */
2670 const boolean_t is_64 = (s_info->delta_mask >> 32) != 0;
2671
2672 const uint16_t *page_starts = (uint16_t *)((uintptr_t)s_info + s_info->page_starts_offset);
2673 const uint16_t *page_extras = (uint16_t *)((uintptr_t)s_info + s_info->page_extras_offset);
2674
2675 uint8_t *page_content = (uint8_t *)vaddr;
2676 uint16_t page_entry;
2677
2678 if (pageIndex >= s_info->page_starts_count) {
2679 printf("vm_shared_region_slide_page() did not find page start in slide info: pageIndex=%u, count=%u\n",
0a7de745 2680 pageIndex, s_info->page_starts_count);
39037602
A
2681 return KERN_FAILURE;
2682 }
2683 page_entry = page_starts[pageIndex];
2684
2685 if (page_entry == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE) {
2686 return KERN_SUCCESS;
2687 }
2688
2689 if (page_entry & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) {
2690 uint16_t chain_index = page_entry & DYLD_CACHE_SLIDE_PAGE_VALUE;
2691 uint16_t info;
2692
2693 do {
2694 uint16_t page_start_offset;
2695 kern_return_t kr;
2696
2697 if (chain_index >= s_info->page_extras_count) {
2698 printf("vm_shared_region_slide_page() out-of-bounds extras index: index=%u, count=%u\n",
0a7de745 2699 chain_index, s_info->page_extras_count);
39037602
A
2700 return KERN_FAILURE;
2701 }
2702 info = page_extras[chain_index];
f427ee49 2703 page_start_offset = (uint16_t)((info & DYLD_CACHE_SLIDE_PAGE_VALUE) << DYLD_CACHE_SLIDE_PAGE_OFFSET_SHIFT);
39037602
A
2704
2705 kr = rebase_chain(is_64, pageIndex, page_content, page_start_offset, slide_amount, s_info);
2706 if (kr != KERN_SUCCESS) {
2707 return KERN_FAILURE;
2708 }
2709
2710 chain_index++;
2711 } while (!(info & DYLD_CACHE_SLIDE_PAGE_ATTR_END));
2712 } else {
f427ee49 2713 const uint16_t page_start_offset = (uint16_t)(page_entry << DYLD_CACHE_SLIDE_PAGE_OFFSET_SHIFT);
39037602
A
2714 kern_return_t kr;
2715
2716 kr = rebase_chain(is_64, pageIndex, page_content, page_start_offset, slide_amount, s_info);
2717 if (kr != KERN_SUCCESS) {
2718 return KERN_FAILURE;
2719 }
2720 }
2721
2722 return KERN_SUCCESS;
2723}
2724
d9a64523
A
2725
2726static kern_return_t
f427ee49
A
2727vm_shared_region_slide_page_v3(
2728 vm_shared_region_slide_info_t si,
2729 vm_offset_t vaddr,
2730 __unused mach_vm_offset_t uservaddr,
2731 uint32_t pageIndex,
2732#if !__has_feature(ptrauth_calls)
2733 __unused
2734#endif /* !__has_feature(ptrauth_calls) */
2735 uint64_t jop_key)
d9a64523 2736{
f427ee49
A
2737 vm_shared_region_slide_info_entry_v3_t s_info = &si->si_slide_info_entry->v3;
2738 const uint32_t slide_amount = si->si_slide;
d9a64523
A
2739
2740 uint8_t *page_content = (uint8_t *)vaddr;
2741 uint16_t page_entry;
2742
2743 if (pageIndex >= s_info->page_starts_count) {
2744 printf("vm_shared_region_slide_page() did not find page start in slide info: pageIndex=%u, count=%u\n",
0a7de745 2745 pageIndex, s_info->page_starts_count);
d9a64523
A
2746 return KERN_FAILURE;
2747 }
2748 page_entry = s_info->page_starts[pageIndex];
2749
2750 if (page_entry == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE) {
2751 return KERN_SUCCESS;
2752 }
2753
2754 uint8_t* rebaseLocation = page_content;
2755 uint64_t delta = page_entry;
2756 do {
2757 rebaseLocation += delta;
2758 uint64_t value;
2759 memcpy(&value, rebaseLocation, sizeof(value));
0a7de745 2760 delta = ((value & 0x3FF8000000000000) >> 51) * sizeof(uint64_t);
d9a64523
A
2761
2762 // A pointer is one of :
2763 // {
2764 // uint64_t pointerValue : 51;
2765 // uint64_t offsetToNextPointer : 11;
2766 // uint64_t isBind : 1 = 0;
2767 // uint64_t authenticated : 1 = 0;
2768 // }
2769 // {
2770 // uint32_t offsetFromSharedCacheBase;
2771 // uint16_t diversityData;
2772 // uint16_t hasAddressDiversity : 1;
2773 // uint16_t hasDKey : 1;
2774 // uint16_t hasBKey : 1;
2775 // uint16_t offsetToNextPointer : 11;
2776 // uint16_t isBind : 1;
2777 // uint16_t authenticated : 1 = 1;
2778 // }
2779
2780 bool isBind = (value & (1ULL << 62)) == 1;
2781 if (isBind) {
2782 return KERN_FAILURE;
2783 }
2784
f427ee49 2785#if __has_feature(ptrauth_calls)
cb323159
A
2786 uint16_t diversity_data = (uint16_t)(value >> 32);
2787 bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
2788 ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
f427ee49 2789#endif /* __has_feature(ptrauth_calls) */
d9a64523
A
2790 bool isAuthenticated = (value & (1ULL << 63)) != 0;
2791
2792 if (isAuthenticated) {
2793 // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
2794 value = (value & 0xFFFFFFFF) + slide_amount;
2795 // Add in the offset from the mach_header
2796 const uint64_t value_add = s_info->value_add;
2797 value += value_add;
2798
f427ee49 2799#if __has_feature(ptrauth_calls)
cb323159
A
2800 uint64_t discriminator = diversity_data;
2801 if (hasAddressDiversity) {
2802 // First calculate a new discriminator using the address of where we are trying to store the value
2803 uintptr_t pageOffset = rebaseLocation - page_content;
2804 discriminator = __builtin_ptrauth_blend_discriminator((void*)(((uintptr_t)uservaddr) + pageOffset), discriminator);
2805 }
2806
f427ee49 2807 if (jop_key != 0 && si->si_ptrauth && !arm_user_jop_disabled()) {
cb323159
A
2808 /*
2809 * these pointers are used in user mode. disable the kernel key diversification
2810 * so we can sign them for use in user mode.
2811 */
f427ee49 2812 value = (uintptr_t)pmap_sign_user_ptr((void *)value, key, discriminator, jop_key);
cb323159 2813 }
f427ee49 2814#endif /* __has_feature(ptrauth_calls) */
d9a64523
A
2815 } else {
2816 // The new value for a rebase is the low 51-bits of the threaded value plus the slide.
2817 // Regular pointer which needs to fit in 51-bits of value.
2818 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
2819 // and the bottom 43-bits to be fit in to 51-bits.
2820 uint64_t top8Bits = value & 0x0007F80000000000ULL;
2821 uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
0a7de745 2822 uint64_t targetValue = (top8Bits << 13) | bottom43Bits;
d9a64523
A
2823 value = targetValue + slide_amount;
2824 }
2825
2826 memcpy(rebaseLocation, &value, sizeof(value));
2827 } while (delta != 0);
2828
2829 return KERN_SUCCESS;
2830}
2831
2832static kern_return_t
2833rebase_chainv4(
0a7de745
A
2834 uint8_t *page_content,
2835 uint16_t start_offset,
2836 uint32_t slide_amount,
2837 vm_shared_region_slide_info_entry_v4_t s_info)
d9a64523 2838{
0a7de745
A
2839 const uint32_t last_page_offset = PAGE_SIZE_FOR_SR_SLIDE - sizeof(uint32_t);
2840
2841 const uint32_t delta_mask = (uint32_t)(s_info->delta_mask);
2842 const uint32_t value_mask = ~delta_mask;
2843 const uint32_t value_add = (uint32_t)(s_info->value_add);
2844 const uint32_t delta_shift = __builtin_ctzll(delta_mask) - 2;
2845
2846 uint32_t page_offset = start_offset;
2847 uint32_t delta = 1;
2848
2849 while (delta != 0 && page_offset <= last_page_offset) {
2850 uint8_t *loc;
2851 uint32_t value;
2852
2853 loc = page_content + page_offset;
2854 memcpy(&value, loc, sizeof(value));
2855 delta = (value & delta_mask) >> delta_shift;
2856 value &= value_mask;
2857
2858 if ((value & 0xFFFF8000) == 0) {
2859 // small positive non-pointer, use as-is
2860 } else if ((value & 0x3FFF8000) == 0x3FFF8000) {
2861 // small negative non-pointer
2862 value |= 0xC0000000;
2863 } else {
2864 // pointer that needs rebasing
2865 value += value_add;
2866 value += slide_amount;
2867 }
2868 memcpy(loc, &value, sizeof(value));
2869 page_offset += delta;
2870 }
2871
2872 /* If the offset went past the end of the page, then the slide data is invalid. */
2873 if (page_offset > last_page_offset) {
2874 return KERN_FAILURE;
2875 }
2876 return KERN_SUCCESS;
d9a64523
A
2877}
2878
2879static kern_return_t
2880vm_shared_region_slide_page_v4(vm_shared_region_slide_info_t si, vm_offset_t vaddr, uint32_t pageIndex)
2881{
f427ee49
A
2882 vm_shared_region_slide_info_entry_v4_t s_info = &si->si_slide_info_entry->v4;
2883 const uint32_t slide_amount = si->si_slide;
0a7de745
A
2884
2885 const uint16_t *page_starts = (uint16_t *)((uintptr_t)s_info + s_info->page_starts_offset);
2886 const uint16_t *page_extras = (uint16_t *)((uintptr_t)s_info + s_info->page_extras_offset);
2887
2888 uint8_t *page_content = (uint8_t *)vaddr;
2889 uint16_t page_entry;
2890
2891 if (pageIndex >= s_info->page_starts_count) {
2892 printf("vm_shared_region_slide_page() did not find page start in slide info: pageIndex=%u, count=%u\n",
2893 pageIndex, s_info->page_starts_count);
2894 return KERN_FAILURE;
2895 }
2896 page_entry = page_starts[pageIndex];
2897
2898 if (page_entry == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE) {
2899 return KERN_SUCCESS;
2900 }
2901
2902 if (page_entry & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA) {
2903 uint16_t chain_index = page_entry & DYLD_CACHE_SLIDE4_PAGE_INDEX;
2904 uint16_t info;
2905
2906 do {
2907 uint16_t page_start_offset;
2908 kern_return_t kr;
2909
2910 if (chain_index >= s_info->page_extras_count) {
2911 printf("vm_shared_region_slide_page() out-of-bounds extras index: index=%u, count=%u\n",
2912 chain_index, s_info->page_extras_count);
2913 return KERN_FAILURE;
2914 }
2915 info = page_extras[chain_index];
f427ee49 2916 page_start_offset = (uint16_t)((info & DYLD_CACHE_SLIDE4_PAGE_INDEX) << DYLD_CACHE_SLIDE_PAGE_OFFSET_SHIFT);
0a7de745
A
2917
2918 kr = rebase_chainv4(page_content, page_start_offset, slide_amount, s_info);
2919 if (kr != KERN_SUCCESS) {
2920 return KERN_FAILURE;
2921 }
2922
2923 chain_index++;
2924 } while (!(info & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END));
2925 } else {
f427ee49 2926 const uint16_t page_start_offset = (uint16_t)(page_entry << DYLD_CACHE_SLIDE_PAGE_OFFSET_SHIFT);
0a7de745
A
2927 kern_return_t kr;
2928
2929 kr = rebase_chainv4(page_content, page_start_offset, slide_amount, s_info);
2930 if (kr != KERN_SUCCESS) {
2931 return KERN_FAILURE;
2932 }
2933 }
2934
2935 return KERN_SUCCESS;
d9a64523
A
2936}
2937
2938
2939
39037602 2940kern_return_t
f427ee49
A
2941vm_shared_region_slide_page(
2942 vm_shared_region_slide_info_t si,
2943 vm_offset_t vaddr,
2944 mach_vm_offset_t uservaddr,
2945 uint32_t pageIndex,
2946 uint64_t jop_key)
39037602 2947{
f427ee49
A
2948 switch (si->si_slide_info_entry->version) {
2949 case 2:
39037602 2950 return vm_shared_region_slide_page_v2(si, vaddr, pageIndex);
f427ee49
A
2951 case 3:
2952 return vm_shared_region_slide_page_v3(si, vaddr, uservaddr, pageIndex, jop_key);
2953 case 4:
0a7de745 2954 return vm_shared_region_slide_page_v4(si, vaddr, pageIndex);
f427ee49 2955 default:
0a7de745
A
2956 return KERN_FAILURE;
2957 }
39037602
A
2958}
2959
2d21ac55
A
2960/******************************************************************************/
2961/* Comm page support */
2962/******************************************************************************/
2963
c3c9b80d
A
2964SECURITY_READ_ONLY_LATE(ipc_port_t) commpage32_handle = IPC_PORT_NULL;
2965SECURITY_READ_ONLY_LATE(ipc_port_t) commpage64_handle = IPC_PORT_NULL;
2966SECURITY_READ_ONLY_LATE(vm_named_entry_t) commpage32_entry = NULL;
2967SECURITY_READ_ONLY_LATE(vm_named_entry_t) commpage64_entry = NULL;
2968SECURITY_READ_ONLY_LATE(vm_map_t) commpage32_map = VM_MAP_NULL;
2969SECURITY_READ_ONLY_LATE(vm_map_t) commpage64_map = VM_MAP_NULL;
2d21ac55 2970
c3c9b80d
A
2971SECURITY_READ_ONLY_LATE(ipc_port_t) commpage_text32_handle = IPC_PORT_NULL;
2972SECURITY_READ_ONLY_LATE(ipc_port_t) commpage_text64_handle = IPC_PORT_NULL;
2973SECURITY_READ_ONLY_LATE(vm_named_entry_t) commpage_text32_entry = NULL;
2974SECURITY_READ_ONLY_LATE(vm_named_entry_t) commpage_text64_entry = NULL;
2975SECURITY_READ_ONLY_LATE(vm_map_t) commpage_text32_map = VM_MAP_NULL;
2976SECURITY_READ_ONLY_LATE(vm_map_t) commpage_text64_map = VM_MAP_NULL;
316670eb 2977
c3c9b80d
A
2978SECURITY_READ_ONLY_LATE(user32_addr_t) commpage_text32_location = 0;
2979SECURITY_READ_ONLY_LATE(user64_addr_t) commpage_text64_location = 0;
316670eb
A
2980
2981#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
2982/*
2983 * Create a memory entry, VM submap and pmap for one commpage.
2984 */
2985static void
2986_vm_commpage_init(
0a7de745
A
2987 ipc_port_t *handlep,
2988 vm_map_size_t size)
2d21ac55 2989{
0a7de745
A
2990 kern_return_t kr;
2991 vm_named_entry_t mem_entry;
2992 vm_map_t new_map;
2d21ac55
A
2993
2994 SHARED_REGION_TRACE_DEBUG(
2995 ("commpage: -> _init(0x%llx)\n",
0a7de745 2996 (long long)size));
2d21ac55
A
2997
2998 kr = mach_memory_entry_allocate(&mem_entry,
0a7de745 2999 handlep);
2d21ac55
A
3000 if (kr != KERN_SUCCESS) {
3001 panic("_vm_commpage_init: could not allocate mem_entry");
3002 }
cb323159 3003 new_map = vm_map_create(pmap_create_options(NULL, 0, 0), 0, size, PMAP_CREATE_64BIT);
2d21ac55
A
3004 if (new_map == VM_MAP_NULL) {
3005 panic("_vm_commpage_init: could not allocate VM map");
3006 }
3007 mem_entry->backing.map = new_map;
3008 mem_entry->internal = TRUE;
3009 mem_entry->is_sub_map = TRUE;
3010 mem_entry->offset = 0;
3011 mem_entry->protection = VM_PROT_ALL;
3012 mem_entry->size = size;
3013
3014 SHARED_REGION_TRACE_DEBUG(
3015 ("commpage: _init(0x%llx) <- %p\n",
0a7de745 3016 (long long)size, (void *)VM_KERNEL_ADDRPERM(*handlep)));
2d21ac55 3017}
316670eb
A
3018#endif
3019
3020
3021/*
0a7de745 3022 * Initialize the comm text pages at boot time
316670eb 3023 */
0a7de745 3024void
316670eb
A
3025vm_commpage_text_init(void)
3026{
3027 SHARED_REGION_TRACE_DEBUG(
3028 ("commpage text: ->init()\n"));
3029#if defined(__i386__) || defined(__x86_64__)
3030 /* create the 32 bit comm text page */
3031 unsigned int offset = (random() % _PFZ32_SLIDE_RANGE) << PAGE_SHIFT; /* restricting to 32bMAX-2PAGE */
3032 _vm_commpage_init(&commpage_text32_handle, _COMM_PAGE_TEXT_AREA_LENGTH);
ea3f0419 3033 commpage_text32_entry = (vm_named_entry_t) ip_get_kobject(commpage_text32_handle);
316670eb
A
3034 commpage_text32_map = commpage_text32_entry->backing.map;
3035 commpage_text32_location = (user32_addr_t) (_COMM_PAGE32_TEXT_START + offset);
3036 /* XXX if (cpu_is_64bit_capable()) ? */
0a7de745 3037 /* create the 64-bit comm page */
316670eb 3038 offset = (random() % _PFZ64_SLIDE_RANGE) << PAGE_SHIFT; /* restricting sliding upto 2Mb range */
0a7de745 3039 _vm_commpage_init(&commpage_text64_handle, _COMM_PAGE_TEXT_AREA_LENGTH);
ea3f0419 3040 commpage_text64_entry = (vm_named_entry_t) ip_get_kobject(commpage_text64_handle);
0a7de745 3041 commpage_text64_map = commpage_text64_entry->backing.map;
316670eb 3042 commpage_text64_location = (user64_addr_t) (_COMM_PAGE64_TEXT_START + offset);
f427ee49 3043#endif
316670eb
A
3044
3045 commpage_text_populate();
f427ee49 3046
316670eb
A
3047 /* populate the routines in here */
3048 SHARED_REGION_TRACE_DEBUG(
0a7de745 3049 ("commpage text: init() <-\n"));
316670eb 3050}
2d21ac55
A
3051
3052/*
3053 * Initialize the comm pages at boot time.
3054 */
3055void
3056vm_commpage_init(void)
3057{
3058 SHARED_REGION_TRACE_DEBUG(
3059 ("commpage: -> init()\n"));
3060
316670eb 3061#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
3062 /* create the 32-bit comm page */
3063 _vm_commpage_init(&commpage32_handle, _COMM_PAGE32_AREA_LENGTH);
ea3f0419 3064 commpage32_entry = (vm_named_entry_t) ip_get_kobject(commpage32_handle);
2d21ac55
A
3065 commpage32_map = commpage32_entry->backing.map;
3066
3067 /* XXX if (cpu_is_64bit_capable()) ? */
3068 /* create the 64-bit comm page */
3069 _vm_commpage_init(&commpage64_handle, _COMM_PAGE64_AREA_LENGTH);
ea3f0419 3070 commpage64_entry = (vm_named_entry_t) ip_get_kobject(commpage64_handle);
2d21ac55
A
3071 commpage64_map = commpage64_entry->backing.map;
3072
316670eb
A
3073#endif /* __i386__ || __x86_64__ */
3074
2d21ac55
A
3075 /* populate them according to this specific platform */
3076 commpage_populate();
b0d623f7 3077 __commpage_setup = 1;
c3c9b80d 3078#if XNU_TARGET_OS_OSX
b0d623f7
A
3079 if (__system_power_source == 0) {
3080 post_sys_powersource_internal(0, 1);
3081 }
c3c9b80d 3082#endif /* XNU_TARGET_OS_OSX */
2d21ac55
A
3083
3084 SHARED_REGION_TRACE_DEBUG(
3085 ("commpage: init() <-\n"));
3086}
3087
3088/*
3089 * Enter the appropriate comm page into the task's address space.
3090 * This is called at exec() time via vm_map_exec().
3091 */
3092kern_return_t
3093vm_commpage_enter(
0a7de745
A
3094 vm_map_t map,
3095 task_t task,
3096 boolean_t is64bit)
2d21ac55 3097{
0a7de745 3098#if defined(__arm__)
5ba3f43e
A
3099#pragma unused(is64bit)
3100 (void)task;
3101 (void)map;
3102 return KERN_SUCCESS;
0a7de745 3103#elif defined(__arm64__)
5ba3f43e
A
3104#pragma unused(is64bit)
3105 (void)task;
3106 (void)map;
3107 pmap_insert_sharedpage(vm_map_pmap(map));
3108 return KERN_SUCCESS;
3109#else
0a7de745
A
3110 ipc_port_t commpage_handle, commpage_text_handle;
3111 vm_map_offset_t commpage_address, objc_address, commpage_text_address;
3112 vm_map_size_t commpage_size, objc_size, commpage_text_size;
3113 int vm_flags;
3114 vm_map_kernel_flags_t vmk_flags;
3115 kern_return_t kr;
2d21ac55
A
3116
3117 SHARED_REGION_TRACE_DEBUG(
3118 ("commpage: -> enter(%p,%p)\n",
0a7de745
A
3119 (void *)VM_KERNEL_ADDRPERM(map),
3120 (void *)VM_KERNEL_ADDRPERM(task)));
2d21ac55 3121
316670eb 3122 commpage_text_size = _COMM_PAGE_TEXT_AREA_LENGTH;
2d21ac55 3123 /* the comm page is likely to be beyond the actual end of the VM map */
5ba3f43e
A
3124 vm_flags = VM_FLAGS_FIXED;
3125 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
3126 vmk_flags.vmkf_beyond_max = TRUE;
2d21ac55
A
3127
3128 /* select the appropriate comm page for this task */
0a7de745 3129 assert(!(is64bit ^ vm_map_is_64bit(map)));
39037602 3130 if (is64bit) {
2d21ac55
A
3131 commpage_handle = commpage64_handle;
3132 commpage_address = (vm_map_offset_t) _COMM_PAGE64_BASE_ADDRESS;
3133 commpage_size = _COMM_PAGE64_AREA_LENGTH;
3134 objc_size = _COMM_PAGE64_OBJC_SIZE;
3135 objc_address = _COMM_PAGE64_OBJC_BASE;
316670eb
A
3136 commpage_text_handle = commpage_text64_handle;
3137 commpage_text_address = (vm_map_offset_t) commpage_text64_location;
2d21ac55
A
3138 } else {
3139 commpage_handle = commpage32_handle;
3140 commpage_address =
0a7de745 3141 (vm_map_offset_t)(unsigned) _COMM_PAGE32_BASE_ADDRESS;
2d21ac55
A
3142 commpage_size = _COMM_PAGE32_AREA_LENGTH;
3143 objc_size = _COMM_PAGE32_OBJC_SIZE;
3144 objc_address = _COMM_PAGE32_OBJC_BASE;
316670eb
A
3145 commpage_text_handle = commpage_text32_handle;
3146 commpage_text_address = (vm_map_offset_t) commpage_text32_location;
2d21ac55
A
3147 }
3148
0a7de745 3149 vm_tag_t tag = VM_KERN_MEMORY_NONE;
f427ee49
A
3150 if ((commpage_address & (pmap_commpage_size_min(map->pmap) - 1)) == 0 &&
3151 (commpage_size & (pmap_commpage_size_min(map->pmap) - 1)) == 0) {
2d21ac55 3152 /* the commpage is properly aligned or sized for pmap-nesting */
5ba3f43e 3153 tag = VM_MEMORY_SHARED_PMAP;
cb323159 3154 vmk_flags.vmkf_nested_pmap = TRUE;
2d21ac55 3155 }
2d21ac55
A
3156 /* map the comm page in the task's address space */
3157 assert(commpage_handle != IPC_PORT_NULL);
3158 kr = vm_map_enter_mem_object(
3159 map,
3160 &commpage_address,
3161 commpage_size,
3162 0,
3163 vm_flags,
5ba3f43e
A
3164 vmk_flags,
3165 tag,
2d21ac55
A
3166 commpage_handle,
3167 0,
3168 FALSE,
316670eb
A
3169 VM_PROT_READ,
3170 VM_PROT_READ,
2d21ac55
A
3171 VM_INHERIT_SHARE);
3172 if (kr != KERN_SUCCESS) {
3173 SHARED_REGION_TRACE_ERROR(
3174 ("commpage: enter(%p,0x%llx,0x%llx) "
0a7de745
A
3175 "commpage %p mapping failed 0x%x\n",
3176 (void *)VM_KERNEL_ADDRPERM(map),
3177 (long long)commpage_address,
3178 (long long)commpage_size,
3179 (void *)VM_KERNEL_ADDRPERM(commpage_handle), kr));
2d21ac55
A
3180 }
3181
316670eb
A
3182 /* map the comm text page in the task's address space */
3183 assert(commpage_text_handle != IPC_PORT_NULL);
3184 kr = vm_map_enter_mem_object(
3185 map,
3186 &commpage_text_address,
3187 commpage_text_size,
3188 0,
3189 vm_flags,
5ba3f43e
A
3190 vmk_flags,
3191 tag,
316670eb
A
3192 commpage_text_handle,
3193 0,
3194 FALSE,
0a7de745
A
3195 VM_PROT_READ | VM_PROT_EXECUTE,
3196 VM_PROT_READ | VM_PROT_EXECUTE,
316670eb
A
3197 VM_INHERIT_SHARE);
3198 if (kr != KERN_SUCCESS) {
3199 SHARED_REGION_TRACE_ERROR(
3200 ("commpage text: enter(%p,0x%llx,0x%llx) "
0a7de745
A
3201 "commpage text %p mapping failed 0x%x\n",
3202 (void *)VM_KERNEL_ADDRPERM(map),
3203 (long long)commpage_text_address,
3204 (long long)commpage_text_size,
3205 (void *)VM_KERNEL_ADDRPERM(commpage_text_handle), kr));
316670eb
A
3206 }
3207
2d21ac55
A
3208 /*
3209 * Since we're here, we also pre-allocate some virtual space for the
3210 * Objective-C run-time, if needed...
3211 */
3212 if (objc_size != 0) {
3213 kr = vm_map_enter_mem_object(
3214 map,
3215 &objc_address,
3216 objc_size,
3217 0,
5ba3f43e
A
3218 VM_FLAGS_FIXED,
3219 vmk_flags,
3220 tag,
2d21ac55
A
3221 IPC_PORT_NULL,
3222 0,
3223 FALSE,
3224 VM_PROT_ALL,
3225 VM_PROT_ALL,
3226 VM_INHERIT_DEFAULT);
3227 if (kr != KERN_SUCCESS) {
3228 SHARED_REGION_TRACE_ERROR(
3229 ("commpage: enter(%p,0x%llx,0x%llx) "
0a7de745
A
3230 "objc mapping failed 0x%x\n",
3231 (void *)VM_KERNEL_ADDRPERM(map),
3232 (long long)objc_address,
3233 (long long)objc_size, kr));
2d21ac55
A
3234 }
3235 }
3236
3237 SHARED_REGION_TRACE_DEBUG(
3238 ("commpage: enter(%p,%p) <- 0x%x\n",
0a7de745
A
3239 (void *)VM_KERNEL_ADDRPERM(map),
3240 (void *)VM_KERNEL_ADDRPERM(task), kr));
2d21ac55 3241 return kr;
5ba3f43e 3242#endif
2d21ac55 3243}
b0d623f7 3244
39236c6e 3245int
f427ee49
A
3246vm_shared_region_slide(
3247 uint32_t slide,
3248 mach_vm_offset_t entry_start_address,
3249 mach_vm_size_t entry_size,
3250 mach_vm_offset_t slide_start,
3251 mach_vm_size_t slide_size,
3252 mach_vm_offset_t slid_mapping,
3253 memory_object_control_t sr_file_control,
3254 vm_prot_t prot)
39236c6e 3255{
0a7de745 3256 vm_shared_region_t sr;
f427ee49 3257 kern_return_t error;
39236c6e
A
3258
3259 SHARED_REGION_TRACE_DEBUG(
3260 ("vm_shared_region_slide: -> slide %#x, entry_start %#llx, entry_size %#llx, slide_start %#llx, slide_size %#llx\n",
0a7de745 3261 slide, entry_start_address, entry_size, slide_start, slide_size));
39236c6e
A
3262
3263 sr = vm_shared_region_get(current_task());
3264 if (sr == NULL) {
3265 printf("%s: no shared region?\n", __FUNCTION__);
3266 SHARED_REGION_TRACE_DEBUG(
3267 ("vm_shared_region_slide: <- %d (no shared region)\n",
0a7de745 3268 KERN_FAILURE));
39236c6e
A
3269 return KERN_FAILURE;
3270 }
3271
3272 /*
3273 * Protect from concurrent access.
3274 */
3275 vm_shared_region_lock();
0a7de745 3276 while (sr->sr_slide_in_progress) {
39236c6e
A
3277 vm_shared_region_sleep(&sr->sr_slide_in_progress, THREAD_UNINT);
3278 }
39236c6e
A
3279
3280 sr->sr_slide_in_progress = TRUE;
3281 vm_shared_region_unlock();
3282
d9a64523 3283 error = vm_shared_region_slide_mapping(sr,
f427ee49 3284 (user_addr_t)slide_start,
0a7de745
A
3285 slide_size,
3286 entry_start_address,
3287 entry_size,
3288 slid_mapping,
3289 slide,
f427ee49
A
3290 sr_file_control,
3291 prot);
d9a64523 3292 if (error) {
39236c6e 3293 printf("slide_info initialization failed with kr=%d\n", error);
39236c6e 3294 }
0a7de745 3295
39236c6e
A
3296 vm_shared_region_lock();
3297
3298 assert(sr->sr_slide_in_progress);
39236c6e
A
3299 sr->sr_slide_in_progress = FALSE;
3300 thread_wakeup(&sr->sr_slide_in_progress);
3301
c3c9b80d 3302#if XNU_TARGET_OS_OSX
f427ee49 3303 if (error == KERN_SUCCESS) {
39236c6e
A
3304 shared_region_completed_slide = TRUE;
3305 }
c3c9b80d 3306#endif /* XNU_TARGET_OS_OSX */
39236c6e
A
3307 vm_shared_region_unlock();
3308
3309 vm_shared_region_deallocate(sr);
3310
3311 SHARED_REGION_TRACE_DEBUG(
3312 ("vm_shared_region_slide: <- %d\n",
0a7de745 3313 error));
39236c6e
A
3314
3315 return error;
3316}
b0d623f7 3317
f427ee49
A
3318/*
3319 * Used during Authenticated Root Volume macOS boot.
3320 * Launchd re-execs itself and wants the new launchd to use
3321 * the shared cache from the new root volume. This call
3322 * makes all the existing shared caches stale to allow
3323 * that to happen.
3324 */
3325void
3326vm_shared_region_pivot(void)
3327{
3328 vm_shared_region_t shared_region = NULL;
3329
3330 vm_shared_region_lock();
3331
3332 queue_iterate(&vm_shared_region_queue, shared_region, vm_shared_region_t, sr_q) {
3333 assert(shared_region->sr_ref_count > 0);
3334 shared_region->sr_stale = TRUE;
3335 if (shared_region->sr_timer_call) {
3336 /*
3337 * We have a shared region ready to be destroyed
3338 * and just waiting for a delayed timer to fire.
3339 * Marking it stale cements its ineligibility to
3340 * be used ever again. So let's shorten the timer
3341 * aggressively down to 10 milliseconds and get rid of it.
3342 * This is a single quantum and we don't need to go
3343 * shorter than this duration. We want it to be short
3344 * enough, however, because we could have an unmount
3345 * of the volume hosting this shared region just behind
3346 * us.
3347 */
3348 uint64_t deadline;
3349 assert(shared_region->sr_ref_count == 1);
3350
3351 /*
3352 * Free the old timer call. Returns with a reference held.
3353 * If the old timer has fired and is waiting for the vm_shared_region_lock
3354 * lock, we will just return with an additional ref_count i.e. 2.
3355 * The old timer will then fire and just drop the ref count down to 1
3356 * with no other modifications.
3357 */
3358 vm_shared_region_reference_locked(shared_region);
3359
3360 /* set up the timer. Keep the reference from above for this timer.*/
3361 shared_region->sr_timer_call = thread_call_allocate(
3362 (thread_call_func_t) vm_shared_region_timeout,
3363 (thread_call_param_t) shared_region);
3364
3365 /* schedule the timer */
3366 clock_interval_to_deadline(10, /* 10 milliseconds */
3367 NSEC_PER_MSEC,
3368 &deadline);
3369 thread_call_enter_delayed(shared_region->sr_timer_call,
3370 deadline);
3371
3372 SHARED_REGION_TRACE_DEBUG(
3373 ("shared_region: pivot(%p): armed timer\n",
3374 (void *)VM_KERNEL_ADDRPERM(shared_region)));
3375 }
3376 }
3377
3378 vm_shared_region_unlock();
3379}
3380
3381/*
3382 * Routine to mark any non-standard slide shared cache region as stale.
3383 * This causes the next "reslide" spawn to create a new shared region.
3384 */
3385void
3386vm_shared_region_reslide_stale(void)
3387{
3388#if __has_feature(ptrauth_calls)
3389 vm_shared_region_t shared_region = NULL;
3390
3391 vm_shared_region_lock();
3392
3393 queue_iterate(&vm_shared_region_queue, shared_region, vm_shared_region_t, sr_q) {
3394 assert(shared_region->sr_ref_count > 0);
3395 if (!shared_region->sr_stale && shared_region->sr_reslide) {
3396 shared_region->sr_stale = TRUE;
3397 vm_shared_region_reslide_count++;
3398 }
3399 }
3400
3401 vm_shared_region_unlock();
3402#endif /* __has_feature(ptrauth_calls) */
3403}
3404
3405/*
3406 * report if the task is using a reslide shared cache region.
3407 */
3408bool
3409vm_shared_region_is_reslide(__unused struct task *task)
3410{
3411 bool is_reslide = FALSE;
3412#if !XNU_TARGET_OS_OSX && __has_feature(ptrauth_calls)
3413 vm_shared_region_t sr = vm_shared_region_get(task);
3414
3415 if (sr != NULL) {
3416 is_reslide = sr->sr_reslide;
3417 vm_shared_region_deallocate(sr);
3418 }
3419#endif /* !XNU_TARGET_OS_OSX && __has_feature(ptrauth_calls) */
3420 return is_reslide;
3421}
3422
0a7de745 3423/*
b0d623f7
A
3424 * This is called from powermanagement code to let kernel know the current source of power.
3425 * 0 if it is external source (connected to power )
3426 * 1 if it is internal power source ie battery
3427 */
3428void
c3c9b80d 3429#if XNU_TARGET_OS_OSX
b0d623f7 3430post_sys_powersource(int i)
c3c9b80d 3431#else /* XNU_TARGET_OS_OSX */
b0d623f7 3432post_sys_powersource(__unused int i)
c3c9b80d 3433#endif /* XNU_TARGET_OS_OSX */
b0d623f7 3434{
c3c9b80d 3435#if XNU_TARGET_OS_OSX
b0d623f7 3436 post_sys_powersource_internal(i, 0);
c3c9b80d 3437#endif /* XNU_TARGET_OS_OSX */
b0d623f7
A
3438}
3439
3440
c3c9b80d 3441#if XNU_TARGET_OS_OSX
b0d623f7
A
3442static void
3443post_sys_powersource_internal(int i, int internal)
3444{
0a7de745 3445 if (internal == 0) {
b0d623f7 3446 __system_power_source = i;
0a7de745 3447 }
b0d623f7 3448}
c3c9b80d 3449#endif /* XNU_TARGET_OS_OSX */
2a1bd2d3
A
3450
3451void *
3452vm_shared_region_root_dir(
3453 struct vm_shared_region *sr)
3454{
3455 void *vnode;
3456
3457 vm_shared_region_lock();
3458 vnode = sr->sr_root_dir;
3459 vm_shared_region_unlock();
3460 return vnode;
3461}