#include <stdio.h> // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <unistd.h>
#include <Availability.h>
#include <mach-o/getsect.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
#if __MAC_OS_X_VERSION_MIN_REQUIRED
extern void foo();
extern int fooData;
static vm_prot_t getPermission(void* addr)
{
mach_vm_address_t address = (mach_vm_address_t)(uintptr_t)addr;
kern_return_t result;
mach_port_t object_name;
vm_region_basic_info_data_64_t info;
mach_msg_type_number_t count;
mach_vm_size_t size = 4096;
count = VM_REGION_BASIC_INFO_COUNT_64;
result = mach_vm_region(mach_task_self(),
&address,
&size,
VM_REGION_BASIC_INFO_64,
(vm_region_info_t)&info,
&count,
&object_name);
if ( result == KERN_SUCCESS )
return info.protection;
return 0;
}
static void* getStubAddr()
{
unsigned long size;
#if __i386__
return getsectdata("__IMPORT", "__jump_table", &size);
#elif __ppc__
void* p = getsectdata("__TEXT", "__picsymbolstub1", &size);
if ( p != NULL )
return p;
return getsectdata("__TEXT", "__symbol_stub1", &size);
#elif __ppc64__
return getsectdata("__TEXT", "__picsymbolstub1", &size);
#elif __x86_64__
return getsectdata("__TEXT", "__symbol_stub1", &size);
#elif __arm__
void* p = getsectdata("__TEXT", "__symbol_stub4", &size);
if ( p != NULL )
return p;
return getsectdata("__TEXT", "__symbolstub1", &size);
#else
#error unknown arch
#endif
}
static void checkStubs(void* addr)
{
vm_prot_t perm = getPermission(addr);
if ( (perm == 0) || ((perm & VM_PROT_WRITE) != 0) ) {
FAIL("read-only-stubs: bad permissions %d at address %p", perm, addr);
exit(0);
}
}
int main()
{
void* stubAddr = getStubAddr();
#if __i386__
if ( stubAddr != NULL )
#endif
{
checkStubs(stubAddr);
fooData = 1;
foo();
checkStubs(stubAddr);
}
PASS("read-only-stubs");
return EXIT_SUCCESS;
}
#else
int main()
{
PASS("read-only-stubs");
return EXIT_SUCCESS;
}
#endif