Skip to content

Commit

Permalink
Hopefully fix spinlock panics (works in conjunction with new ellekit)
Browse files Browse the repository at this point in the history
  • Loading branch information
opa334 committed Apr 26, 2024
1 parent 02ce434 commit 04e370c
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 19 deletions.
28 changes: 27 additions & 1 deletion BaseBin/forkfix/src/litehook.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <mach-o/dyld.h>
#include <dlfcn.h>
#include <libkern/OSCacheControl.h>
#include <libjailbreak/jbclient_xpc.h>
#include <libjailbreak/dyld.h>

#ifdef __arm64e__
static uint64_t __attribute((naked)) __xpaci(uint64_t a)
Expand Down Expand Up @@ -84,6 +86,31 @@ kern_return_t litehook_hook_function(void *source, void *target)

uint32_t *toHook = (uint32_t*)xpaci((uint64_t)source);
uint64_t target64 = (uint64_t)xpaci((uint64_t)target);
uint32_t hookSize = 5 * sizeof(uint32_t);

#ifdef __arm64e__
if (__builtin_available(iOS 16.0, *)) { }
else {
// Also apply spinlock fix here
static uint64_t dscSlide = 0;
static dispatch_once_t ot;
dispatch_once(&ot, ^{
task_dyld_info_data_t dyldInfo;
uint32_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&dyldInfo, &count);
DyldAllImageInfos64 *infos = (DyldAllImageInfos64 *)dyldInfo.all_image_info_addr;
dscSlide = infos->shared_cache_slide;
});

Dl_info targetInfo;
if (dladdr(toHook, &targetInfo) != 0) {
if (_dyld_shared_cache_contains_path(targetInfo.dli_fname)) {
uint64_t unslidTarget = (uint64_t)toHook - dscSlide;
jbclient_mlock_dsc(unslidTarget, hookSize);
}
}
}
#endif

kr = litehook_unprotect((vm_address_t)toHook, 5*4);
if (kr != KERN_SUCCESS) return kr;
Expand All @@ -93,7 +120,6 @@ kern_return_t litehook_hook_function(void *source, void *target)
toHook[2] = movk(16, target64 >> 32, 32);
toHook[3] = movk(16, target64 >> 48, 48);
toHook[4] = br(16);
uint32_t hookSize = 5 * sizeof(uint32_t);

kr = litehook_protect((vm_address_t)toHook, hookSize);
if (kr != KERN_SUCCESS) return kr;
Expand Down
27 changes: 27 additions & 0 deletions BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <libjailbreak/util.h>
#include <libjailbreak/primitives.h>
#include <libjailbreak/codesign.h>
#include "../mlock_dsc.h"

extern bool stringEndsWith(const char* str, const char* suffix);

Expand Down Expand Up @@ -245,6 +246,22 @@ static int systemwide_cs_revalidate(audit_token_t *callerToken)
return -1;
}

static int systemwide_mlock_dsc(audit_token_t *callerToken, uint64_t unslidStart, uint64_t size)
{
#if 1
uint64_t pid = audit_token_to_pid(*callerToken);
char procPath[4*MAXPATHLEN];
if (proc_pidpath(pid, procPath, sizeof(procPath)) < 0) {
return -1;
}
FILE *f = fopen("/var/mobile/launchd_dsc_lock.log", "a");
fprintf(f, "[%s] mlock_dsc(addr: 0x%llx, size: 0x%llx)\n", procPath, unslidStart, size);
fclose(f);
#endif

return mlock_dsc(unslidStart, size);
}

