Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT is violating Darwin W^X if not targeting macOS#212

Open
Torrekie opened this issue Feb 27, 2023 · 6 comments
Open

JIT is violating Darwin W^X if not targeting macOS #212

Torrekie opened this issue Feb 27, 2023 · 6 comments

Comments

@Torrekie
Copy link

On iOS there's no pthread_jit* API provided by Apple, resulting PROT_WRITE and PROT_EXEC has been set at same time, causing KERN_PROTECTION_FAILURE

Date/Time:           2023-02-27 15:52:08.6193 +0800
Launch Time:         2023-02-27 15:52:08.2011 +0800
OS Version:          iPhone OS 14.5.1 (18E212)
Release Type:        User
Baseband Version:    n/a
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: KERN_PROTECTION_FAILURE at 0x0000000a1b2fc008
VM Region Info: 0xa1b2fc008 is in 0xa1b2fc000-0xa1b30c000;  bytes after start: 8  bytes before end: 65527
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      unused shlib __TEXT      210000000-217598000 [117.6M] r--/r-- SM=COW  ... this process
      GAP OF 0x803d64000 BYTES
--->  VM_ALLOCATE              a1b2fc000-a1b30c000 [   64K] rwx/rwx SM=PRV  
      GAP OF 0x5a4cf4000 BYTES
      commpage (reserved)      fc0000000-1000000000 [  1.0G] ---/--- SM=NUL  ...(unallocated)

Triggered by Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libpcre2-8.0.dylib                  0x0000000100cfe700 0x100ce4000 + 108288
1   libpcre2-8.0.dylib                  0x0000000100cfe6a4 0x100ce4000 + 108196
2   libpcre2-8.0.dylib                  0x0000000100cfe578 0x100ce4000 + 107896
3   pcre2_jit_test                      0x0000000100cc1050 0x100cbc000 + 20560
4   libdyld.dylib                       0x000000019ed26cf8 0x19ed25000 + 7416
@zherczeg
Copy link
Collaborator

As far as I heard no jit works on ios, it is better to disable it.

@Torrekie
Copy link
Author

After several patching I could avoid that SIGBUS using METHOD1, but then resulting all pcre2_jit_tests failed

--- a/src/sljit/sljitExecAllocator.c  1645780892.000000000
+++ b/src/sljit/sljitExecAllocator.c      1677493457.634072731
@@ -158,7 +158,62 @@ static SLJIT_INLINE void apple_update_wx
 }
 #endif /* SLJIT_CONFIG_X86 */
 #else /* !TARGET_OS_OSX */
+#define _COMM_PAGE_START_ADDRESS        (0x0000000FFFFFC000ULL) /* In TTBR0 */
+#define _COMM_PAGE_APRR_SUPPORT         (_COMM_PAGE_START_ADDRESS + 0x10C)
+#define _COMM_PAGE_APPR_WRITE_ENABLE    (_COMM_PAGE_START_ADDRESS + 0x110)
+#define _COMM_PAGE_APRR_WRITE_DISABLE   (_COMM_PAGE_START_ADDRESS + 0x118)
+
 #define SLJIT_MAP_JIT  (MAP_JIT)
