diff --git a/nx/include/switch/kernel/detect.h b/nx/include/switch/kernel/detect.h index 9061acce..09fa3534 100644 --- a/nx/include/switch/kernel/detect.h +++ b/nx/include/switch/kernel/detect.h @@ -19,3 +19,6 @@ bool kernelAbove500(void); bool kernelAbove600(void); /// Returns true if the process has a debugger attached. bool detectDebugger(void); + +/// Returns true if the kernel is patched to allow self-process-jit. +bool detectCfwJitPatch(void); diff --git a/nx/source/kernel/detect.c b/nx/source/kernel/detect.c index 34d1b20c..acabefcb 100644 --- a/nx/source/kernel/detect.c +++ b/nx/source/kernel/detect.c @@ -1,26 +1,32 @@ // Copyright 2017 plutoo #include "types.h" +#include "result.h" #include "kernel/detect.h" #include "kernel/mutex.h" #include "kernel/svc.h" +#include +static bool g_VersionCached = 0; +static Mutex g_VersionMutex; static bool g_IsAbove200; static bool g_IsAbove300; static bool g_IsAbove400; static bool g_IsAbove500; static bool g_IsAbove600; -static bool g_HasCached = 0; -static Mutex g_Mutex; -static void _CacheValues(void) +static bool g_CfwJitCached = 0; +static Mutex g_CfwJitMutex; +static bool g_CfwJitPatchDetected; + +static void _CacheVersion(void) { - if (__atomic_load_n(&g_HasCached, __ATOMIC_SEQ_CST)) + if (__atomic_load_n(&g_VersionCached, __ATOMIC_SEQ_CST)) return; - mutexLock(&g_Mutex); + mutexLock(&g_VersionMutex); - if (g_HasCached) { - mutexUnlock(&g_Mutex); + if (g_VersionCached) { + mutexUnlock(&g_VersionMutex); return; } @@ -36,33 +42,71 @@ static void _CacheValues(void) g_IsAbove300 |= g_IsAbove400; g_IsAbove200 |= g_IsAbove300; - __atomic_store_n(&g_HasCached, true, __ATOMIC_SEQ_CST); + __atomic_store_n(&g_VersionCached, true, __ATOMIC_SEQ_CST); - mutexUnlock(&g_Mutex); + mutexUnlock(&g_VersionMutex); +} + +static void _CacheCfwJit(void) +{ + if (__atomic_load_n(&g_CfwJitCached, __ATOMIC_SEQ_CST)) + return; + + mutexLock(&g_CfwJitMutex); + + if (g_CfwJitCached) { + mutexUnlock(&g_CfwJitMutex); + return; + } + + void* heap = memalign(0x1000, 0x1000); + + if (heap != NULL) + { + Handle code; + Result rc; + rc = svcCreateCodeMemory(&code, heap, 0x1000); + + if (R_SUCCEEDED(rc)) + { + // On an unpatched kernel on 5.0.0 and above, this would return 0xD401. + // It is not allowed for the creator-process of a CodeMemory object to use svcControlCodeMemory on it. + rc = svcControlCodeMemory(code, -1, 0, 0x1000, 0); + + g_CfwJitPatchDetected = (rc == 0xF001); + __atomic_store_n(&g_CfwJitCached, true, __ATOMIC_SEQ_CST); + + svcCloseHandle(code); + } + + free(heap); + } + + mutexUnlock(&g_CfwJitMutex); } bool kernelAbove200(void) { - _CacheValues(); + _CacheVersion(); return g_IsAbove200; } bool kernelAbove300(void) { - _CacheValues(); + _CacheVersion(); return g_IsAbove300; } bool kernelAbove400(void) { - _CacheValues(); + _CacheVersion(); return g_IsAbove400; } bool kernelAbove500(void) { - _CacheValues(); + _CacheVersion(); return g_IsAbove500; } bool kernelAbove600(void) { - _CacheValues(); + _CacheVersion(); return g_IsAbove600; } @@ -71,3 +115,8 @@ bool detectDebugger(void) { svcGetInfo(&tmp, 8, 0, 0); return !!tmp; } + +bool detectCfwJitPatch(void) { + _CacheCfwJit(); + return g_CfwJitPatchDetected; +} diff --git a/nx/source/kernel/jit.c b/nx/source/kernel/jit.c index 455ca6b7..018dfe25 100644 --- a/nx/source/kernel/jit.c +++ b/nx/source/kernel/jit.c @@ -15,8 +15,9 @@ Result jitCreate(Jit* j, size_t size) // Use new jit primitive introduced in 4.0.0, if available. // Not usable with 5.0.0+ since svcMapJitMemory doesn't allow using that SVC under the same process which owns that object. - if (kernelAbove400() && !kernelAbove500() && envIsSyscallHinted(0x4B) && envIsSyscallHinted(0x4C)) { - type = JitType_JitMemory; + if (kernelAbove400() && envIsSyscallHinted(0x4B) && envIsSyscallHinted(0x4C) + && (!kernelAbove500() || detectCfwJitPatch())) { + type = JitType_JitMemory; } // Fall back to MapProcessCodeMemory if available. else if (envIsSyscallHinted(0x73) && envIsSyscallHinted(0x77) && envIsSyscallHinted(0x78)