struct jbserver_domain gSystemwideDomain = {
.permissionHandler = systemwide_domain_allowed,
.actions = {
Expand Down Expand Up @@ -310,6 +327,16 @@ struct jbserver_domain gSystemwideDomain = {
{ 0 },
},
},
// JBS_SYSTEMWIDE_MLOCK_DSC
{
.handler = systemwide_mlock_dsc,
.args = (jbserver_arg[]) {
{ .name = "caller-token", .type = JBS_TYPE_CALLER_TOKEN, .out = false },
{ .name = "unslid-addr", .type = JBS_TYPE_UINT64, .out = false },
{ .name = "size", .type = JBS_TYPE_UINT64, .out = false },
{ 0 },
},
},
{ 0 },
},
};
1 change: 1 addition & 0 deletions BaseBin/launchdhook/src/mlock_dsc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int mlock_dsc(uint64_t unslid_addr, size_t size);
68 changes: 68 additions & 0 deletions BaseBin/launchdhook/src/mlock_dsc.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#import <Foundation/Foundation.h>
#import <dlfcn.h>
#import <libjailbreak/libjailbreak.h>
#import <sys/param.h>
#import <sys/mount.h>
#import <objc/runtime.h>
#import <sys/mman.h>
#import <libjailbreak/dyld.h>

struct dsc_text_segment {
void *mapping;
uint64_t offset;
uint64_t address;
uint64_t size;
};

int mlock_dsc(uint64_t unslid_addr, size_t size)
{
static struct dsc_text_segment *segments = NULL;
static int segmentCount = 0;
static dispatch_once_t ot;
dispatch_once(&ot, ^{
NSURL *dscURL = [NSURL fileURLWithPath:@"/System/Library/Caches/com.apple.dyld" isDirectory:YES];
for (NSURL *partURL in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:dscURL includingPropertiesForKeys:nil options:0 error:nil]) {
if (![partURL.pathExtension isEqualToString:@"symbols"]) {
FILE *f = fopen(partURL.fileSystemRepresentation, "r");
if (f) {
fseek(f, 0, SEEK_SET);
struct dyld_cache_header header = { 0 };
if (fread(&header, sizeof(header), 1, f) == 1) {
for (uint32_t i = 0; i < header.mappingCount; i++) {
uint32_t curMappingOff = header.mappingOffset + (i * sizeof(struct dyld_cache_mapping_info));
fseek(f, curMappingOff, SEEK_SET);
struct dyld_cache_mapping_info curMapping = { 0 };
if (fread(&curMapping, sizeof(curMapping), 1, f) == 1) {
if (curMapping.initProt & PROT_EXEC) {
void *textMap = mmap(NULL, curMapping.size, PROT_READ, MAP_SHARED, fileno(f), curMapping.fileOffset);
if (textMap != MAP_FAILED) {
segmentCount++;
segments = realloc(segments, segmentCount * sizeof(struct dsc_text_segment));
segments[segmentCount-1] = (struct dsc_text_segment){
.mapping = textMap,
.offset = curMapping.fileOffset,
.address = curMapping.address,
.size = curMapping.size,
};
}
}
}
}
}
fclose(f);
}
}
}
});

for (int i = 0; i < segmentCount; i++) {
struct dsc_text_segment *curSegment = &segments[i];
if (unslid_addr >= curSegment->address && (unslid_addr + size) < (curSegment->address + curSegment->size)) {
uint64_t rel = unslid_addr - curSegment->address;
void *start = (void *)((uint64_t)curSegment->mapping + rel);
return mlock(start, size);
}
}

