Skip to content

Instantly share code, notes, and snippets.

@stuartcarnie
Created March 4, 2011 19:59
Show Gist options
  • Save stuartcarnie/855607 to your computer and use it in GitHub Desktop.
Save stuartcarnie/855607 to your computer and use it in GitHub Desktop.
Demonstrates we can now support limited JIT compilation on recent versions of iOS (assuming Apple approves entitlements at some future point)
//
// 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);
}
@TooTallNate
Copy link

On my iPhone 4, jailbroken 4.3.1:

gcc main.m -o main
./main
2

:)

@saurik
Copy link

saurik commented Apr 10, 2011

"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.

@stuartcarnie
Copy link
Author

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.

@diclophis
Copy link

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.

@stuartcarnie
Copy link
Author

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

@eniton
Copy link

eniton commented Dec 13, 2011

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.

@wtholliday
Copy link

I just ran this on an iOS 6 iPad and it worked without adding an entitlement. Am I missing something?

@munsie
Copy link

munsie commented Dec 5, 2012

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.

@rolfbjarne
Copy link

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.")

@dcaspi
Copy link

dcaspi commented Feb 24, 2016

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.

@vpeca
Copy link

vpeca commented Apr 29, 2017

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.

@saagarjha
Copy link

@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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment