Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions BaseBin/jailbreakd/src/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ int main(int argc, char* argv[])
}
}

JBLogDebug("initializing exec patch handling...");
initExecPatch();

JBLogDebug("check in jailbreakd port...");
mach_port_t serverPort = jbclient_jailbreakd_checkin();
if (!MACH_PORT_VALID(serverPort)) {
Expand Down
34 changes: 28 additions & 6 deletions BaseBin/jailbreakd/src/server.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
#include <libjailbreak/libjailbreak.h>
#include <libjailbreak/roothider.h>

static dispatch_queue_t execPatchRequestQueue(void)
{
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Keep the receive queue free for launchd's nested child-patch request
// while exec registration is waiting in kevent.
queue = dispatch_queue_create("com.roothide.jailbreakd.exec-patch", DISPATCH_QUEUE_SERIAL);
});
return queue;
}

void jailbreakd_reply_message(JBD_MESSAGE_ID msgId, xpc_object_t reply)
{
char* desc = NULL;
Expand Down Expand Up @@ -94,17 +106,27 @@ void jailbreakd_received_message(mach_port_t port)
case JBD_MSG_SPAWN_EXEC_START: {
bool resume = xpc_dictionary_get_bool(message, "resume");
const char* execfile = xpc_dictionary_get_string(message, "execfile");
JBLogDebug("spawn exec start: %d %s", clientPid, execfile);
int64_t result = spawnExecPatchAdd(clientPid, resume);
xpc_dictionary_set_int64(reply, "result", result);
NSString* execPath = execfile ? @(execfile) : @"(null)";
dispatch_async(execPatchRequestQueue(), ^{
JBLogDebug("spawn exec start: %d %s", clientPid, execPath.UTF8String);
int64_t result = spawnExecPatchAdd(clientPid, resume);
xpc_dictionary_set_int64(reply, "result", result);
jailbreakd_reply_message(msgId, reply);
});
reply = nil;
break;
}

case JBD_MSG_SPAWN_EXEC_CANCEL: {
const char* execfile = xpc_dictionary_get_string(message, "execfile");
JBLogDebug("spawn exec cancel: %d %s", clientPid, execfile);
int64_t result = spawnExecPatchDel(clientPid);
xpc_dictionary_set_int64(reply, "result", result);
NSString* execPath = execfile ? @(execfile) : @"(null)";
dispatch_async(execPatchRequestQueue(), ^{
JBLogDebug("spawn exec cancel: %d %s", clientPid, execPath.UTF8String);
int64_t result = spawnExecPatchDel(clientPid);
xpc_dictionary_set_int64(reply, "result", result);
jailbreakd_reply_message(msgId, reply);
});
reply = nil;
break;
}

Expand Down
1 change: 1 addition & 0 deletions BaseBin/libjailbreak/src/roothider/exec_patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#import <stdbool.h>
#include <stdlib.h>

void initExecPatch(void);
int spawnExecPatchAdd(int pid, bool resume);
int spawnExecPatchDel(int pid);

Expand Down
62 changes: 61 additions & 1 deletion BaseBin/libjailbreak/src/roothider/jailbreakd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
#include <stdatomic.h>
#include <xpc/xpc.h>
#include <mach/mach.h>
#include <bsm/libbsm.h>
Expand Down Expand Up @@ -296,6 +297,61 @@ xpc_object_t jailbreakdXpcRequest(xpc_object_t xdict)
return xreply;
}

typedef struct {
dispatch_semaphore_t semaphore;
xpc_object_t reply;
_Atomic uint32_t references;
} jbd_timed_request_t;

static void jbdTimedRequestRelease(jbd_timed_request_t *request)
{
if (atomic_fetch_sub_explicit(&request->references, 1, memory_order_acq_rel) != 1) {
return;
}

if (request->reply) {
xpc_release(request->reply);
}
#if !OS_OBJECT_USE_OBJC
dispatch_release(request->semaphore);
#endif
free(request);
}

xpc_object_t jailbreakdXpcRequestWithTimeout(xpc_object_t xdict, uint64_t timeoutNanoseconds)
{
jbd_timed_request_t *request = calloc(1, sizeof(*request));
if (!request) {
return NULL;
}

request->semaphore = dispatch_semaphore_create(0);
if (!request->semaphore) {
free(request);
return NULL;
}
atomic_init(&request->references, 2);

xpc_retain(xdict);
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
request->reply = jailbreakdXpcRequest(xdict);
xpc_release(xdict);
dispatch_semaphore_signal(request->semaphore);
jbdTimedRequestRelease(request);
});

if (dispatch_semaphore_wait(request->semaphore,
dispatch_time(DISPATCH_TIME_NOW, timeoutNanoseconds)) != 0) {
jbdTimedRequestRelease(request);
return NULL;
}

xpc_object_t reply = request->reply;
request->reply = NULL;
jbdTimedRequestRelease(request);
return reply;
}

int jbdTestCall(int value)
{
xpc_object_t message = xpc_dictionary_create_empty();
Expand Down Expand Up @@ -347,12 +403,16 @@ int jbdSpawnPatchChild(int pid, bool resume)
xpc_dictionary_set_uint64(message, "id", JBD_MSG_SPAWN_PATCH_CHILD);
xpc_dictionary_set_int64(message, "pid", pid);
xpc_dictionary_set_bool(message, "resume", resume);
xpc_object_t reply = jailbreakdXpcRequest(message);
// launchd must be able to reach its existing failed-spawn cleanup instead
// of waiting indefinitely and triggering a system watchdog reboot.
xpc_object_t reply = jailbreakdXpcRequestWithTimeout(message, 10 * NSEC_PER_SEC);
xpc_release(message);
int64_t result = -1;
if (reply) {
result = xpc_dictionary_get_int64(reply, "result");
xpc_release(reply);
} else {
JBLogError("jbdSpawnPatchChild timed out or failed for pid %d", pid);
}
return result;
}
Expand Down
7 changes: 6 additions & 1 deletion BaseBin/libjailbreak/src/roothider/jailbreakd.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#ifndef JAILBREAKD_H
#define JAILBREAKD_H

#include <stdint.h>
#include <unistd.h>
#include <xpc/xpc.h>

typedef enum {
JBD_MSG_TEST_CALL = 101,
Expand All @@ -23,6 +25,9 @@ void setJailbreakdProcess(pid_t pid);
mach_port_t jailbreakdClientPort();
mach_port_t jailbreakdServerPort();

XPC_RETURNS_RETAINED xpc_object_t jailbreakdXpcRequest(xpc_object_t xdict);
XPC_RETURNS_RETAINED xpc_object_t jailbreakdXpcRequestWithTimeout(xpc_object_t xdict, uint64_t timeoutNanoseconds);

int jbdTestCall(int value);
int jbdSystemwideLog(const char* fmt, ...);

Expand All @@ -33,4 +38,4 @@ int jbdExecTraceStart(const char* execfile, bool* traced);
int jbdExecTraceCancel(const char* execfile, bool* detached);
int jbdSpinlockFixOnly(int pid, bool resume);

#endif // JAILBREAKD_H
#endif // JAILBREAKD_H