You're entirely correct because JIT requires violating Write xor Execute security policy. This is the reason on iOS, it is limited to Apple shipped software.
- Android Runtime Just-In-Time (JIT) compilation/profiling is fully disabled and replaced with full ahead-of-time (AOT) compilation. The only JIT compilation in the base OS is the V8 JavaScript JIT which is disabled by default for the Vanadium browser with per-site exception support.
- Dynamic code loading for both native code or Java/Kotlin classes is blocked for nearly the entire base OS. […]
- Dynamic code loading for both native code or Java/Kotlin classes can be disabled for user installed apps via 3 exploit protection toggles: […]
As someone who has written a jit compiler, I am puzzled by the claim that jitting requires write/execute permissions. When I have written a jit, I loaded some memory with read/write permissions using mmap. Once I filled in the generated code, I mprotected the region to read/execute before executing.
The drawback to this approach is there can be some bloat because you can only mprotect at page granulariy so a jitted function that only takes say 10 bytes to represent would take up a full page in memory, but this is extreme and in practice, the overhead is unlikely to be worth worrying about.
Comments
You're entirely correct because JIT requires violating Write xor Execute security policy. This is the reason on iOS, it is limited to Apple shipped software.
https://en.wikipedia.org/wiki/W%5EX
GrapheneOS heavily restricts JIT usage, too:
https://grapheneos.org/features
As someone who has written a jit compiler, I am puzzled by the claim that jitting requires write/execute permissions. When I have written a jit, I loaded some memory with read/write permissions using mmap. Once I filled in the generated code, I mprotected the region to read/execute before executing.
The drawback to this approach is there can be some bloat because you can only mprotect at page granulariy so a jitted function that only takes say 10 bytes to represent would take up a full page in memory, but this is extreme and in practice, the overhead is unlikely to be worth worrying about.
The wiki page mentions this is only a minor problem. Because everyone just writes, then switches and executes.
But this means that you have to decide who is allowed to switch.
VirtualProtect/mprotect aren't privileged calls on any modern OS.
It's how you do JIT on macOS, where W^X is enforced, for example.