Skip to content

Instantly share code, notes, and snippets.

@darfink
Last active November 22, 2023 15:01
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darfink/a756b88e999631d75cbbeefd3eee7e2d to your computer and use it in GitHub Desktop.
Save darfink/a756b88e999631d75cbbeefd3eee7e2d to your computer and use it in GitHub Desktop.
Drop-in replacement/wrapper around macOS' linker (ld) that respects segprot's `max_prot` value
#!/usr/bin/python2
import argparse
import sys
import subprocess
from itertools import takewhile
from macholib import MachO, ptypes
def parse_rwx(text):
return ('r' in text and 1) | ('w' in text and 2) | ('x' in text and 4)
def apply_maxprots(path, maxprots):
mach = MachO.MachO(path)
header = mach.headers[0]
offset = ptypes.sizeof(header.mach_header)
for cload, ccmd, cdata in header.commands:
if not hasattr(ccmd, 'segname'): break
segname = ccmd.segname.to_str().strip(chr(0))
if segname in maxprots and ccmd.maxprot != maxprots[segname]:
fields = takewhile(lambda (n, _): n != 'maxprot', cload._fields_ + ccmd._fields_)
index = offset + sum(ptypes.sizeof(typ) for _, typ in fields)
with open(path, 'r+b') as fh:
fh.seek(index)
fh.write(chr(maxprots[segname]))
offset += cload.cmdsize
try:
subprocess.check_call(['/usr/bin/ld'] + sys.argv[1:])
except subprocess.CalledProcessError as ex:
sys.exit(ex.returncode)
parser = argparse.ArgumentParser()
parser.add_argument('-o', default='a.out')
parser.add_argument('-segprot', nargs=3, action='append')
args, _ = parser.parse_known_args()
if args.segprot:
segprots = {segment: parse_rwx(maxprot) for segment, maxprot, _ in args.segprot}
apply_maxprots(args.o, segprots)
@darfink
Copy link
Author

darfink commented May 29, 2020

Run with -segprot __TEXT rwx rx to allow self-modifying code.

@eisenxp
Copy link

eisenxp commented Dec 22, 2020

Thank you!
You helped me to find a solution for "syscall.Mprotect panic: permission denied" in Golang.

@mudepz-tokped
Copy link

thanks both of you!
solved my problem on running test for monkey patching
tested & worked on mac os big sur 11.2.3

@caulor
Copy link

caulor commented Jun 21, 2021

thanks both of you!
solved my problem on running test for monkey patching
tested & worked on mac os big sur 11.2.3

hi,i have same issue in my mac os big sur 11.2.3. i want learn how to run the file to solve my question.

@chaoedu
Copy link

chaoedu commented Jul 1, 2021

it didn't work on Apple Silicon, mac os big sur 11.4

@darfink
Copy link
Author

darfink commented Jul 1, 2021

Yes, see https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon.

RWX-pages will most likely never be allowed on Apple Silicon, the closest is to use mprotect & MAP_JIT in tandem with pthread_jit_write_protect_np (although this still leaves a ton of use cases outside the realm of possibility).

@wathenjiang
Copy link

Mac OS Version 11.6 m1 does not work.
Could some one give a solution to help syscall.Mprotect works on m1 silicon?

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