+#ifdef METHOD1
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+                       apple_update_wx_flags(enable_exec)
+#warning Using https://siguza.github.io/APRR/
+static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
+{
+    uint8_t aprr_support = *(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT;
+    if (aprr_support == 0 || aprr_support > 3) {
+        return;
+    } else if (aprr_support == 1) {
+        __asm__ __volatile__ (
+            "mov x0, %0\n"
+            "ldr x0, [x0]\n"
+            "msr S3_4_c15_c2_7, x0\n"
+            "isb sy\n"
+            :: "r" (enable_exec ? _COMM_PAGE_APRR_WRITE_DISABLE
+                            : _COMM_PAGE_APPR_WRITE_ENABLE)
+            : "memory", "x0"
+        );
+    } else {
+        __asm__ __volatile__ (
+            "mov x0, %0\n"
+            "ldr x0, [x0]\n"
+            "msr S3_6_c15_c1_5, x0\n"
+            "isb sy\n"
+            :: "r" (enable_exec ? _COMM_PAGE_APRR_WRITE_DISABLE
+                            : _COMM_PAGE_APPR_WRITE_ENABLE)
+            : "memory", "x0"
+        );
+    }
+}
+#elif defined(METHOD2)
+#warning Using mprotect
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+                       update_wx_flags(from, to, enable_exec)
+static SLJIT_INLINE void update_wx_flags(void *from, void *to, int enable_exec)
+{
+       sljit_uw page_mask = (sljit_uw)get_page_alignment();
+       sljit_uw start = (sljit_uw)from;
+       sljit_uw end = (sljit_uw)to;
+       int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
+
+       SLJIT_ASSERT(start < end);
+
+       start &= ~page_mask;
+       end = (end + page_mask) & ~page_mask;
+
+       mprotect((void*)start, end - start, prot);
+}
+#endif
 #endif /* TARGET_OS_OSX */
 #endif /* __APPLE__ && MAP_JIT */
 #ifndef SLJIT_UPDATE_WX_FLAGS
iPad:/buildroot/pcre2-10.42 root# .libs/pcre2_jit_test | grep "%"
Successful test ratio: 0% (674 failed)
Invalid UTF8 successful test ratio: 0% (129 failed)
Invalid UTF16 successful test ratio: 0% (39 failed)
Invalid UTF32 successful test ratio: 0% (26 failed)

@zherczeg
Copy link
Collaborator

zherczeg commented Mar 1, 2023

The last thing I heard, no jit is allowed in iOS, because it hurts monetizing the platform. I also heard jit works on jailbroken devices, but that is special case.

@Torrekie
Copy link
Author

Torrekie commented Mar 1, 2023

basically, there have JIT support on iOS with dynamic-codesigning entitlement enabled (which also enabled for Safari.app) and I am pretty sure there used to have iOS JIT support during PCRE 8.x. Actually partial JIT tests passed after my modification but still meeting some weird errors on others. I believe it can work properly if we are able to handle W^X in a better way (qemu/qemu@36195a7 this fork using the exactly same method that I mentioned above to replace previous pthread_jit_write_protect_np and it do have working JIT on both macOS/iOS)

@zherczeg
Copy link
Collaborator

zherczeg commented Mar 1, 2023

Sounds interesting. Unfortunately I cannot help since I have no access to any Apple device, but somebody else might know something. Maybe in some apple dev forums.

@Torrekie
Copy link
Author

Torrekie commented May 9, 2024

Retried today and have to say defining SLJIT_WX_EXECUTABLE_ALLOCATOR and make non-macOS Darwin targets to use POSIX implementation is now having a working JIT outside of sandbox. But this macro doesn’t seems configurable by autoconf script.

so the thing is:

  • When sandboxed (either sandbox_apply() or container-required), use the pthread_jit_write_protect_np API (Which exactly same as the APRR hack i commented before), which allows RWX pages being created when MAP_JIT and dynamic-codesigning entitlement specified.
  • When outside of sandbox, MAP_JIT shouldn’t be added, no RWX pages can be used, either allocate two separate region for JIT RW/RX or some mirror mapping like this

JIT (SLJIT_WX_EXECUTABLE_ALLOCATOR defined, unsandboxed)

iPad:/buildroot/pcre2-10.43 root# ./pcre2_jit_test 
Running JIT regression tests
  target CPU of SLJIT compiler: ARM-64 64bit (little endian + unaligned)
  in  8 bit mode with UTF-8  enabled:
  in 16 bit mode with UTF-16 enabled:
  in 32 bit mode with UTF-32 enabled:
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................................................
............................
All JIT regression tests are successfully passed.

Running invalid-utf8 JIT regression tests
............................................................
............................................................
............

All invalid UTF8 JIT regression tests are successfully passed.

Running invalid-utf16 JIT regression tests
.......................................

All invalid UTF16 JIT regression tests are successfully passed.

Running invalid-utf32 JIT regression tests
..........................

All invalid UTF32 JIT regression tests are successfully passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants