Skip to content

Commit

Permalink
Fix codesign bypass not working when passing an archpref to posix_spawn
Browse files Browse the repository at this point in the history
  • Loading branch information
opa334 committed May 23, 2024
1 parent 43cf5c5 commit cdd113f
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Application/Dopamine/Jailbreak/DOJailbreaker.m
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ - (NSError *)createFakeLib

cdhash_t *cdhashes = NULL;
uint32_t cdhashesCount = 0;
macho_collect_untrusted_cdhashes(JBRootPath("/basebin/.fakelib/dyld"), NULL, NULL, &cdhashes, &cdhashesCount);
macho_collect_untrusted_cdhashes(JBRootPath("/basebin/.fakelib/dyld"), NULL, NULL, NULL, NULL, 0, &cdhashes, &cdhashesCount);
if (cdhashesCount != 1) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Got unexpected number of cdhashes for dyld???: %d", cdhashesCount]}];

trustcache_file_v1 *dyldTCFile = NULL;
Expand Down
25 changes: 20 additions & 5 deletions BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ static int systemwide_get_boot_uuid(char **bootUUIDOut)
return 0;
}

static int trust_file(const char *filePath, const char *dlopenCallerImagePath, const char *dlopenCallerExecutablePath)
static int trust_file(const char *filePath, const char *dlopenCallerImagePath, const char *dlopenCallerExecutablePath, xpc_object_t preferredArchsArray)
{
// Shared logic between client and server, implemented in client
// This should essentially mean these files never reach us in the first place
Expand All @@ -76,9 +76,23 @@ static int trust_file(const char *filePath, const char *dlopenCallerImagePath, c

if (can_skip_trusting_file(filePath, (bool)dlopenCallerExecutablePath, false)) return -1;

size_t preferredArchCount = 0;
if (preferredArchsArray) preferredArchCount = xpc_array_get_count(preferredArchsArray);
uint32_t preferredArchTypes[preferredArchCount];
uint32_t preferredArchSubtypes[preferredArchCount];
for (size_t i = 0; i < preferredArchCount; i++) {
preferredArchTypes[i] = 0;
preferredArchSubtypes[i] = UINT32_MAX;
xpc_object_t arch = xpc_array_get_value(preferredArchsArray, i);
if (xpc_get_type(arch) == XPC_TYPE_DICTIONARY) {
preferredArchTypes[i] = xpc_dictionary_get_uint64(arch, "type");
preferredArchSubtypes[i] = xpc_dictionary_get_uint64(arch, "subtype");
}
}

cdhash_t *cdhashes = NULL;
uint32_t cdhashesCount = 0;
macho_collect_untrusted_cdhashes(filePath, dlopenCallerImagePath, dlopenCallerExecutablePath, &cdhashes, &cdhashesCount);
macho_collect_untrusted_cdhashes(filePath, dlopenCallerImagePath, dlopenCallerExecutablePath, preferredArchTypes, preferredArchSubtypes, preferredArchCount, &cdhashes, &cdhashesCount);
if (cdhashes && cdhashesCount > 0) {
jb_trustcache_add_cdhashes(cdhashes, cdhashesCount);
free(cdhashes);
Expand All @@ -87,9 +101,9 @@ static int trust_file(const char *filePath, const char *dlopenCallerImagePath, c
}

// Not static because launchd will directly call this from it's posix_spawn hook
int systemwide_trust_binary(const char *binaryPath)
int systemwide_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray)
{
return trust_file(binaryPath, NULL, NULL);
return trust_file(binaryPath, NULL, NULL, preferredArchsArray);
}

static int systemwide_trust_library(audit_token_t *processToken, const char *libraryPath, const char *callerLibraryPath)
Expand All @@ -105,7 +119,7 @@ static int systemwide_trust_library(audit_token_t *processToken, const char *lib
// This is to support dlopen("@executable_path/whatever", RTLD_NOW) and stuff like that
// (Yes that is a thing >.<)
// Also we need to pass the path of the image that called dlopen due to @loader_path, sigh...
return trust_file(libraryPath, callerLibraryPath, callerPath);
return trust_file(libraryPath, callerLibraryPath, callerPath, NULL);
}

static int systemwide_process_checkin(audit_token_t *processToken, char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut)
Expand Down Expand Up @@ -343,6 +357,7 @@ struct jbserver_domain gSystemwideDomain = {
.handler = systemwide_trust_binary,
.args = (jbserver_arg[]){
{ .name = "binary-path", .type = JBS_TYPE_STRING, .out = false },
{ .name = "preferred-archs", .type = JBS_TYPE_ARRAY, .out = false },
{ 0 },
},
},
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/launchdhook/src/spawn_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <sys/mount.h>
extern char **environ;

extern int systemwide_trust_binary(const char *binaryPath);
extern int systemwide_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray);
extern int platform_set_process_debugged(uint64_t pid, bool fullyDebugged);

#define LOG_PROCESS_LAUNCHES 0
Expand Down
5 changes: 4 additions & 1 deletion BaseBin/libjailbreak/src/jbclient_xpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ char *realafpath(const char *restrict path, char *restrict resolved_path)
}
}

int jbclient_trust_binary(const char *binaryPath)
int jbclient_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray)
{
if (!binaryPath) return -1;

Expand All @@ -195,6 +195,9 @@ int jbclient_trust_binary(const char *binaryPath)

xpc_object_t xargs = xpc_dictionary_create_empty();
xpc_dictionary_set_string(xargs, "binary-path", absolutePath);
if (preferredArchsArray) {
xpc_dictionary_set_value(xargs, "preferred-archs", preferredArchsArray);
}
xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_TRUST_BINARY, xargs);
xpc_release(xargs);
if (xreply) {
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/libjailbreak/src/jbclient_xpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ xpc_object_t jbserver_xpc_send(uint64_t domain, uint64_t action, xpc_object_t xa

char *jbclient_get_jbroot(void);
char *jbclient_get_boot_uuid(void);
int jbclient_trust_binary(const char *binaryPath);
int jbclient_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray);
int jbclient_trust_library(const char *libraryPath, void *addressInCaller);
int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut);
int jbclient_fork_fix(uint64_t childPid);
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/libjailbreak/src/signatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
#include <choma/CodeDirectory.h>

typedef uint8_t cdhash_t[CS_CDHASH_LEN];
void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut);
void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, uint32_t *preferredArchTypes, uint32_t *preferredArchSubtypes, size_t preferredArchCount, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut);

#endif
26 changes: 23 additions & 3 deletions BaseBin/libjailbreak/src/signatures.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ bool csd_superblob_is_adhoc_signed(CS_DecodedSuperBlob *superblob)
}
}

