The two main test programs being used for xonly assessment, as attachments. They will eventually head towards src/regress but for now, people can play with them.
#include <sys/types.h> #include <sys/mman.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <setjmp.h> #include <dlfcn.h> #include <string.h> #include <err.h> #include <wchar.h> int main(int argc, char *argv[]); void *s_ldso(void); void *s_mmap_xz(void); void *s_mmap_x(void); void *s_mmap_nrx(void); void *s_mmap_nwx(void); void *s_mmap_xnwx(void); struct readable { char *name; void *(*setup)(void); int isfn; void *addr; int uu, ku; int skip; } readables[] = { { "ld.so", s_ldso, 1, }, { "mmap xz", s_mmap_xz, 0, }, { "mmap x", s_mmap_x, 0, }, { "mmap nrx", s_mmap_nrx, 0, }, { "mmap nwx", s_mmap_nwx, 0, }, { "mmap xnwx", s_mmap_xnwx, 0, }, { "main", NULL, 1, &main }, { "libc unmapped?", NULL, 1, &wcstol }, { "libc mapped", NULL, 1, &mmap } }; jmp_buf fail; void sigsegv(int _unused) { longjmp(fail, 1); } void * s_mmap_xz(void) { return mmap(NULL, getpagesize(), PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); /* no data written. tests read-fault of an unbacked exec-only page */ } void * s_mmap_x(void) { char *addr; addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); explicit_bzero(addr, getpagesize()); mprotect(addr, getpagesize(), PROT_EXEC); return addr; } void * s_mmap_nrx(void) { char *addr; addr = mmap(NULL, getpagesize(), PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); mprotect(addr, getpagesize(), PROT_READ | PROT_WRITE); explicit_bzero(addr, getpagesize()); mprotect(addr, getpagesize(), PROT_EXEC); return addr; } void * s_mmap_nwx(void) { char *addr; addr = mmap(NULL, getpagesize(), PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); mprotect(addr, getpagesize(), PROT_WRITE); explicit_bzero(addr, getpagesize()); mprotect(addr, getpagesize(), PROT_EXEC); return addr; } void * s_mmap_xnwx(void) { char *addr; addr = mmap(NULL, getpagesize(), PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); mprotect(addr, getpagesize(), PROT_NONE); mprotect(addr, getpagesize(), PROT_WRITE); explicit_bzero(addr, getpagesize()); mprotect(addr, getpagesize(), PROT_EXEC); return addr; } void * s_ldso(void) { void *handle, *dlopenp; handle = dlopen("ld.so", RTLD_NOW); if (handle == NULL) *(volatile char *)0 = 0; dlopenp = dlsym(handle, "dlopen"); return dlopenp; } void s_table() { int i; for (i = 0; i < sizeof(readables)/sizeof(readables[0]); i++) { if (setjmp(fail) == 0) { if (readables[i].setup) readables[i].addr = readables[i].setup(); } else readables[i].skip = 1; #ifdef __hppa__ /* hppa ptable headers point at the instructions */ if (readables[i].isfn) readables[i].addr = (void *)*(u_int *) ((u_int)readables[i].addr & ~3); #endif } } int main(int argc, char *argv[]) { int p[2], i; signal(SIGSEGV, sigsegv); signal(SIGBUS, sigsegv); s_table(); for (i = 0; i < sizeof(readables)/sizeof(readables[0]); i++) { struct readable *r = &readables[i]; char c; if (r->skip) continue; pipe(p); fcntl(p[0], F_SETFL, O_NONBLOCK); if (write(p[1], r->addr, 1) == 1 && read(p[0], &c, 1) == 1) r->ku = 1; if (setjmp(fail) == 0) { volatile int x = *(int *)(r->addr); r->uu = 1; } close(p[0]); close(p[1]); } printf("%-16s userland kernel\n", ""); for (i = 0; i < sizeof(readables)/sizeof(readables[0]); i++) { struct readable *r = &readables[i]; if (r->skip) printf("%-16s %-10s %-10s\n", r->name, "skipped", "skipped"); else printf("%-16s %-10s %-10s\n", r->name, r->uu ? "readable" : "unreadable", r->ku ? "readable" : "unreadable"); } }
#include <sys/types.h> #include <sys/mman.h> #include <sys/exec_elf.h> #include <dlfcn.h> #include <link.h> #include <setjmp.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) int pgsize; jmp_buf fail; void sigsegv(int _unused) { longjmp(fail, 1); } int callback(struct dl_phdr_info *info, size_t size, void *cookie) { Elf_Addr start, end, p; Elf_Off len; void *test; int i, count, total, col; /* Find all text segments */ for (i = 0; i < info->dlpi_phnum; i++) { if (info->dlpi_phdr[i].p_type == PT_LOAD && info->dlpi_phdr[i].p_flags & PF_X) { start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; len = info->dlpi_phdr[i].p_memsz; end = start + len; printf("%s %llx-%llx (%llx, %lld pg) prot %s\n\t", info->dlpi_name, (uint64_t)start, (uint64_t)end, (uint64_t)len, ((uint64_t)len + pgsize) / pgsize, (info->dlpi_phdr[i].p_flags & PF_R) ? "RX" : "X"); test = malloc(pgsize); count = total = col = 0; /* attempt to read the entire text segment */ for (p = start; p < end; p += pgsize) { total++; if (setjmp(fail) == 0) { memcpy(test, (char *)p, pgsize); printf("y"); count++; } else { printf("n"); } if (++col % 64 == 0) printf("\n\t"); } printf("\n"); printf("\tread %d pages of %d\n", count, total); if (count != total) printf("\tcannot read the whole\n"); free(test); } } return 0; } int main() { pgsize = getpagesize(); signal(SIGSEGV, sigsegv); signal(SIGBUS, sigsegv); dl_iterate_phdr(callback, NULL); }