return -1;
}
96 changes: 96 additions & 0 deletions BaseBin/libjailbreak/src/dyld.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
struct dyld_cache_header
{
char magic[16]; // e.g. "dyld_v0 i386"
uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
uint32_t mappingCount; // number of dyld_cache_mapping_info entries
uint32_t imagesOffset; // file offset to first dyld_cache_image_info
uint32_t imagesCount; // number of dyld_cache_image_info entries
uint64_t dyldBaseAddress; // base address of dyld when cache was built
uint64_t codeSignatureOffset; // file offset of code signature blob
uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file)
uint64_t slideInfoOffsetUnused; // unused. Used to be file offset of kernel slid info
uint64_t slideInfoSizeUnused; // unused. Used to be size of kernel slid info
uint64_t localSymbolsOffset; // file offset of where local symbols are stored
uint64_t localSymbolsSize; // size of local symbols information
uint8_t uuid[16]; // unique value for each shared cache file
uint64_t cacheType; // 0 for development, 1 for production
uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses
uint32_t branchPoolsCount; // number of uint64_t entries
uint64_t accelerateInfoAddr; // (unslid) address of optimization info
uint64_t accelerateInfoSize; // size of optimization info
uint64_t imagesTextOffset; // file offset to first dyld_cache_image_text_info
uint64_t imagesTextCount; // number of dyld_cache_image_text_info entries
uint64_t patchInfoAddr; // (unslid) address of dyld_cache_patch_info
uint64_t patchInfoSize; // Size of all of the patch information pointed to via the dyld_cache_patch_info
uint64_t otherImageGroupAddrUnused; // unused
uint64_t otherImageGroupSizeUnused; // unused
uint64_t progClosuresAddr; // (unslid) address of list of program launch closures
uint64_t progClosuresSize; // size of list of program launch closures
uint64_t progClosuresTrieAddr; // (unslid) address of trie of indexes into program launch closures
uint64_t progClosuresTrieSize; // size of trie of indexes into program launch closures
uint32_t platform; // platform number (macOS=1, etc)
uint32_t formatVersion : 8, // dyld3::closure::kFormatVersion
dylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid
simulator : 1, // for simulator of specified platform
locallyBuiltCache : 1, // 0 for B&I built cache, 1 for locally built cache
builtFromChainedFixups : 1, // some dylib in cache was built using chained fixups, so patch tables must be used for overrides
padding : 20; // TBD
uint64_t sharedRegionStart; // base load address of cache if not slid
uint64_t sharedRegionSize; // overall size of region cache can be mapped into
uint64_t maxSlide; // runtime slide of cache can be between zero and this value
uint64_t dylibsImageArrayAddr; // (unslid) address of ImageArray for dylibs in this cache
uint64_t dylibsImageArraySize; // size of ImageArray for dylibs in this cache
uint64_t dylibsTrieAddr; // (unslid) address of trie of indexes of all cached dylibs
uint64_t dylibsTrieSize; // size of trie of cached dylib paths
uint64_t otherImageArrayAddr; // (unslid) address of ImageArray for dylibs and bundles with dlopen closures
uint64_t otherImageArraySize; // size of ImageArray for dylibs and bundles with dlopen closures
uint64_t otherTrieAddr; // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures
uint64_t otherTrieSize; // size of trie of dylibs and bundles with dlopen closures
uint32_t mappingWithSlideOffset; // file offset to first dyld_cache_mapping_and_slide_info
uint32_t mappingWithSlideCount; // number of dyld_cache_mapping_and_slide_info entries
};

struct dyld_cache_mapping_info {
uint64_t address;
uint64_t size;
uint64_t fileOffset;
uint32_t maxProt;
uint32_t initProt;
};

struct _DyldAllImageInfos64
{
uint32_t version;
uint32_t info_array_count;
uint64_t info_array;
uint64_t notification;
uint8_t process_detached_from_shared_region;
uint8_t libsystem_initialized;
uint32_t padding;
uint64_t dyld_image_load_address;
uint64_t jit_info;
uint64_t dyld_version;
uint64_t error_message;
uint64_t termination_flags;
uint64_t core_symbolication_shm_page;
uint64_t system_order_flag;
uint64_t uuid_array_count;
uint64_t uuid_array;
uint64_t dyld_all_image_infos_address;
uint64_t initial_image_count;
uint64_t error_kind;
uint64_t error_client_of_dylib_path;
uint64_t error_target_dylib_path;
uint64_t error_symbol;
uint64_t shared_cache_slide;
uint8_t shared_cache_uuid[16];
uint64_t shared_cache_base_address;
volatile uint64_t info_array_change_timestamp;
uint64_t dyld_path;
uint32_t notify_mach_ports[8];
uint64_t reserved[9];
uint64_t compact_dyld_image_info_addr;
uint64_t compact_dyld_image_info_size;
uint32_t platform;
};
typedef struct _DyldAllImageInfos64 DyldAllImageInfos64;
15 changes: 15 additions & 0 deletions BaseBin/libjailbreak/src/jbclient_xpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,21 @@ int jbclient_cs_revalidate(void)
return -1;
}

