| 1 | /* |
| 2 | * Copyright (c) 2007 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * @APPLE_LICENSE_HEADER_START@ |
| 5 | * |
| 6 | * This file contains Original Code and/or Modifications of Original Code |
| 7 | * as defined in and that are subject to the Apple Public Source License |
| 8 | * Version 2.0 (the 'License'). You may not use this file except in |
| 9 | * compliance with the License. Please obtain a copy of the License at |
| 10 | * http://www.opensource.apple.com/apsl/ and read it before using this |
| 11 | * file. |
| 12 | * |
| 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. |
| 20 | * |
| 21 | * @APPLE_LICENSE_HEADER_END@ |
| 22 | */ |
| 23 | /* |
| 24 | * |
| 25 | * File: vm/vm_shared_region.h |
| 26 | * |
| 27 | * protos and struct definitions for shared region |
| 28 | */ |
| 29 | |
| 30 | #ifndef _VM_SHARED_REGION_H_ |
| 31 | #define _VM_SHARED_REGION_H_ |
| 32 | |
| 33 | #ifdef KERNEL_PRIVATE |
| 34 | |
| 35 | #include <mach/vm_prot.h> |
| 36 | #include <mach/mach_types.h> |
| 37 | #include <mach/shared_region.h> |
| 38 | |
| 39 | #include <kern/kern_types.h> |
| 40 | #include <kern/macro_help.h> |
| 41 | |
| 42 | #include <vm/vm_map.h> |
| 43 | |
| 44 | extern int shared_region_version; |
| 45 | extern int shared_region_persistence; |
| 46 | |
| 47 | #if DEBUG |
| 48 | extern int shared_region_debug; |
| 49 | #define SHARED_REGION_DEBUG(args) \ |
| 50 | MACRO_BEGIN \ |
| 51 | if (shared_region_debug) { \ |
| 52 | kprintf args; \ |
| 53 | } \ |
| 54 | MACRO_END |
| 55 | #else /* DEBUG */ |
| 56 | #define SHARED_REGION_DEBUG(args) |
| 57 | #endif /* DEBUG */ |
| 58 | |
| 59 | extern int shared_region_trace_level; |
| 60 | |
| 61 | extern struct vm_shared_region *primary_system_shared_region; |
| 62 | |
| 63 | #define SHARED_REGION_TRACE_NONE_LVL 0 /* no trace */ |
| 64 | #define SHARED_REGION_TRACE_ERROR_LVL 1 /* trace abnormal events */ |
| 65 | #define SHARED_REGION_TRACE_INFO_LVL 2 /* trace all events */ |
| 66 | #define SHARED_REGION_TRACE_DEBUG_LVL 3 /* extra traces for debug */ |
| 67 | #define SHARED_REGION_TRACE(level, args) \ |
| 68 | MACRO_BEGIN \ |
| 69 | if (shared_region_trace_level >= level) { \ |
| 70 | printf args; \ |
| 71 | } \ |
| 72 | MACRO_END |
| 73 | #define SHARED_REGION_TRACE_NONE(args) |
| 74 | #define SHARED_REGION_TRACE_ERROR(args) \ |
| 75 | MACRO_BEGIN \ |
| 76 | SHARED_REGION_TRACE(SHARED_REGION_TRACE_ERROR_LVL, \ |
| 77 | args); \ |
| 78 | MACRO_END |
| 79 | #define SHARED_REGION_TRACE_INFO(args) \ |
| 80 | MACRO_BEGIN \ |
| 81 | SHARED_REGION_TRACE(SHARED_REGION_TRACE_INFO_LVL, \ |
| 82 | args); \ |
| 83 | MACRO_END |
| 84 | #define SHARED_REGION_TRACE_DEBUG(args) \ |
| 85 | MACRO_BEGIN \ |
| 86 | SHARED_REGION_TRACE(SHARED_REGION_TRACE_DEBUG_LVL, \ |
| 87 | args); \ |
| 88 | MACRO_END |
| 89 | |
| 90 | typedef struct vm_shared_region *vm_shared_region_t; |
| 91 | |
| 92 | #ifdef MACH_KERNEL_PRIVATE |
| 93 | |
| 94 | #include <kern/queue.h> |
| 95 | #include <vm/vm_object.h> |
| 96 | #include <vm/memory_object.h> |
| 97 | |
| 98 | #define PAGE_SIZE_FOR_SR_SLIDE 4096 |
| 99 | #define PAGE_SIZE_FOR_SR_SLIDE_16KB 16384 |
| 100 | |
| 101 | /* |
| 102 | * Documentation for the slide info format can be found in the dyld project in |
| 103 | * the file 'launch-cache/dyld_cache_format.h'. |
| 104 | */ |
| 105 | |
| 106 | typedef struct vm_shared_region_slide_info_entry_v1 *vm_shared_region_slide_info_entry_v1_t; |
| 107 | struct vm_shared_region_slide_info_entry_v1 { |
| 108 | uint32_t version; |
| 109 | uint32_t toc_offset; // offset from start of header to table-of-contents |
| 110 | uint32_t toc_count; // number of entries in toc (same as number of pages in r/w mapping) |
| 111 | uint32_t entry_offset; |
| 112 | uint32_t entry_count; |
| 113 | uint32_t entries_size; |
| 114 | // uint16_t toc[toc_count]; |
| 115 | // entrybitmap entries[entries_count]; |
| 116 | }; |
| 117 | |
| 118 | #define NUM_SLIDING_BITMAPS_PER_PAGE (0x1000/sizeof(int)/8) /*128*/ |
| 119 | typedef struct slide_info_entry_toc *slide_info_entry_toc_t; |
| 120 | struct slide_info_entry_toc { |
| 121 | uint8_t entry[NUM_SLIDING_BITMAPS_PER_PAGE]; |
| 122 | }; |
| 123 | |
| 124 | typedef struct vm_shared_region_slide_info_entry_v2 *vm_shared_region_slide_info_entry_v2_t; |
| 125 | struct vm_shared_region_slide_info_entry_v2 { |
| 126 | uint32_t version; |
| 127 | uint32_t page_size; |
| 128 | uint32_t page_starts_offset; |
| 129 | uint32_t page_starts_count; |
| 130 | uint32_t ; |
| 131 | uint32_t ; |
| 132 | uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location |
| 133 | uint64_t value_add; |
| 134 | // uint16_t page_starts[page_starts_count]; |
| 135 | // uint16_t page_extras[page_extras_count]; |
| 136 | }; |
| 137 | |
| 138 | #define DYLD_CACHE_SLIDE_PAGE_ATTRS 0xC000 // high bits of uint16_t are flags |
| 139 | #define 0x8000 // index is into extras array (not starts array) |
| 140 | #define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing |
| 141 | #define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page |
| 142 | #define DYLD_CACHE_SLIDE_PAGE_VALUE 0x3FFF // bitwise negation of DYLD_CACHE_SLIDE_PAGE_ATTRS |
| 143 | #define DYLD_CACHE_SLIDE_PAGE_OFFSET_SHIFT 2 |
| 144 | |
| 145 | typedef struct vm_shared_region_slide_info_entry_v3 *vm_shared_region_slide_info_entry_v3_t; |
| 146 | struct vm_shared_region_slide_info_entry_v3 { |
| 147 | uint32_t version; // currently 3 |
| 148 | uint32_t page_size; // currently 4096 (may also be 16384) |
| 149 | uint32_t page_starts_count; |
| 150 | uint64_t value_add; |
| 151 | uint16_t page_starts[] /* page_starts_count */; |
| 152 | }; |
| 153 | |
| 154 | #define DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing |
| 155 | |
| 156 | |
| 157 | typedef struct vm_shared_region_slide_info_entry_v4 *vm_shared_region_slide_info_entry_v4_t; |
| 158 | struct vm_shared_region_slide_info_entry_v4 { |
| 159 | uint32_t version; // currently 4 |
| 160 | uint32_t page_size; // currently 4096 (may also be 16384) |
| 161 | uint32_t page_starts_offset; |
| 162 | uint32_t page_starts_count; |
| 163 | uint32_t ; |
| 164 | uint32_t ; |
| 165 | uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location (0xC0000000) |
| 166 | uint64_t value_add; // base address of cache |
| 167 | // uint16_t page_starts[page_starts_count]; |
| 168 | // uint16_t page_extras[page_extras_count]; |
| 169 | }; |
| 170 | |
| 171 | #define DYLD_CACHE_SLIDE4_PAGE_NO_REBASE 0xFFFF // page has no rebasing |
| 172 | #define DYLD_CACHE_SLIDE4_PAGE_INDEX 0x7FFF // index into starts or extras |
| 173 | #define 0x8000 // index is into extras array (not starts array) |
| 174 | #define 0x8000 // last chain entry for page |
| 175 | |
| 176 | |
| 177 | typedef struct vm_shared_region_slide_info_entry_v5 *vm_shared_region_slide_info_entry_v5_t; |
| 178 | struct vm_shared_region_slide_info_entry_v5 { |
| 179 | uint32_t version; // currently 5 |
| 180 | uint32_t page_size; // 16384 |
| 181 | uint32_t page_starts_count; |
| 182 | uint64_t value_add; |
| 183 | uint16_t page_starts[] /* page_starts_count */; |
| 184 | }; |
| 185 | |
| 186 | #define DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing |
| 187 | |
| 188 | |
| 189 | typedef union vm_shared_region_slide_info_entry *vm_shared_region_slide_info_entry_t; |
| 190 | union vm_shared_region_slide_info_entry { |
| 191 | struct { |
| 192 | uint32_t version; |
| 193 | uint32_t page_size; // only valid to use this on version >= 2 |
| 194 | }; |
| 195 | struct vm_shared_region_slide_info_entry_v1 v1; |
| 196 | struct vm_shared_region_slide_info_entry_v2 v2; |
| 197 | struct vm_shared_region_slide_info_entry_v3 v3; |
| 198 | struct vm_shared_region_slide_info_entry_v4 v4; |
| 199 | struct vm_shared_region_slide_info_entry_v5 v5; |
| 200 | }; |
| 201 | |
| 202 | #define MIN_SLIDE_INFO_SIZE \ |
| 203 | MIN(sizeof(struct vm_shared_region_slide_info_entry_v1), \ |
| 204 | MIN(sizeof(struct vm_shared_region_slide_info_entry_v2), \ |
| 205 | MIN(sizeof(struct vm_shared_region_slide_info_entry_v3), \ |
| 206 | MIN(sizeof(struct vm_shared_region_slide_info_entry_v4), \ |
| 207 | sizeof(struct vm_shared_region_slide_info_entry_v5))))) |
| 208 | |
| 209 | /* |
| 210 | * This is the information used by the shared cache pager for sub-sections |
| 211 | * which must be modified for relocations and/or pointer authentications |
| 212 | * before it can be used. The shared_region_pager gets source pages from |
| 213 | * the shared cache file and modifies them -- see shared_region_pager_data_request(). |
| 214 | * |
| 215 | * A single pager may be used from multiple shared regions provided: |
| 216 | * - same si_slide_object, si_start, si_end, si_slide, si_ptrauth and si_jop_key |
| 217 | * - The size and contents of si_slide_info_entry are the same. |
| 218 | */ |
| 219 | typedef struct vm_shared_region_slide_info { |
| 220 | uint32_t si_slide; /* the distance that the file data is relocated */ |
| 221 | bool si_slid; |
| 222 | #if __has_feature(ptrauth_calls) |
| 223 | bool si_ptrauth; |
| 224 | uint64_t si_jop_key; |
| 225 | struct vm_shared_region *si_shared_region; /* so we can ref/dealloc for authenticated slide info */ |
| 226 | #endif /* __has_feature(ptrauth_calls) */ |
| 227 | mach_vm_address_t si_slid_address __kernel_data_semantics; |
| 228 | mach_vm_offset_t si_start __kernel_data_semantics; /* start offset in si_slide_object */ |
| 229 | mach_vm_offset_t si_end __kernel_data_semantics; |
| 230 | vm_object_t si_slide_object; /* The source object for the pages to be modified */ |
| 231 | mach_vm_size_t si_slide_info_size; /* size of dyld provided relocation information */ |
| 232 | vm_shared_region_slide_info_entry_t si_slide_info_entry; /* dyld provided relocation information */ |
| 233 | } *vm_shared_region_slide_info_t; |
| 234 | |
| 235 | /* |
| 236 | * Data structure that represents a unique shared cache region. |
| 237 | */ |
| 238 | struct vm_shared_region { |
| 239 | uint32_t sr_ref_count; |
| 240 | uint32_t sr_slide; |
| 241 | queue_chain_t sr_q; |
| 242 | void *sr_root_dir; |
| 243 | cpu_type_t sr_cpu_type; |
| 244 | cpu_subtype_t sr_cpu_subtype; |
| 245 | ipc_port_t sr_mem_entry; |
| 246 | mach_vm_offset_t sr_first_mapping; |
| 247 | mach_vm_offset_t sr_base_address; |
| 248 | mach_vm_size_t sr_size; |
| 249 | mach_vm_offset_t sr_pmap_nesting_start; |
| 250 | mach_vm_size_t sr_pmap_nesting_size; |
| 251 | thread_call_t sr_timer_call; |
| 252 | uuid_t sr_uuid; |
| 253 | |
| 254 | #if __ARM_MIXED_PAGE_SIZE__ |
| 255 | uint8_t sr_page_shift; |
| 256 | #endif /* __ARM_MIXED_PAGE_SIZE__ */ |
| 257 | thread_t sr_mapping_in_progress; /* sr_first_mapping will be != -1 when done */ |
| 258 | thread_t sr_slide_in_progress; |
| 259 | bool sr_64bit; |
| 260 | bool sr_persists; |
| 261 | bool sr_uuid_copied; |
| 262 | bool sr_stale; /* This region should never be used again. */ |
| 263 | bool sr_driverkit; |
| 264 | |
| 265 | #if __has_feature(ptrauth_calls) |
| 266 | bool sr_reslide; /* Special shared region for suspected attacked processes */ |
| 267 | uint_t sr_num_auth_section; /* num entries in sr_auth_section */ |
| 268 | uint_t sr_next_auth_section; /* used while filling in sr_auth_section */ |
| 269 | vm_shared_region_slide_info_t *sr_auth_section; |
| 270 | #endif /* __has_feature(ptrauth_calls) */ |
| 271 | |
| 272 | uint32_t sr_rsr_version; |
| 273 | |
| 274 | uint64_t sr_install_time; /* mach_absolute_time() of installation into global list */ |
| 275 | uint32_t sr_id; /* identifier for shared cache */ |
| 276 | uint32_t sr_images_count; |
| 277 | struct dyld_uuid_info_64 *sr_images; |
| 278 | }; |
| 279 | |
| 280 | extern kern_return_t vm_shared_region_slide_page( |
| 281 | vm_shared_region_slide_info_t si, |
| 282 | vm_offset_t vaddr, |
| 283 | mach_vm_offset_t uservaddr, |
| 284 | uint32_t pageIndex, |
| 285 | uint64_t jop_key); |
| 286 | extern uint64_t shared_region_find_key(char *shared_region_id); |
| 287 | #else /* !MACH_KERNEL_PRIVATE */ |
| 288 | |
| 289 | struct vm_shared_region; |
| 290 | struct vm_shared_region_slide_info; |
| 291 | struct vm_shared_region_slide_info_entry; |
| 292 | struct slide_info_entry_toc; |
| 293 | |
| 294 | #endif /* MACH_KERNEL_PRIVATE */ |
| 295 | |
| 296 | struct _sr_file_mappings { |
| 297 | int fd; |
| 298 | uint32_t mappings_count; |
| 299 | struct shared_file_mapping_slide_np *mappings; |
| 300 | uint32_t slide; |
| 301 | struct fileproc *fp; |
| 302 | struct vnode *vp; |
| 303 | memory_object_size_t file_size; |
| 304 | memory_object_control_t file_control; |
| 305 | }; |
| 306 | |
| 307 | extern void vm_shared_region_init(void); |
| 308 | extern kern_return_t vm_shared_region_enter( |
| 309 | struct _vm_map *map, |
| 310 | struct task *task, |
| 311 | boolean_t is_64bit, |
| 312 | void *fsroot, |
| 313 | cpu_type_t cpu, |
| 314 | cpu_subtype_t cpu_subtype, |
| 315 | boolean_t reslide, |
| 316 | boolean_t is_driverkit, |
| 317 | uint32_t rsr_version); |
| 318 | extern void vm_shared_region_remove( |
| 319 | struct task *task, |
| 320 | struct vm_shared_region *sr); |
| 321 | extern vm_shared_region_t vm_shared_region_get( |
| 322 | struct task *task); |
| 323 | extern vm_shared_region_t vm_shared_region_trim_and_get( |
| 324 | struct task *task); |
| 325 | extern void vm_shared_region_deallocate( |
| 326 | struct vm_shared_region *shared_region); |
| 327 | extern vm_map_t vm_shared_region_vm_map( |
| 328 | struct vm_shared_region *shared_region); |
| 329 | extern void vm_shared_region_set( |
| 330 | struct task *task, |
| 331 | struct vm_shared_region *new_shared_region); |
| 332 | extern vm_shared_region_t vm_shared_region_lookup( |
| 333 | void *root_dir, |
| 334 | cpu_type_t cpu, |
| 335 | cpu_subtype_t cpu_subtype, |
| 336 | boolean_t is_64bit, |
| 337 | int target_page_shift, |
| 338 | boolean_t reslide, |
| 339 | boolean_t is_driverkit, |
| 340 | uint32_t rsr_version); |
| 341 | extern kern_return_t vm_shared_region_start_address( |
| 342 | struct vm_shared_region *shared_region, |
| 343 | mach_vm_offset_t *start_address, |
| 344 | task_t task); |
| 345 | extern void vm_shared_region_undo_mappings( |
| 346 | vm_map_t sr_map, |
| 347 | mach_vm_offset_t sr_base_address, |
| 348 | struct _sr_file_mappings *srf_mappings, |
| 349 | struct _sr_file_mappings *srf_mappings_count, |
| 350 | unsigned int mappings_count); |
| 351 | __attribute__((noinline)) |
| 352 | extern kern_return_t vm_shared_region_map_file( |
| 353 | struct vm_shared_region *shared_region, |
| 354 | int sr_mappings_count, |
| 355 | struct _sr_file_mappings *sr_mappings); |
| 356 | extern void *vm_shared_region_root_dir( |
| 357 | struct vm_shared_region *shared_region); |
| 358 | extern kern_return_t vm_shared_region_sliding_valid(uint32_t slide); |
| 359 | extern void vm_commpage_init(void); |
| 360 | extern void vm_commpage_text_init(void); |
| 361 | extern kern_return_t vm_commpage_enter( |
| 362 | struct _vm_map *map, |
| 363 | struct task *task, |
| 364 | boolean_t is64bit); |
| 365 | extern kern_return_t vm_commpage_remove( |
| 366 | struct _vm_map *map, |
| 367 | struct task *task); |
| 368 | int vm_shared_region_slide(uint32_t, |
| 369 | mach_vm_offset_t, |
| 370 | mach_vm_size_t, |
| 371 | mach_vm_offset_t, |
| 372 | mach_vm_size_t, |
| 373 | mach_vm_offset_t, |
| 374 | memory_object_control_t, |
| 375 | vm_prot_t); |
| 376 | extern void vm_shared_region_pivot(void); |
| 377 | extern void vm_shared_region_reslide_stale(boolean_t driverkit); |
| 378 | #if __has_feature(ptrauth_calls) |
| 379 | __attribute__((noinline)) |
| 380 | extern kern_return_t vm_shared_region_auth_remap(vm_shared_region_t sr); |
| 381 | #endif /* __has_feature(ptrauth_calls) */ |
| 382 | extern void vm_shared_region_reference(vm_shared_region_t sr); |
| 383 | |
| 384 | #endif /* KERNEL_PRIVATE */ |
| 385 | |
| 386 | #endif /* _VM_SHARED_REGION_H_ */ |
| 387 | |