crash.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2019-2020, Shannon Booth <shannon.ml.booth@gmail.com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  20. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <AK/Function.h>
  28. #include <AK/String.h>
  29. #include <Kernel/API/Syscall.h>
  30. #include <Kernel/IO.h>
  31. #include <LibCore/ArgsParser.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <sys/mman.h>
  35. #include <sys/wait.h>
  36. #pragma GCC optimize("O0")
  37. class Crash {
  38. public:
  39. enum class RunType {
  40. UsingChildProcess,
  41. UsingCurrentProcess,
  42. };
  43. enum class Failure {
  44. DidNotCrash,
  45. UnexpectedError,
  46. };
  47. Crash(String test_type, Function<Crash::Failure()> crash_function)
  48. : m_type(test_type)
  49. , m_crash_function(move(crash_function))
  50. {
  51. }
  52. void run(RunType run_type)
  53. {
  54. printf("\x1B[33mTesting\x1B[0m: \"%s\"\n", m_type.characters());
  55. auto run_crash_and_print_if_error = [this]() {
  56. auto failure = m_crash_function();
  57. // If we got here something went wrong
  58. printf("\x1B[31mFAIL\x1B[0m: ");
  59. switch (failure) {
  60. case Failure::DidNotCrash:
  61. printf("Did not crash!\n");
  62. break;
  63. case Failure::UnexpectedError:
  64. printf("Unexpected error!\n");
  65. break;
  66. default:
  67. ASSERT_NOT_REACHED();
  68. }
  69. };
  70. if (run_type == RunType::UsingCurrentProcess) {
  71. run_crash_and_print_if_error();
  72. } else {
  73. // Run the test in a child process so that we do not crash the crash program :^)
  74. pid_t pid = fork();
  75. if (pid < 0) {
  76. perror("fork");
  77. ASSERT_NOT_REACHED();
  78. } else if (pid == 0) {
  79. run_crash_and_print_if_error();
  80. exit(0);
  81. }
  82. int status;
  83. waitpid(pid, &status, 0);
  84. if (WIFSIGNALED(status))
  85. printf("\x1B[32mPASS\x1B[0m: Terminated with signal %d\n", WTERMSIG(status));
  86. }
  87. }
  88. private:
  89. String m_type;
  90. Function<Crash::Failure()> m_crash_function;
  91. };
  92. int main(int argc, char** argv)
  93. {
  94. bool do_all_crash_types = false;
  95. bool do_segmentation_violation = false;
  96. bool do_division_by_zero = false;
  97. bool do_illegal_instruction = false;
  98. bool do_abort = false;
  99. bool do_write_to_uninitialized_malloc_memory = false;
  100. bool do_write_to_freed_memory = false;
  101. bool do_write_to_read_only_memory = false;
  102. bool do_read_from_uninitialized_malloc_memory = false;
  103. bool do_read_from_freed_memory = false;
  104. bool do_invalid_stack_pointer_on_syscall = false;
  105. bool do_invalid_stack_pointer_on_page_fault = false;
  106. bool do_syscall_from_writeable_memory = false;
  107. bool do_execute_non_executable_memory = false;
  108. bool do_trigger_user_mode_instruction_prevention = false;
  109. bool do_use_io_instruction = false;
  110. bool do_read_cpu_counter = false;
  111. auto args_parser = Core::ArgsParser();
  112. args_parser.set_general_help(
  113. "Exercise error-handling paths of the execution environment "
  114. "(i.e., Kernel or UE) by crashing in many different ways.");
  115. args_parser.add_option(do_all_crash_types, "Test that all of the following crash types crash as expected", nullptr, 'A');
  116. args_parser.add_option(do_segmentation_violation, "Perform a segmentation violation by dereferencing an invalid pointer", nullptr, 's');
  117. args_parser.add_option(do_division_by_zero, "Perform a division by zero", nullptr, 'd');
  118. args_parser.add_option(do_illegal_instruction, "Execute an illegal CPU instruction", nullptr, 'i');
  119. args_parser.add_option(do_abort, "Call `abort()`", nullptr, 'a');
  120. args_parser.add_option(do_read_from_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then read from it", nullptr, 'm');
  121. args_parser.add_option(do_read_from_freed_memory, "Read a pointer from memory freed using `free()`, then read from it", nullptr, 'f');
  122. args_parser.add_option(do_write_to_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then write to it", nullptr, 'M');
  123. args_parser.add_option(do_write_to_freed_memory, "Read a pointer from memory freed using `free()`, then write to it", nullptr, 'F');
  124. args_parser.add_option(do_write_to_read_only_memory, "Write to read-only memory", nullptr, 'r');
  125. args_parser.add_option(do_invalid_stack_pointer_on_syscall, "Make a syscall while using an invalid stack pointer", nullptr, 'T');
  126. args_parser.add_option(do_invalid_stack_pointer_on_page_fault, "Trigger a page fault while using an invalid stack pointer", nullptr, 't');
  127. args_parser.add_option(do_syscall_from_writeable_memory, "Make a syscall from writeable memory", nullptr, 'S');
  128. args_parser.add_option(do_execute_non_executable_memory, "Attempt to execute non-executable memory (not mapped with PROT_EXEC)", nullptr, 'X');
  129. args_parser.add_option(do_trigger_user_mode_instruction_prevention, "Attempt to trigger an x86 User Mode Instruction Prevention fault", nullptr, 'U');
  130. args_parser.add_option(do_use_io_instruction, "Use an x86 I/O instruction in userspace", nullptr, 'I');
  131. args_parser.add_option(do_read_cpu_counter, "Read the x86 TSC (Time Stamp Counter) directly", nullptr, 'c');
  132. if (argc != 2) {
  133. args_parser.print_usage(stderr, argv[0]);
  134. exit(1);
  135. }
  136. args_parser.parse(argc, argv);
  137. Crash::RunType run_type = do_all_crash_types ? Crash::RunType::UsingChildProcess
  138. : Crash::RunType::UsingCurrentProcess;
  139. if (do_segmentation_violation || do_all_crash_types) {
  140. Crash("Segmentation violation", []() {
  141. volatile int* crashme = nullptr;
  142. *crashme = 0xbeef;
  143. return Crash::Failure::DidNotCrash;
  144. }).run(run_type);
  145. }
  146. if (do_division_by_zero || do_all_crash_types) {
  147. Crash("Division by zero", []() {
  148. volatile int lala = 10;
  149. volatile int zero = 0;
  150. [[maybe_unused]] volatile int test = lala / zero;
  151. return Crash::Failure::DidNotCrash;
  152. }).run(run_type);
  153. }
  154. if (do_illegal_instruction || do_all_crash_types) {
  155. Crash("Illegal instruction", []() {
  156. asm volatile("ud2");
  157. return Crash::Failure::DidNotCrash;
  158. }).run(run_type);
  159. }
  160. if (do_abort || do_all_crash_types) {
  161. Crash("Abort", []() {
  162. abort();
  163. return Crash::Failure::DidNotCrash;
  164. }).run(run_type);
  165. }
  166. if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) {
  167. Crash("Read from uninitialized malloc memory", []() {
  168. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  169. if (!uninitialized_memory)
  170. return Crash::Failure::UnexpectedError;
  171. [[maybe_unused]] volatile auto x = uninitialized_memory[0][0];
  172. return Crash::Failure::DidNotCrash;
  173. }).run(run_type);
  174. }
  175. if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) {
  176. Crash("Read from freed memory", []() {
  177. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  178. if (!uninitialized_memory)
  179. return Crash::Failure::UnexpectedError;
  180. free(uninitialized_memory);
  181. [[maybe_unused]] volatile auto x = uninitialized_memory[4][0];
  182. return Crash::Failure::DidNotCrash;
  183. }).run(run_type);
  184. }
  185. if (do_write_to_uninitialized_malloc_memory || do_all_crash_types) {
  186. Crash("Write to uninitialized malloc memory", []() {
  187. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  188. if (!uninitialized_memory)
  189. return Crash::Failure::UnexpectedError;
  190. uninitialized_memory[4][0] = 1;
  191. return Crash::Failure::DidNotCrash;
  192. }).run(run_type);
  193. }
  194. if (do_write_to_freed_memory || do_all_crash_types) {
  195. Crash("Write to freed memory", []() {
  196. auto* uninitialized_memory = (volatile u32**)malloc(1024);
  197. if (!uninitialized_memory)
  198. return Crash::Failure::UnexpectedError;
  199. free(uninitialized_memory);
  200. uninitialized_memory[4][0] = 1;
  201. return Crash::Failure::DidNotCrash;
  202. }).run(run_type);
  203. }
  204. if (do_write_to_read_only_memory || do_all_crash_types) {
  205. Crash("Write to read only memory", []() {
  206. auto* ptr = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
  207. if (ptr != MAP_FAILED)
  208. return Crash::Failure::UnexpectedError;
  209. *ptr = 'x'; // This should work fine.
  210. int rc = mprotect(ptr, 4096, PROT_READ);
  211. if (rc != 0 || *ptr != 'x')
  212. return Crash::Failure::UnexpectedError;
  213. *ptr = 'y'; // This should crash!
  214. return Crash::Failure::DidNotCrash;
  215. }).run(run_type);
  216. }
  217. if (do_invalid_stack_pointer_on_syscall || do_all_crash_types) {
  218. Crash("Invalid stack pointer on syscall", []() {
  219. u8* makeshift_stack = (u8*)mmap(nullptr, 0, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK, 0, 0);
  220. if (!makeshift_stack)
  221. return Crash::Failure::UnexpectedError;
  222. u8* makeshift_esp = makeshift_stack + 2048;
  223. asm volatile("mov %%eax, %%esp" ::"a"(makeshift_esp));
  224. getuid();
  225. dbgln("Survived syscall with MAP_STACK stack");
  226. u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  227. if (!bad_stack)
  228. return Crash::Failure::UnexpectedError;
  229. u8* bad_esp = bad_stack + 2048;
  230. asm volatile("mov %%eax, %%esp" ::"a"(bad_esp));
  231. getuid();
  232. return Crash::Failure::DidNotCrash;
  233. }).run(run_type);
  234. }
  235. if (do_invalid_stack_pointer_on_page_fault || do_all_crash_types) {
  236. Crash("Invalid stack pointer on page fault", []() {
  237. u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  238. if (!bad_stack)
  239. return Crash::Failure::UnexpectedError;
  240. u8* bad_esp = bad_stack + 2048;
  241. asm volatile("mov %%eax, %%esp" ::"a"(bad_esp));
  242. asm volatile("pushl $0");
  243. return Crash::Failure::DidNotCrash;
  244. }).run(run_type);
  245. }
  246. if (do_syscall_from_writeable_memory || do_all_crash_types) {
  247. Crash("Syscall from writable memory", []() {
  248. u8 buffer[] = { 0xb8, Syscall::SC_getuid, 0, 0, 0, 0xcd, 0x82 };
  249. ((void (*)())buffer)();
  250. return Crash::Failure::DidNotCrash;
  251. }).run(run_type);
  252. }
  253. if (do_execute_non_executable_memory || do_all_crash_types) {
  254. Crash("Execute non executable memory", []() {
  255. auto* ptr = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  256. if (ptr == MAP_FAILED)
  257. return Crash::Failure::UnexpectedError;
  258. ptr[0] = 0xc3; // ret
  259. typedef void* (*CrashyFunctionPtr)();
  260. ((CrashyFunctionPtr)ptr)();
  261. return Crash::Failure::DidNotCrash;
  262. }).run(run_type);
  263. }
  264. if (do_trigger_user_mode_instruction_prevention || do_all_crash_types) {
  265. Crash("Trigger x86 User Mode Instruction Prevention", []() {
  266. asm volatile("str %eax");
  267. return Crash::Failure::DidNotCrash;
  268. }).run(run_type);
  269. }
  270. if (do_use_io_instruction || do_all_crash_types) {
  271. Crash("Attempt to use an I/O instruction", [] {
  272. u8 keyboard_status = IO::in8(0x64);
  273. printf("Keyboard status: %#02x\n", keyboard_status);
  274. return Crash::Failure::DidNotCrash;
  275. }).run(run_type);
  276. }
  277. if (do_read_cpu_counter || do_all_crash_types) {
  278. Crash("Read the CPU timestamp counter", [] {
  279. asm volatile("rdtsc");
  280. return Crash::Failure::DidNotCrash;
  281. }).run(run_type);
  282. }
  283. return 0;
  284. }