#include #include #include #include #include #include #include #include #ifdef __arm__ static int test() { __asm (".rept 1024; nop; .endr"); return 0x123; } #endif static mach_port_t task; static size_t page; static void look(void *base, const char **message, vm_prot_t *cur, vm_prot_t *max, kern_return_t *ret) { if (base == MAP_FAILED) { *message = "mmap fail!"; *cur = 0; *max = 0; *ret = 0; } else { vm_address_t address = (vm_address_t) base; struct vm_region_basic_info_64 info; vm_size_t size; mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; mach_port_t object; *ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t) &info, &count, &object); if (*ret == 0) { *message = "success!"; *cur = info.protection; *max = info.max_protection; } else { *message = "vm_region fail!"; *cur = 0; *max = 0; } } } static void skim(vm_prot_t prot, char name[4]) { name[0] = (prot & VM_PROT_READ) == 0 ? '-' : 'r'; name[1] = (prot & VM_PROT_WRITE) == 0 ? '-' : 'w'; name[2] = (prot & VM_PROT_EXECUTE) == 0 ? '-' : 'x'; name[3] = '\0'; } static void *alloc( bool write, bool exec, bool *fail, const char *v1cur, const char *v1max, int v1err, const char *v2cur, const char *v2max, int v2err ) { char v0ask[4] = {'r', write ? 'w' : '-', exec ? 'x' : '-', '\0'}; int flags = PROT_READ; if (write) flags |= PROT_WRITE; if (exec) flags |= PROT_EXEC; errno = 0; void *base = mmap(NULL, page, flags, MAP_ANON | MAP_PRIVATE, -1, 0); const char *message; vm_prot_t cur, max; kern_return_t ret; look(base, &message, &cur, &max, &ret); char v0cur[4], v0max[4]; skim(cur, v0cur); skim(max, v0max); vm_prot_t ask = VM_PROT_READ; if (write) ask |= VM_PROT_WRITE; if (exec) ask |= VM_PROT_EXECUTE; *fail = ask != cur; printf("%s? =%s<%s:%2d (=%s<%s:%2d) (=%s<%s:%2d) :(%d) %s\n", v0ask, v0cur, v0max, errno, v1cur, v1max, v1err, v2cur, v2max, v2err, ret, message == NULL ? "" : message); return base; } static void flip( void *base, bool flip, bool execute, const char *v2cur, const char *v2max, int v2err ) { errno = 0; mprotect(base, page, PROT_READ | (execute ? PROT_EXEC : PROT_WRITE)); const char *message; vm_prot_t cur, max; kern_return_t ret; look(base, &message, &cur, &max, &ret); char v0cur[4], v0max[4]; skim(cur, v0cur); skim(max, v0max); printf("%c%s =%s<%s:%2d (=%s' : '<', execute ? "r-x" : "rw-", v0cur, v0max, errno, execute ? "r-x" : "rw-", 0, v2cur, v2max, v2err, ret, message == NULL ? "" : message); } int main() { task = mach_task_self(); page = vm_page_size; printf("ask? =cur unsafe (%u)\n", diff); else { uintptr_t addr = (uintptr_t) test / page * page; if (page - ((uintptr_t) test - addr) < 8) page *= 2; const char *message; vm_prot_t cur, max; char v0cur[4], v0max[4]; look(addr, &message, &cur, &max, &ret); skim(cur, v0cur); skim(max, v0max); printf("#rwx =%s<%s:%2d (=rwx error vm_protect(rw_|c)=%d\n", ret); else { printf("$r<> "); fflush(stdout); uint32_t *code = (uint32_t *) test; code[0] = 0xe3a00e21; printf("."); fflush(stdout); code[1] = 0xe12fff1e; printf("."); fflush(stdout); printf("."); fflush(stdout); ret = vm_protect(task, addr, page, FALSE, VM_PROT_READ | VM_PROT_EXECUTE); if (ret != 0) printf(" error vm_protect(r_x|0)=%d\n", ret); else { int r0 = test(); printf(" %s\n", r0 == 0x210 ? "success" : "failure"); } } } fflush(stdout); #endif return 0; }