int jbclient_mlock_dsc(uint64_t unslidAddr, uint64_t size)
{
xpc_object_t xargs = xpc_dictionary_create_empty();
xpc_dictionary_set_uint64(xargs, "unslid-addr", unslidAddr);
xpc_dictionary_set_uint64(xargs, "size", size);
xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_MLOCK_DSC, xargs);
xpc_release(xargs);
if (xreply) {
int result = xpc_dictionary_get_int64(xreply, "result");
xpc_release(xreply);
return result;
}
return -1;
}

int jbclient_platform_set_process_debugged(uint64_t pid, bool fullyDebugged)
{
xpc_object_t xargs = xpc_dictionary_create_empty();
Expand Down
1 change: 1 addition & 0 deletions BaseBin/libjailbreak/src/jbclient_xpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ int jbclient_trust_library(const char *libraryPath, void *addressInCaller);
int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut);
int jbclient_fork_fix(uint64_t childPid);
int jbclient_cs_revalidate(void);
int jbclient_mlock_dsc(uint64_t unslidAddr, uint64_t size);
int jbclient_platform_set_process_debugged(uint64_t pid, bool fullyDebugged);
int jbclient_platform_stage_jailbreak_update(const char *updateTar);
int jbclient_watchdog_intercept_userspace_panic(const char *panicMessage);
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/libjailbreak/src/jbserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum {
JBS_SYSTEMWIDE_PROCESS_CHECKIN,
JBS_SYSTEMWIDE_FORK_FIX,
JBS_SYSTEMWIDE_CS_REVALIDATE,
// JBS_SYSTEMWIDE_LOCK_PAGE,
JBS_SYSTEMWIDE_MLOCK_DSC,
};

// Domain: Platform
Expand Down
58 changes: 58 additions & 0 deletions BaseBin/systemhook/src/ellekit_custom.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <stdio.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include <libjailbreak/dyld.h>
#include <libjailbreak/jbclient_xpc.h>
#include "common.h"
#include <os/log.h>

static kern_return_t (*EKHookMemoryRaw_orig)(void *target, const void *data, size_t size);
static kern_return_t EKHookMemoryRaw_impl(void *target, const void *data, size_t size)
{
static uint64_t dscSlide = 0;
static dispatch_once_t ot;
dispatch_once(&ot, ^{
task_dyld_info_data_t dyldInfo;
uint32_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&dyldInfo, &count);
DyldAllImageInfos64 *infos = (DyldAllImageInfos64 *)dyldInfo.all_image_info_addr;
dscSlide = infos->shared_cache_slide;
});

Dl_info targetInfo;
if (dladdr(target, &targetInfo) != 0) {
if (_dyld_shared_cache_contains_path(targetInfo.dli_fname)) {
uint64_t unslidTarget = (uint64_t)target - dscSlide;
jbclient_mlock_dsc(unslidTarget, size);
}
}

return EKHookMemoryRaw_orig(target, data, size);
}

static bool ignore_images = true;
static void image_added(const struct mach_header *mh, intptr_t vmaddr_slide)
{
if (ignore_images) return;

Dl_info info;
if (dladdr(mh, &info) != 0) {
if (stringEndsWith(info.dli_fname, "/usr/lib/libellekit.dylib")) {
void *handle = dlopen(info.dli_fname, RTLD_NOLOAD);
kern_return_t (**EKHookMemoryRaw)(void *, const void *, size_t) = dlsym(handle, "EKHookMemoryRaw");
if (EKHookMemoryRaw) {
EKHookMemoryRaw_orig = *EKHookMemoryRaw;
*EKHookMemoryRaw = EKHookMemoryRaw_impl;
}
ignore_images = true;
}
}
}

void enable_ellekit_custom_memory_hooks(void)
{
_dyld_register_func_for_add_image(image_added);
ignore_images = false;
}
1 change: 1 addition & 0 deletions BaseBin/systemhook/src/ellekit_custom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
void enable_ellekit_custom_memory_hooks(void);
Loading

0 comments on commit 04e370c

Please sign in to comment.