void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut)
void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, uint32_t *preferredArchTypes, uint32_t *preferredArchSubtypes, size_t preferredArchCount, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut)
{
@autoreleasepool {
if (!path) return;
Expand All @@ -140,7 +140,16 @@ void macho_collect_untrusted_cdhashes(const char *path, const char *callerImageP
if (!callerExecutablePath) {
FAT *mainFAT = fat_init_from_path(path);
if (mainFAT) {
MachO *mainMachO = ljb_fat_find_preferred_slice(mainFAT);
MachO *mainMachO = NULL;
if (preferredArchCount > 0) {
for (size_t i = 0; i < preferredArchCount; i++) {
if (preferredArchTypes[i] != 0 && preferredArchSubtypes[i] != UINT32_MAX) {
mainMachO = fat_find_slice(mainFAT, preferredArchTypes[i], preferredArchSubtypes[i]);
if (mainMachO) break;
}
}
}
if (!mainMachO) mainMachO = ljb_fat_find_preferred_slice(mainFAT);
if (mainMachO) {
if (macho_get_filetype(mainMachO) == MH_EXECUTE) {
callerExecutablePath = path;
Expand All @@ -160,7 +169,18 @@ void macho_collect_untrusted_cdhashes(const char *path, const char *callerImageP
NSString *resolvedBinaryPath = resolveDependencyPath(binaryPath, sourceImagePath, sourceExecutablePath);
FAT *fat = fat_init_from_path(resolvedBinaryPath.fileSystemRepresentation);
if (!fat) return;
MachO *macho = ljb_fat_find_preferred_slice(fat);
MachO *macho = NULL;
if ([binaryPath isEqualToString:sourceExecutablePath]) {
if (preferredArchCount > 0) {
for (size_t i = 0; i < preferredArchCount; i++) {
if (preferredArchTypes[i] != 0 && preferredArchSubtypes[i] != UINT32_MAX) {
macho = fat_find_slice(fat, preferredArchTypes[i], preferredArchSubtypes[i]);
if (macho) break;
}
}
}
}
if (!macho) macho = ljb_fat_find_preferred_slice(fat);
if (!macho) {
fat_free(fat);
return;
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/libjailbreak/src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ int exec_cmd_suspended(pid_t *pidOut, const char *binary, ...);
int exec_cmd_root(const char *binary, ...);

#define exec_cmd_trusted(x, args ...) ({ \
jbclient_trust_binary(x); \
jbclient_trust_binary(x, NULL); \
int retval; \
retval = exec_cmd(x, args); \
retval; \
Expand Down
36 changes: 33 additions & 3 deletions BaseBin/systemhook/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path,
char *const argv[restrict],
char *const envp[restrict],
void *orig,
int (*trust_binary)(const char *),
int (*trust_binary)(const char *path, xpc_object_t preferredArchsArray),
int (*set_process_debugged)(uint64_t pid, bool fullyDebugged))
{
int (*pspawn_orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]) = orig;
Expand All @@ -244,8 +244,38 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path,
kBinaryConfig binaryConfig = configForBinary(path, argv);

if (!(binaryConfig & kBinaryConfigDontProcess)) {

bool preferredArchsSet = false;
cpu_type_t preferredTypes[4];
cpu_subtype_t preferredSubtypes[4];
size_t sizeOut = 0;
if (posix_spawnattr_getarchpref_np(attrp, 4, preferredTypes, preferredSubtypes, &sizeOut) == 0) {
for (size_t i = 0; i < sizeOut; i++) {
if (preferredTypes[i] != 0 || preferredSubtypes[i] != UINT32_MAX) {
preferredArchsSet = true;
break;
}
}
}

xpc_object_t preferredArchsArray = NULL;
if (preferredArchsSet) {
preferredArchsArray = xpc_array_create_empty();
for (size_t i = 0; i < sizeOut; i++) {
xpc_object_t curArch = xpc_dictionary_create_empty();
xpc_dictionary_set_uint64(curArch, "type", preferredTypes[i]);
xpc_dictionary_set_uint64(curArch, "subtype", preferredSubtypes[i]);
xpc_array_set_value(preferredArchsArray, XPC_ARRAY_APPEND, curArch);
xpc_release(curArch);
}
}

// Upload binary to trustcache if needed
trust_binary(path);
trust_binary(path, preferredArchsArray);

if (preferredArchsArray) {
xpc_release(preferredArchsArray);
}
}

const char *existingLibraryInserts = envbuf_getenv((const char **)envp, "DYLD_INSERT_LIBRARIES");
Expand All @@ -256,7 +286,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path,
systemHookAlreadyInserted = true;
}
else {
trust_binary(existingLibraryInsert);
trust_binary(existingLibraryInsert, NULL);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/systemhook/src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path,
char *const argv[restrict],
char *const envp[restrict],
void *orig,
int (*trust_binary)(const char *),
int (*trust_binary)(const char *path, xpc_object_t preferredArchsArray),
int (*set_process_debugged)(uint64_t pid, bool fullyDebugged));
2 changes: 1 addition & 1 deletion BaseBin/systemhook/src/objc.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ bool NSConcreteTask_launchWithDictionary_error__hook(id self, id sender, NSDicti
NSString *executablePath = __objc_msgSend_1(dictionary, @selector(objectForKey:), keyExecutablePath);
if (executablePath) {
const char *executablePathC = __objc_msgSend_0(executablePath, @selector(UTF8String));
jbclient_trust_binary(executablePathC);
jbclient_trust_binary(executablePathC, NULL);
}

NSDictionary *existingEnvironment = __objc_msgSend_1(dictionary, @selector(objectForKey:), keyEnvironmentDict);
Expand Down

0 comments on commit cdd113f

Please sign in to comment.