3 #include <mach-o/fixup-chains.h>
4 #include <mach-o/loader.h>
6 #include "kernel-fixups.h"
8 #ifndef LC_FILESET_ENTRY
9 #define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD) /* used with fileset_entry_command */
10 struct fileset_entry_command
{
11 uint32_t cmd
; /* LC_FILESET_ENTRY */
12 uint32_t cmdsize
; /* includes id string */
13 uint64_t vmaddr
; /* memory address of the dylib */
14 uint64_t fileoff
; /* file offset of the dylib */
15 union lc_str entry_id
; /* contained entry id */
16 uint32_t reserved
; /* entry_id is 32-bits long, so this is the reserved padding */
20 typedef int (*ModInitLogFunc
)(const char*, ...);
21 static const int LogModInits
= 0;
23 struct TestRunnerFunctions
;
24 typedef int (*InitializerFunc
)(const TestRunnerFunctions
*);
27 __attribute__((section(("__HIB, __text"))))
29 __attribute__((section(("__TEXT_EXEC, __text"))))
31 static int getSlide(const struct mach_header
* mh
, ModInitLogFunc logFunc
,
33 uint64_t textVMAddr
= 0;
36 logFunc("[LOG] kernel-slide: mh %p\n", mh
);
40 logFunc("[LOG] kernel-slide: parsing load commands\n");
43 const struct load_command
* startCmds
= 0;
44 if ( mh
->magic
== MH_MAGIC_64
)
45 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header_64
));
46 else if ( mh
->magic
== MH_MAGIC
)
47 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
49 const uint32_t* h
= (uint32_t*)mh
;
50 //diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
51 return 1; // not a mach-o file
53 const struct load_command
* const cmdsEnd
= (struct load_command
*)((char*)startCmds
+ mh
->sizeofcmds
);
54 const struct load_command
* cmd
= startCmds
;
55 for (uint32_t i
= 0; i
< mh
->ncmds
; ++i
) {
57 logFunc("[LOG] kernel-slide: parsing load command %d with cmd=0x%x\n", i
, cmd
->cmd
);
59 const struct load_command
* nextCmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
60 if ( cmd
->cmdsize
< 8 ) {
61 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
64 if ( (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
65 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
68 if ( cmd
->cmd
== LC_SEGMENT_64
) {
69 const struct segment_command_64
* seg
= (const struct segment_command_64
*)cmd
;
70 if ( areEqual(seg
->segname
, "__TEXT") ) {
71 textVMAddr
= seg
->vmaddr
;
77 *slide
= (uintptr_t)mh
- textVMAddr
;
82 __attribute__((section(("__HIB, __text"))))
84 __attribute__((section(("__TEXT_EXEC, __text"))))
86 static int runAllModInitFunctions(const struct mach_header
* mh
, ModInitLogFunc logFunc
,
87 const TestRunnerFunctions
* funcs
) {
89 if ( getSlide(mh
, logFunc
, &slide
) != 0 ) {
93 const struct load_command
* startCmds
= 0;
94 if ( mh
->magic
== MH_MAGIC_64
)
95 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header_64
));
96 else if ( mh
->magic
== MH_MAGIC
)
97 startCmds
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
99 const uint32_t* h
= (uint32_t*)mh
;
100 //diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
101 return 1; // not a mach-o file
104 const struct load_command
* const cmdsEnd
= (struct load_command
*)((char*)startCmds
+ mh
->sizeofcmds
);
105 const struct load_command
* cmd
= startCmds
;
106 for (uint32_t i
= 0; i
< mh
->ncmds
; ++i
) {
108 logFunc("[LOG] kernel-mod-inits: parsing load command %d with cmd=0x%x\n", i
, cmd
->cmd
);
110 const struct load_command
* nextCmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
111 if ( cmd
->cmdsize
< 8 ) {
112 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
115 if ( (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
116 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
119 if ( cmd
->cmd
== LC_SEGMENT_64
) {
120 const struct segment_command_64
* seg
= (const struct segment_command_64
*)cmd
;
121 const struct section_64
* const sectionsStart
= (struct section_64
*)((char*)seg
+ sizeof(struct segment_command_64
));
122 const struct section_64
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
123 for (const struct section_64
* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
124 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
126 logFunc("[LOG] kernel-mod-inits: section: %s %s\n", sect
->segname
, sect
->sectname
);
128 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
129 InitializerFunc
* inits
= (InitializerFunc
*)(sect
->addr
+ slide
);
130 const uintptr_t count
= sect
->size
/ sizeof(uintptr_t);
131 // Ensure __mod_init_func section is within segment
132 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) ) {
133 logFunc("[LOG] kernel-mod-inits: __mod_init_funcs section has malformed address range\n");
136 for (uintptr_t j
= 0; j
< count
; ++j
) {
137 InitializerFunc func
= inits
[j
];
138 #if __has_feature(ptrauth_calls)
139 func
= (InitializerFunc
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0);
142 logFunc("[LOG] kernel-mod-inits: running mod init %p\n", (const void*)func
);
144 int initResult
= func(funcs
);
145 if ( initResult
!= 0 ) {
146 logFunc("[LOG] kernel-mod-inits: mod init %p, result = %d\n", (const void*)func
, initResult
);
160 __attribute__((section(("__HIB, __text"))))
162 __attribute__((section(("__TEXT_EXEC, __text"))))
164 static int runAllModInitFunctionsForAppCache(const struct mach_header
* appCacheMH
, ModInitLogFunc logFunc
,
165 const TestRunnerFunctions
* funcs
) {
167 if ( getSlide(appCacheMH
, logFunc
, &slide
) != 0 ) {
172 logFunc("[LOG] mod-init: appCacheMH %p\n", appCacheMH
);
176 logFunc("[LOG] mod-init: parsing load commands\n");
179 const struct load_command
* startCmds
= 0;
180 if ( appCacheMH
->magic
== MH_MAGIC_64
)
181 startCmds
= (struct load_command
*)((char *)appCacheMH
+ sizeof(struct mach_header_64
));
182 else if ( appCacheMH
->magic
== MH_MAGIC
)
183 startCmds
= (struct load_command
*)((char *)appCacheMH
+ sizeof(struct mach_header
));
185 const uint32_t* h
= (uint32_t*)appCacheMH
;
186 //diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
187 return 1; // not a mach-o file
189 const struct load_command
* const cmdsEnd
= (struct load_command
*)((char*)startCmds
+ appCacheMH
->sizeofcmds
);
190 const struct load_command
* cmd
= startCmds
;
191 for (uint32_t i
= 0; i
< appCacheMH
->ncmds
; ++i
) {
193 logFunc("[LOG] mod-init: parsing load command %d with cmd=0x%x\n", i
, cmd
->cmd
);
195 const struct load_command
* nextCmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
196 if ( cmd
->cmdsize
< 8 ) {
197 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
200 if ( (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
201 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
204 if ( cmd
->cmd
== LC_FILESET_ENTRY
) {
205 const struct fileset_entry_command
* app_cache_cmd
= (const struct fileset_entry_command
*)cmd
;
206 const char* name
= (char*)app_cache_cmd
+ app_cache_cmd
->entry_id
.offset
;
207 const struct mach_header
* mh
= (const struct mach_header
*)(app_cache_cmd
->vmaddr
+ slide
);
209 logFunc("[LOG] mod-init: Running mod inits for %p: %s\n", mh
, name
);
211 int result
= runAllModInitFunctions(mh
, logFunc
, funcs
);
223 __attribute__((section(("__HIB, __text"))))
225 __attribute__((section(("__TEXT_EXEC, __text"))))
227 static int slideKextsInsideKernelCollection(const struct mach_header
* appCacheMH
, const void* basePointers
[4],
228 FixupsLogFunc logFunc
, const TestRunnerFunctions
* funcs
) {
229 uintptr_t slideAmount
= 0;
230 if ( getSlide(appCacheMH
, logFunc
, &slideAmount
) != 0 ) {
235 logFunc("[LOG] slide-pageable: appCacheMH %p\n", appCacheMH
);
239 logFunc("[LOG] slide-pageable: parsing load commands\n");
242 const struct load_command
* startCmds
= 0;
243 if ( appCacheMH
->magic
== MH_MAGIC_64
)
244 startCmds
= (struct load_command
*)((char *)appCacheMH
+ sizeof(struct mach_header_64
));
245 else if ( appCacheMH
->magic
== MH_MAGIC
)
246 startCmds
= (struct load_command
*)((char *)appCacheMH
+ sizeof(struct mach_header
));
248 const uint32_t* h
= (uint32_t*)appCacheMH
;
249 //diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
250 return 1; // not a mach-o file
252 const struct load_command
* const cmdsEnd
= (struct load_command
*)((char*)startCmds
+ appCacheMH
->sizeofcmds
);
253 const struct load_command
* cmd
= startCmds
;
254 for (uint32_t i
= 0; i
< appCacheMH
->ncmds
; ++i
) {
256 logFunc("[LOG] slide-pageable: parsing load command %d with cmd=0x%x\n", i
, cmd
->cmd
);
258 const struct load_command
* nextCmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
259 if ( cmd
->cmdsize
< 8 ) {
260 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
263 if ( (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
264 //diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
267 if ( cmd
->cmd
== LC_FILESET_ENTRY
) {
268 const struct fileset_entry_command
* app_cache_cmd
= (const struct fileset_entry_command
*)cmd
;
269 const char* name
= (char*)app_cache_cmd
+ app_cache_cmd
->entry_id
.offset
;
270 const struct mach_header
* mh
= (const struct mach_header
*)(app_cache_cmd
->vmaddr
+ slideAmount
);
272 logFunc("[LOG] slide-pageable: Sliding %p: %s\n", mh
, name
);
274 int slideReturnCode
= slide(mh
, basePointers
, logFunc
);
275 if ( slideReturnCode
!= 0 ) {
276 FAIL("mh slide = %d\n", slideReturnCode
);