Skip to content

Commit

Permalink
Fixed potential race condition during user patching
Browse files Browse the repository at this point in the history
  • Loading branch information
vit9696 committed Dec 20, 2018
1 parent d4d61e6 commit a6e29b4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 19 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Lilu Changelog
- Added ThreadLocal APIs
- Added `KernelPatcher::eraseCoverageInstPrefix` API
- Fixed race condition during bootstrap (thx @Download-Fritz)
- Fixed potential race condition during user patching

#### v1.2.8
- Fixed CPU generation detection for Coffee Lake-U
Expand Down
29 changes: 17 additions & 12 deletions Lilu/Headers/kern_user.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,22 +313,27 @@ class UserPatcher {
* Kernel patcher instance
*/
KernelPatcher *patcher {nullptr};

/**
* Patch requested for path
*/
char pendingPath[MAXPATHLEN] {};


/**
* Patch requested for path
* Pending callback entry
*/
uint32_t pendingPathLen {0};

struct PendingUser {
/**
* Patch requested for path
*/
char path[MAXPATHLEN] {};

/**
* Patch requested for path
*/
uint32_t pathLen {0};
};

/**
* Patch requested
* Stored pending callback
*/
bool pendingPatchCallback {false};
ThreadLocal<PendingUser *, 8> pending;

/**
* Current minimal proc name length
*/
Expand Down
30 changes: 23 additions & 7 deletions Lilu/Sources/kern_user.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ bool UserPatcher::init(KernelPatcher &kernelPatcher, bool preferSlowMode) {
that = this;
patchDyldSharedCache = !preferSlowMode;
patcher = &kernelPatcher;

if (!pending.init()) {
SYSLOG("user", "failed to allocate pending storage");
return false;
}

listener = kauth_listen_scope(KAUTH_SCOPE_FILEOP, execListener, &cookie);

Expand Down Expand Up @@ -152,7 +157,8 @@ void UserPatcher::deinit() {
kauth_unlisten_scope(listener);
listener = nullptr;
}


pending.deinit();
lookupStorage.deinit();
for (size_t i = 0; i < Lookup::matchNum; i++)
lookup.c[i].deinit();
Expand Down Expand Up @@ -279,9 +285,17 @@ void UserPatcher::onPath(const char *path, uint32_t len) {
DBGLOG("user", "caught %s performing injection", path);
if (orgProcExecSwitchTask) {
DBGLOG("user", "requesting proc_exec_switch_task patch");
lilu_os_strlcpy(pendingPath, path, MAXPATHLEN);
pendingPathLen = len;
pendingPatchCallback = true;

PANIC_COND(pending.get(), "user", "found dangling user patch request");
auto p = new PendingUser;
if (p != nullptr) {
lilu_os_strlcpy(p->path, path, MAXPATHLEN);
p->pathLen = len;
PANIC_COND(!pending.set(p), "user", "failed to set user patch request");
} else {
SYSLOG("user", "failed to allocate pending user callback");
}

} else {
patchBinary(orgCurrentMap(), path, len);
}
Expand Down Expand Up @@ -586,10 +600,12 @@ int UserPatcher::vmSharedRegionSlideMojave(uint32_t slide, mach_vm_offset_t entr
proc_t UserPatcher::procExecSwitchTask(proc_t p, task_t current_task, task_t new_task, thread_t new_thread) {
proc_t rp = that->orgProcExecSwitchTask(p, current_task, new_task, new_thread);

if (that->pendingPatchCallback) {
auto entry = that->pending.get();
if (entry) {
DBGLOG("user", "firing hook from procExecSwitchTask");
that->patchBinary(that->orgGetTaskMap(new_task), that->pendingPath, that->pendingPathLen);
that->pendingPatchCallback = false;
that->patchBinary(that->orgGetTaskMap(new_task), (*entry)->path, (*entry)->pathLen);
PANIC_COND(!that->pending.erase(), "user", "failed to remove pending user patch");
delete *entry;
}

return rp;
Expand Down

0 comments on commit a6e29b4

Please sign in to comment.