-
-
Save stuartcarnie/855607 to your computer and use it in GitHub Desktop.
// | |
// main.m | |
// ProtectTest | |
// Demonstrates newer versions of iOS now support PROT_EXEC pages, for just-in-time compilation. | |
// | |
// Must be compiled with Thumb disabled | |
// | |
// Created by Stuart Carnie on 3/4/11. | |
// Copyright 2011 Manomio LLC. All rights reserved. | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include <sys/mman.h> | |
#include <limits.h> /* for PAGESIZE */ | |
#ifndef PAGESIZE | |
#define PAGESIZE 4096 | |
#endif | |
typedef int (*inc_t)(int a); | |
inc_t _inc = NULL; | |
int | |
main(void) | |
{ | |
uint32_t code[] = { | |
0xe2800001, // add r0, r0, #1 | |
0xe12fff1e, // bx lr | |
}; | |
uint32_t *p; | |
/* Allocate a buffer; it will have the default | |
protection of PROT_READ|PROT_WRITE. */ | |
p = malloc(1024+PAGESIZE-1); | |
if (!p) { | |
perror("Couldn't malloc(1024)"); | |
exit(errno); | |
} | |
/* Align to a multiple of PAGESIZE, assumed to be a power of two */ | |
p = (uint32_t *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1)); | |
// copy instructions to function | |
p[0] = code[0]; | |
p[1] = code[1]; | |
/* Mark the buffer read / execute. */ | |
if (mprotect(p, 1024, PROT_READ | PROT_EXEC)) { | |
perror("Couldn't mprotect"); | |
exit(errno); | |
} | |
_inc = (inc_t)p; | |
int a = 1; | |
a = _inc(a); | |
printf("%d\n", a); // as expected, echos 2 | |
exit(0); | |
} |
"Demonstrates newer versions of iOS now support PROT_EXEC pages, for just-in-time compilation." <- For the record, jailbroken devices have always supported this (this is exactly how MobileSubstrate works, as well as the various code-generation engines used in JocStrap, PyObjC, and Cycript). It is true that iOS 4.3 now supports a "dynamic_codesign" entitlement, that allows this kind of page flipping, but as you did not add that entitlement to your binary it would not work on a non-jailbroken device.
Indeed - I used otool to list the entitlements of MobileSafari from a decrypted 4.3 image and found the dynamic_codesign
property (among others). Almost certain that Apple will reject apps which have been signed with this undocumented entitlement.
For jailbroken devices, you are lucky enough to support rwx
, whereas currently this entitlement only allows either rw
or rx
, but no rwx
. This severely limits its use for dynamic code gen.
Almost certain that Apple will reject apps which have been signed with this undocumented entitlement.
Is there any way we can get ahold of apple to see if this is something that they would indeed react on?
Might be worthwhile to try an update an existing app with this entitlement and see how far it gets through the review process.
Given it is not documented anywhere, that is a pretty good sign Apple won't accept it, however, you could try contacting appreview at apple.com
How to add a new entitlement in Xcode 4 as it doesn't support creating custom entitlement file anymore?
I tried to list a valid entitlement file first via: codesign -d --entitlements - /path/to/myapp.app
And then add "dynamic_codesign" into it. But I still got "Invalid entitlement ***" error when I tried to install on my non-jailbroken iPhone.
I just ran this on an iOS 6 iPad and it worked without adding an entitlement. Am I missing something?
To follow up to @wtholliday's post, this does appear to work as is, without an entitlements, on iOS 6. Someone should check with Apple to see if this would actually be allowed into the App Store. If so, this is a very welcome change.
It works on both iOS 5.1 and iOS 6.0 if you run it from Xcode. If you tap on the app it crashes in both cases. Presumably starting the app with gdbserver enables jitting (my guess is that this is to support executing random expressions in the debugger).
I was not able to set the "dynamic_codesign" entitlement, Xcode refused to deploy/install the app ("The executable was signed with invalid entitlements" and "The entitlements specified in your application's Code Signing Entitlements file do not match those specified in your provisioning profile.")
For future reference -
- You can technically change the protection of memory to be executable in iOS on local builds (you wouldn't get past app review process though, obviously).
- Marking memory regions for JIT use with 'mmap's MAP_JIT flag is still blocked, even in local builds. This is guarded today by the 'dynamic_codesign' entitlement. That's what's keeping JavaScriptCore.framework from using JIT when running locally in your app.
- It seems that the old method of just adding the dynamic_codesign entitlement in Xcode doesn't work anymore.
You can technically change the protection of memory to be executable in iOS on local builds (you wouldn't get past app review process though, obviously).
@dcaspi Could you elaborate on that? I have a small benchmark app I'm playing with for personal use (not going to the app store) that could benefit from executable memory. I've tried mmap and vm_protect but neither seems to work in giving me executable memory.
@vpeca You need a get-task-allow
entitlement (injected by Xcode automatically) and get ptrace
to trace you in some way. Either this can be done by attaching via LLDB, as Xcode does, or you can do it programmatically with ptrace(PT_TRACE_ME, 0, NULL, 0)
.
On my iPhone 4, jailbroken 4.3.1:
:)