crash.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2019-2020, Shannon Booth <shannon.ml.booth@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Function.h>
  8. #include <AK/String.h>
  9. #include <Kernel/IO.h>
  10. #include <LibCore/ArgsParser.h>
  11. #include <LibTest/CrashTest.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <sys/mman.h>
  15. #include <sys/wait.h>
  16. #include <syscall.h>
  17. #include <unistd.h>
  18. using Test::Crash;
  19. #pragma GCC optimize("O0")
  20. int main(int argc, char** argv)
  21. {
  22. bool do_all_crash_types = false;
  23. bool do_segmentation_violation = false;
  24. bool do_division_by_zero = false;
  25. bool do_illegal_instruction = false;
  26. bool do_abort = false;
  27. bool do_write_to_uninitialized_malloc_memory = false;
  28. bool do_write_to_freed_memory = false;
  29. bool do_write_to_read_only_memory = false;
  30. bool do_read_from_uninitialized_malloc_memory = false;
  31. bool do_read_from_freed_memory = false;
  32. bool do_invalid_stack_pointer_on_syscall = false;
  33. bool do_invalid_stack_pointer_on_page_fault = false;
  34. bool do_syscall_from_writeable_memory = false;
  35. bool do_execute_non_executable_memory = false;
  36. bool do_trigger_user_mode_instruction_prevention = false;
  37. bool do_use_io_instruction = false;
  38. bool do_read_cpu_counter = false;
  39. bool do_pledge_violation = false;
  40. bool do_failing_assertion = false;
  41. auto args_parser = Core::ArgsParser();
  42. args_parser.set_general_help(
  43. "Exercise error-handling paths of the execution environment "
  44. "(i.e., Kernel or UE) by crashing in many different ways.");
  45. args_parser.add_option(do_all_crash_types, "Test that all of the following crash types crash as expected", nullptr, 'A');
  46. args_parser.add_option(do_segmentation_violation, "Perform a segmentation violation by dereferencing an invalid pointer", nullptr, 's');
  47. args_parser.add_option(do_division_by_zero, "Perform a division by zero", nullptr, 'd');
  48. args_parser.add_option(do_illegal_instruction, "Execute an illegal CPU instruction", nullptr, 'i');
  49. args_parser.add_option(do_abort, "Call `abort()`", nullptr, 'a');
  50. args_parser.add_option(do_read_from_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then read from it", nullptr, 'm');
  51. args_parser.add_option(do_read_from_freed_memory, "Read a pointer from memory freed using `free()`, then read from it", nullptr, 'f');
  52. args_parser.add_option(do_write_to_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then write to it", nullptr, 'M');
  53. args_parser.add_option(do_write_to_freed_memory, "Read a pointer from memory freed using `free()`, then write to it", nullptr, 'F');
  54. args_parser.add_option(do_write_to_read_only_memory, "Write to read-only memory", nullptr, 'r');
  55. args_parser.add_option(do_invalid_stack_pointer_on_syscall, "Make a syscall while using an invalid stack pointer", nullptr, 'T');
  56. args_parser.add_option(do_invalid_stack_pointer_on_page_fault, "Trigger a page fault while using an invalid stack pointer", nullptr, 't');
  57. args_parser.add_option(do_syscall_from_writeable_memory, "Make a syscall from writeable memory", nullptr, 'S');
  58. args_parser.add_option(do_execute_non_executable_memory, "Attempt to execute non-executable memory (not mapped with PROT_EXEC)", nullptr, 'X');
  59. args_parser.add_option(do_trigger_user_mode_instruction_prevention, "Attempt to trigger an x86 User Mode Instruction Prevention fault", nullptr, 'U');
  60. args_parser.add_option(do_use_io_instruction, "Use an x86 I/O instruction in userspace", nullptr, 'I');
  61. args_parser.add_option(do_read_cpu_counter, "Read the x86 TSC (Time Stamp Counter) directly", nullptr, 'c');
  62. args_parser.add_option(do_pledge_violation, "Violate pledge()'d promises", nullptr, 'p');
  63. args_parser.add_option(do_failing_assertion, "Perform a failing assertion", nullptr, 'n');
  64. if (argc != 2) {
  65. args_parser.print_usage(stderr, argv[0]);
  66. exit(1);
  67. }
  68. args_parser.parse(argc, argv);
  69. Crash::RunType run_type = do_all_crash_types ? Crash::RunType::UsingChildProcess
  70. : Crash::RunType::UsingCurrentProcess;
  71. if (do_segmentation_violation || do_all_crash_types) {
  72. Crash("Segmentation violation", []() {
  73. volatile int* crashme = nullptr;
  74. *crashme = 0xbeef;
  75. return Crash::Failure::DidNotCrash;
  76. }).run(run_type);
  77. }
  78. if (do_division_by_zero || do_all_crash_types) {
  79. Crash("Division by zero", []() {
  80. volatile int lala = 10;
  81. volatile int zero = 0;
  82. [[maybe_unused]] volatile int test = lala / zero;
  83. return Crash::Failure::DidNotCrash;
  84. }).run(run_type);
  85. }
  86. if (do_illegal_instruction || do_all_crash_types) {
  87. Crash("Illegal instruction", []() {
  88. asm volatile("ud2");
  89. return Crash::Failure::DidNotCrash;
  90. }).run(run_type);
  91. }
  92. if (do_abort || do_all_crash_types) {
  93. Crash("Abort", []() {
  94. abort();
  95. return Crash::Failure::DidNotCrash;
  96. }).run(run_type);
  97. }
  98. if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) {
  99. Crash("Read from uninitialized malloc memory", []() {
  100. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  101. if (!uninitialized_memory)
  102. return Crash::Failure::UnexpectedError;
  103. #pragma GCC diagnostic push
  104. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  105. [[maybe_unused]] volatile auto x = uninitialized_memory[0][0];
  106. #pragma GCC diagnostic pop
  107. return Crash::Failure::DidNotCrash;
  108. }).run(run_type);
  109. }
  110. if (do_read_from_freed_memory || do_all_crash_types) {
  111. Crash("Read from freed memory", []() {
  112. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  113. if (!uninitialized_memory)
  114. return Crash::Failure::UnexpectedError;
  115. free(uninitialized_memory);
  116. [[maybe_unused]] volatile auto x = uninitialized_memory[4][0];
  117. return Crash::Failure::DidNotCrash;
  118. }).run(run_type);
  119. }
  120. if (do_write_to_uninitialized_malloc_memory || do_all_crash_types) {
  121. Crash("Write to uninitialized malloc memory", []() {
  122. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  123. if (!uninitialized_memory)
  124. return Crash::Failure::UnexpectedError;
  125. #pragma GCC diagnostic push
  126. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  127. uninitialized_memory[4][0] = 1;
  128. #pragma GCC diagnostic pop
  129. return Crash::Failure::DidNotCrash;
  130. }).run(run_type);
  131. }
  132. if (do_write_to_freed_memory || do_all_crash_types) {
  133. Crash("Write to freed memory", []() {
  134. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  135. if (!uninitialized_memory)
  136. return Crash::Failure::UnexpectedError;
  137. free(uninitialized_memory);
  138. uninitialized_memory[4][0] = 1;
  139. return Crash::Failure::DidNotCrash;
  140. }).run(run_type);
  141. }
  142. if (do_write_to_read_only_memory || do_all_crash_types) {
  143. Crash("Write to read only memory", []() {
  144. auto* ptr = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0);
  145. if (ptr == MAP_FAILED)
  146. return Crash::Failure::UnexpectedError;
  147. *ptr = 'x'; // This should work fine.
  148. int rc = mprotect(ptr, 4096, PROT_READ);
  149. if (rc != 0 || *ptr != 'x')
  150. return Crash::Failure::UnexpectedError;
  151. *ptr = 'y'; // This should crash!
  152. return Crash::Failure::DidNotCrash;
  153. }).run(run_type);
  154. }
  155. if (do_invalid_stack_pointer_on_syscall || do_all_crash_types) {
  156. Crash("Invalid stack pointer on syscall", []() {
  157. u8* makeshift_stack = (u8*)mmap(nullptr, 0, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK, 0, 0);
  158. if (!makeshift_stack)
  159. return Crash::Failure::UnexpectedError;
  160. u8* makeshift_esp = makeshift_stack + 2048;
  161. asm volatile("mov %%eax, %%esp" ::"a"(makeshift_esp));
  162. getuid();
  163. dbgln("Survived syscall with MAP_STACK stack");
  164. u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  165. if (!bad_stack)
  166. return Crash::Failure::UnexpectedError;
  167. u8* bad_esp = bad_stack + 2048;
  168. asm volatile("mov %%eax, %%esp" ::"a"(bad_esp));
  169. getuid();
  170. return Crash::Failure::DidNotCrash;
  171. }).run(run_type);
  172. }
  173. if (do_invalid_stack_pointer_on_page_fault || do_all_crash_types) {
  174. Crash("Invalid stack pointer on page fault", []() {
  175. u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  176. if (!bad_stack)
  177. return Crash::Failure::UnexpectedError;
  178. u8* bad_esp = bad_stack + 2048;
  179. #ifndef __LP64__
  180. asm volatile("mov %%eax, %%esp" ::"a"(bad_esp));
  181. asm volatile("pushl $0");
  182. #else
  183. asm volatile("movq %%rax, %%rsp" ::"a"(bad_esp));
  184. asm volatile("pushq $0");
  185. #endif
  186. return Crash::Failure::DidNotCrash;
  187. }).run(run_type);
  188. }
  189. if (do_syscall_from_writeable_memory || do_all_crash_types) {
  190. Crash("Syscall from writable memory", []() {
  191. u8 buffer[] = { 0xb8, Syscall::SC_getuid, 0, 0, 0, 0xcd, 0x82 };
  192. ((void (*)())buffer)();
  193. return Crash::Failure::DidNotCrash;
  194. }).run(run_type);
  195. }
  196. if (do_execute_non_executable_memory || do_all_crash_types) {
  197. Crash("Execute non executable memory", []() {
  198. auto* ptr = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  199. if (ptr == MAP_FAILED)
  200. return Crash::Failure::UnexpectedError;
  201. ptr[0] = 0xc3; // ret
  202. typedef void* (*CrashyFunctionPtr)();
  203. ((CrashyFunctionPtr)ptr)();
  204. return Crash::Failure::DidNotCrash;
  205. }).run(run_type);
  206. }
  207. if (do_trigger_user_mode_instruction_prevention || do_all_crash_types) {
  208. Crash("Trigger x86 User Mode Instruction Prevention", []() {
  209. asm volatile("str %eax");
  210. return Crash::Failure::DidNotCrash;
  211. }).run(run_type);
  212. }
  213. if (do_use_io_instruction || do_all_crash_types) {
  214. Crash("Attempt to use an I/O instruction", [] {
  215. u8 keyboard_status = IO::in8(0x64);
  216. printf("Keyboard status: %#02x\n", keyboard_status);
  217. return Crash::Failure::DidNotCrash;
  218. }).run(run_type);
  219. }
  220. if (do_read_cpu_counter || do_all_crash_types) {
  221. Crash("Read the CPU timestamp counter", [] {
  222. asm volatile("rdtsc");
  223. return Crash::Failure::DidNotCrash;
  224. }).run(run_type);
  225. }
  226. if (do_pledge_violation || do_all_crash_types) {
  227. Crash("Violate pledge()'d promises", [] {
  228. if (pledge("", nullptr) < 0) {
  229. perror("pledge");
  230. return Crash::Failure::DidNotCrash;
  231. }
  232. printf("Didn't pledge 'stdio', this should fail!\n");
  233. return Crash::Failure::DidNotCrash;
  234. }).run(run_type);
  235. }
  236. if (do_failing_assertion || do_all_crash_types) {
  237. Crash("Perform a failing assertion", [] {
  238. VERIFY(1 == 2);
  239. return Crash::Failure::DidNotCrash;
  240. }).run(run_type);
  241. }
  242. return 0;
  243. }