self-modifying code on MacOS Catalina / x64

Deadly 提交于 2020-07-10 10:28:00

问题


As part as porting a forth compiler, I'm trying to create a binary that allows for self modifying code. Gory details at https://github.com/klapauciusisgreat/jonesforth-MacOS-x64

Ideally, I create a bunch of pages for user definitions and call mprotect like so:

#define __NR_exit 0x2000001
#define __NR_open 0x2000005
#define __NR_close 0x2000006
#define __NR_read 0x2000003
#define __NR_write 0x2000004
#define __NR_mprotect 0x200004a

#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
#define PAGE_SIZE 4096


// https://opensource.apple.com/source/xnu/xnu-201/bsd/sys/errno.h
#define EACCES          13              /* Permission denied */
#define EINVAL          22              /* Invalid argument */
#define ENOTSUP 45              /* Operation not supported */


/* Assembler entry point. */
        .text
        .globl start
start:
        // use mprotect to allow read/write/execute of the .bss section
        mov $__NR_mprotect, %rax                //mprotect
        lea user_defs_start(%rip), %rdi         // start address
        and $-PAGE_SIZE,%rdi                    // align at page boundary
        mov $USER_DEFS_SIZE, %rsi               // length
        mov $PROT_ALL,%rdx
        syscall
        cmp $EINVAL, %rax
        je 1f
        cmp $EACCES,%rax
        je 2f
        test %rax,%rax
        je 4f                                   // all good, proceed:

        // must be ENOTSUP
        mov $2,%rdi                     // 1st param: stderr
        lea errENOTSUP(%rip),%rsi       // 2nd param: error message
        mov $8,%rdx                     // 3rd param: length of string
        mov $__NR_write,%rax            // write syscall
        syscall
        jmp 3f

1:
        mov $2,%rdi                     // 1st param: stderr
        lea errEINVAL(%rip),%rsi        // 2nd param: error message
        mov $7,%rdx                     // 3rd param: length of string
        mov $__NR_write,%rax            // write syscall
        syscall
        jmp 3f

2:
        mov $2,%rdi                     // 1st param: stderr
        lea errEACCES(%rip),%rsi        // 2nd param: error message
        mov $7,%rdx                     // 3rd param: length of string
        mov $__NR_write,%rax            // write syscall
        syscall

3:
        // did't work -- then exit
        xor %rdi,%rdi
        mov $__NR_exit,%rax     // syscall: exit
        syscall

4:
// all good, let's get started for real:

.
.
.


        .set RETURN_STACK_SIZE,8192
        .set BUFFER_SIZE,4096
        .set USER_DEFS_SIZE,65536*2 //128kiB ought to be enough for everybody

        .bss
        .balign 8
user_defs_start:
        .space USER_DEFS_SIZE

However, I get an EACCES return value. I suspect that this is because of some security policy apple has set up but do not find good documentation.

Can someone point out the source code for mprotect, and/or methods to mark the data area executable and writable at the same time ?

I found that compiling with

gcc -segprot __DATA rwx rwx

does mark the entire data segment rwx, so it must somehow be possible to do the right thing. But I would prefer to only make the area hosting forth words executable, not the entire data segment.

Any advice greatly appreciated. I found a similar discussion here but no solution.


回答1:


The segment that I want to 'unprotect' exec permission in has really two values describing it's permissions:

  1. the initial protection settings, which for __DATA I want rw-

  2. the maximum protection (loosest) settings, which I want to be rwx.

So the first thing I need to do is to set the maxprot field to rwx. According to the ld manpage, this should be achieved by invoking gcc or ld with the flags -segprot __DATA rwx rw. However, a recent change made by Apple to the linker essentially ignores the maxprot value, and sets maxprot=initprot.

Thanks to Darfink, you can use this script to tweak the maxprot bits after the fact. I thought additional code signing with special entitlements was required, but it's not, at least for the __DATA segment. The __TEXT segment may need code signing with the com.apple.security.cs.disable-executable-page-protection entitlement.

Also see here for a few more details.

Looking at the larger picture, I should also point out that rather to unprotect pieces of an otherwise protected __DATA segment, it may be better to create a complete new data/code segment just for the self-modifying code with rwx permissions from the start. This allows still protecting the rest of data by the operating system, and requires no non-standard tools.



来源:https://stackoverflow.com/questions/62052528/self-modifying-code-on-macos-catalina-x64

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!