1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stdint.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9 10#include <zircon/syscalls.h> 11 12// defined in cpp_specific.cpp. 13int cpp_out_of_mem(void); 14 15typedef struct { 16 const char* name; 17 int (*func)(volatile unsigned int*); 18 const char* desc; 19} command_t; 20 21int blind_write(volatile unsigned int* addr) { 22 *addr = 0xBAD1DEA; 23 return 0; 24} 25 26int blind_read(volatile unsigned int* addr) { 27 return (int)(*addr); 28} 29 30int ro_write(volatile unsigned int* addr) { 31 // test that we cannot write to RO code memory 32 volatile unsigned int* p = (volatile unsigned int*)&ro_write; 33 *p = 99; 34 return 0; 35} 36 37int nx_run(volatile unsigned int* addr) { 38 // Test that we cannot execute NX memory. Use stack memory for this 39 // because using a static means the compiler might generate a direct 40 // branch to the symbol rather than computing the function pointer 41 // address in a register as the code looks like it would do, and 42 // declaring a static writable variable that the compiler can see 43 // nobody writes leaves the compiler free to morph it into a static 44 // const variable, which gets put into a mergeable rodata section, and 45 // the Gold linker for aarch64 cannot handle a branch into a mergeable 46 // section. 47 uint8_t codebuf[16] = {}; 48 void (*func)(void) = (void*)codebuf; 49 func(); 50 return 0; 51} 52 53// Note that as of 5/21/16 the crash reads: 54// PageFault:199: UNIMPLEMENTED: faulting with a page already present. 55int stack_overflow(volatile unsigned int* i_array) { 56 volatile unsigned int array[512]; 57 if (i_array) { 58 array[0] = i_array[0] + 1; 59 if (array[0] < 4096) 60 return stack_overflow(array); 61 } else { 62 array[0] = 0; 63 return stack_overflow(array); 64 } 65 return 0; 66} 67 68int stack_buf_overrun(volatile unsigned int* arg) { 69 volatile unsigned int array[6]; 70 if (!arg) { 71 return stack_buf_overrun(array); 72 } else { 73 memset((void*)arg, 0, sizeof(array[0]) * 7); 74 } 75 return 0; 76} 77 78int undefined(volatile unsigned int* unused) { 79#if defined(__x86_64__) 80 __asm__ volatile("ud2"); 81#elif defined(__aarch64__) 82 __asm__ volatile("brk #0"); // not undefined, but close enough 83#else 84#error "need to define undefined for this architecture" 85#endif 86 return 0; 87} 88 89int oom(volatile unsigned int* unused) { 90 return cpp_out_of_mem(); 91} 92 93#include <unistd.h> 94 95// volatile to ensure compiler doesn't optimize the allocs away 96volatile char* mem_alloc; 97 98int mem(volatile unsigned int* arg) { 99 int count = 0; 100 for (;;) { 101 mem_alloc = malloc(1024*1024); 102 memset((void*)mem_alloc, 0xa5, 1024*1024); 103 count++; 104 if ((count % 128) == 0) { 105 zx_nanosleep(zx_deadline_after(ZX_MSEC(250))); 106 write(1, ".", 1); 107 } 108 } 109 110} 111 112int use_after_free(volatile unsigned int* arg) { 113 char *p = strdup("Hello, world!"); 114 free(p); 115 puts(p); 116 return 0; 117} 118 119command_t commands[] = { 120 {"write0", blind_write, "write to address 0x0"}, 121 {"read0", blind_read, "read address 0x0"}, 122 {"writero", ro_write, "write to read only code segment"}, 123 {"stackov", stack_overflow, "overflow the stack (recursive)"}, 124 {"stackbuf", stack_buf_overrun, "overrun a buffer on the stack"}, 125 {"und", undefined, "undefined instruction"}, 126 {"nx_run", nx_run, "run in no-execute memory"}, 127 {"oom", oom, "out of memory c++ death"}, 128 {"mem", mem, "out of memory"}, 129 {"use_after_free", use_after_free, "use memory after freeing it"}, 130 {NULL, NULL, NULL}}; 131 132int main(int argc, char** argv) { 133 printf("=@ crasher @=\n"); 134 135 if (argc < 2) { 136 printf("default to write0 (use 'help' for more options).\n"); 137 blind_write(NULL); 138 } else { 139 if (strcmp("help", argv[1])) { 140 for (command_t* cmd = commands; cmd->name != NULL; ++cmd) { 141 if (strcmp(cmd->name, argv[1]) == 0) { 142 printf("doing : %s\n", cmd->desc); 143 cmd->func(NULL); 144 goto exit; // should not reach here. 145 } 146 } 147 } 148 149 printf("known commands are:\n"); 150 for (command_t* cmd = commands; cmd->name != NULL; ++cmd) { 151 printf("%s : %s\n", cmd->name, cmd->desc); 152 } 153 return 0; 154 } 155 156exit: 157 printf("crasher: exiting normally ?!!\n"); 158 return 0; 159} 160