Serenity Operating System
at master 337 lines 14 kB view raw
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 8#include <AK/Assertions.h> 9#include <AK/DeprecatedString.h> 10#include <AK/Function.h> 11#if ARCH(X86_64) 12# include <Kernel/Arch/x86_64/IO.h> 13#endif 14#include <LibCore/ArgsParser.h> 15#include <LibCore/Object.h> 16#include <LibTest/CrashTest.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <sys/mman.h> 20#include <sys/wait.h> 21#include <syscall.h> 22#include <unistd.h> 23 24using Test::Crash; 25 26#if defined(AK_COMPILER_CLANG) 27# pragma clang optimize off 28#else 29# pragma GCC optimize("O0") 30#endif 31 32int main(int argc, char** argv) 33{ 34 Vector<StringView> arguments; 35 arguments.ensure_capacity(argc); 36 for (auto i = 0; i < argc; ++i) 37 arguments.append({ argv[i], strlen(argv[i]) }); 38 39 bool do_all_crash_types = false; 40 bool do_segmentation_violation = false; 41 bool do_division_by_zero = false; 42 bool do_illegal_instruction = false; 43 bool do_abort = false; 44 bool do_write_to_uninitialized_malloc_memory = false; 45 bool do_write_to_freed_memory = false; 46 bool do_write_to_read_only_memory = false; 47 bool do_read_from_uninitialized_malloc_memory = false; 48 bool do_read_from_freed_memory = false; 49 bool do_invalid_stack_pointer_on_syscall = false; 50 bool do_invalid_stack_pointer_on_page_fault = false; 51 bool do_syscall_from_writeable_memory = false; 52 bool do_legitimate_syscall = false; 53 bool do_execute_non_executable_memory = false; 54 bool do_trigger_user_mode_instruction_prevention = false; 55#if ARCH(X86_64) 56 bool do_use_io_instruction = false; 57#endif 58 bool do_pledge_violation = false; 59 bool do_failing_assertion = false; 60 bool do_deref_null_refptr = false; 61 62 auto args_parser = Core::ArgsParser(); 63 args_parser.set_general_help( 64 "Exercise error-handling paths of the execution environment " 65 "(i.e., Kernel or UE) by crashing in many different ways."); 66 args_parser.add_option(do_all_crash_types, "Test that all (except -U) of the following crash types crash as expected (default behavior)", nullptr, 'A'); 67 args_parser.add_option(do_segmentation_violation, "Perform a segmentation violation by dereferencing an invalid pointer", nullptr, 's'); 68 args_parser.add_option(do_division_by_zero, "Perform a division by zero", nullptr, 'd'); 69 args_parser.add_option(do_illegal_instruction, "Execute an illegal CPU instruction", nullptr, 'i'); 70 args_parser.add_option(do_abort, "Call `abort()`", nullptr, 'a'); 71 args_parser.add_option(do_read_from_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then read from it", nullptr, 'm'); 72 args_parser.add_option(do_read_from_freed_memory, "Read a pointer from memory freed using `free()`, then read from it", nullptr, 'f'); 73 args_parser.add_option(do_write_to_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then write to it", nullptr, 'M'); 74 args_parser.add_option(do_write_to_freed_memory, "Read a pointer from memory freed using `free()`, then write to it", nullptr, 'F'); 75 args_parser.add_option(do_write_to_read_only_memory, "Write to read-only memory", nullptr, 'r'); 76 args_parser.add_option(do_invalid_stack_pointer_on_syscall, "Make a syscall while using an invalid stack pointer", nullptr, 'T'); 77 args_parser.add_option(do_invalid_stack_pointer_on_page_fault, "Trigger a page fault while using an invalid stack pointer", nullptr, 't'); 78 args_parser.add_option(do_syscall_from_writeable_memory, "Make a syscall from writeable memory", nullptr, 'S'); 79 args_parser.add_option(do_legitimate_syscall, "Make a syscall from legitimate memory (but outside syscall-code mapped region)", nullptr, 'y'); 80 args_parser.add_option(do_execute_non_executable_memory, "Attempt to execute non-executable memory (not mapped with PROT_EXEC)", nullptr, 'X'); 81 args_parser.add_option(do_trigger_user_mode_instruction_prevention, "Attempt to trigger an x86 User Mode Instruction Prevention fault. WARNING: This test runs only when invoked manually, see #10042.", nullptr, 'U'); 82#if ARCH(X86_64) 83 args_parser.add_option(do_use_io_instruction, "Use an x86 I/O instruction in userspace", nullptr, 'I'); 84#endif 85 args_parser.add_option(do_pledge_violation, "Violate pledge()'d promises", nullptr, 'p'); 86 args_parser.add_option(do_failing_assertion, "Perform a failing assertion", nullptr, 'n'); 87 args_parser.add_option(do_deref_null_refptr, "Dereference a null RefPtr", nullptr, 'R'); 88 89 if (argc == 1) { 90 do_all_crash_types = true; 91 } else if (argc != 2) { 92 args_parser.print_usage(stderr, arguments[0]); 93 exit(1); 94 } 95 96 args_parser.parse(arguments); 97 98 Crash::RunType run_type = do_all_crash_types ? Crash::RunType::UsingChildProcess 99 : Crash::RunType::UsingCurrentProcess; 100 bool any_failures = false; 101 102 if (do_segmentation_violation || do_all_crash_types) { 103 any_failures |= !Crash("Segmentation violation", []() { 104 volatile int* crashme = nullptr; 105 *crashme = 0xbeef; 106 return Crash::Failure::DidNotCrash; 107 }).run(run_type); 108 } 109 110 if (do_division_by_zero || do_all_crash_types) { 111 any_failures |= !Crash("Division by zero", []() { 112 volatile int lala = 10; 113 volatile int zero = 0; 114 [[maybe_unused]] volatile int test = lala / zero; 115 return Crash::Failure::DidNotCrash; 116 }).run(run_type); 117 } 118 119 if (do_illegal_instruction || do_all_crash_types) { 120 any_failures |= !Crash("Illegal instruction", []() { 121 __builtin_trap(); 122 return Crash::Failure::DidNotCrash; 123 }).run(run_type); 124 } 125 126 if (do_abort || do_all_crash_types) { 127 any_failures |= !Crash("Abort", []() { 128 abort(); 129 return Crash::Failure::DidNotCrash; 130 }).run(run_type); 131 } 132 133 if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) { 134 any_failures |= !Crash("Read from uninitialized malloc memory", []() { 135 auto* uninitialized_memory = (volatile u32**)malloc(1024); 136 if (!uninitialized_memory) 137 return Crash::Failure::UnexpectedError; 138 139 [[maybe_unused]] volatile auto x = uninitialized_memory[0][0]; 140 return Crash::Failure::DidNotCrash; 141 }).run(run_type); 142 } 143 144 if (do_read_from_freed_memory || do_all_crash_types) { 145 any_failures |= !Crash("Read from freed memory", []() { 146 auto* uninitialized_memory = (volatile u32**)malloc(1024); 147 if (!uninitialized_memory) 148 return Crash::Failure::UnexpectedError; 149 150 free(uninitialized_memory); 151#pragma GCC diagnostic push 152#pragma GCC diagnostic ignored "-Wuse-after-free" 153 [[maybe_unused]] volatile auto x = uninitialized_memory[4][0]; 154#pragma GCC diagnostic pop 155 return Crash::Failure::DidNotCrash; 156 }).run(run_type); 157 } 158 159 if (do_write_to_uninitialized_malloc_memory || do_all_crash_types) { 160 any_failures |= !Crash("Write to uninitialized malloc memory", []() { 161 auto* uninitialized_memory = (volatile u32**)malloc(1024); 162 if (!uninitialized_memory) 163 return Crash::Failure::UnexpectedError; 164 165 uninitialized_memory[4][0] = 1; 166 return Crash::Failure::DidNotCrash; 167 }).run(run_type); 168 } 169 170 if (do_write_to_freed_memory || do_all_crash_types) { 171 any_failures |= !Crash("Write to freed memory", []() { 172 auto* uninitialized_memory = (volatile u32**)malloc(1024); 173 if (!uninitialized_memory) 174 return Crash::Failure::UnexpectedError; 175 176#pragma GCC diagnostic push 177#pragma GCC diagnostic ignored "-Wuse-after-free" 178 free(uninitialized_memory); 179 uninitialized_memory[4][0] = 1; 180#pragma GCC diagnostic pop 181 return Crash::Failure::DidNotCrash; 182 }).run(run_type); 183 } 184 185 if (do_write_to_read_only_memory || do_all_crash_types) { 186 any_failures |= !Crash("Write to read only memory", []() { 187 auto* ptr = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0); 188 if (ptr == MAP_FAILED) 189 return Crash::Failure::UnexpectedError; 190 191 *ptr = 'x'; // This should work fine. 192 int rc = mprotect(ptr, 4096, PROT_READ); 193 if (rc != 0 || *ptr != 'x') 194 return Crash::Failure::UnexpectedError; 195 196 *ptr = 'y'; // This should crash! 197 return Crash::Failure::DidNotCrash; 198 }).run(run_type); 199 } 200 201 if (do_invalid_stack_pointer_on_syscall || do_all_crash_types) { 202 any_failures |= !Crash("Invalid stack pointer on syscall", []() { 203 u8* makeshift_stack = (u8*)mmap(nullptr, 0, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK, 0, 0); 204 if (!makeshift_stack) 205 return Crash::Failure::UnexpectedError; 206 207 u8* makeshift_esp = makeshift_stack + 2048; 208#if ARCH(X86_64) 209 asm volatile("mov %%eax, %%esp" ::"a"(makeshift_esp)); 210#elif ARCH(AARCH64) 211 (void)makeshift_esp; 212 TODO_AARCH64(); 213#else 214# error Unknown architecture 215#endif 216 getuid(); 217 dbgln("Survived syscall with MAP_STACK stack"); 218 219 u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 220 if (!bad_stack) 221 return Crash::Failure::UnexpectedError; 222 223 u8* bad_esp = bad_stack + 2048; 224#if ARCH(X86_64) 225 asm volatile("mov %%eax, %%esp" ::"a"(bad_esp)); 226#elif ARCH(AARCH64) 227 (void)bad_esp; 228 TODO_AARCH64(); 229#else 230# error Unknown architecture 231#endif 232 getuid(); 233 return Crash::Failure::DidNotCrash; 234 }).run(run_type); 235 } 236 237 if (do_invalid_stack_pointer_on_page_fault || do_all_crash_types) { 238 any_failures |= !Crash("Invalid stack pointer on page fault", []() { 239 u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 240 if (!bad_stack) 241 return Crash::Failure::UnexpectedError; 242 243 u8* bad_esp = bad_stack + 2048; 244#if ARCH(X86_64) 245 asm volatile("movq %%rax, %%rsp" ::"a"(bad_esp)); 246 asm volatile("pushq $0"); 247#elif ARCH(AARCH64) 248 (void)bad_esp; 249 TODO_AARCH64(); 250#else 251# error Unknown architecture 252#endif 253 254 return Crash::Failure::DidNotCrash; 255 }).run(run_type); 256 } 257 258 if (do_syscall_from_writeable_memory || do_all_crash_types) { 259 any_failures |= !Crash("Syscall from writable memory", []() { 260 u8 buffer[] = { 0xb8, Syscall::SC_getuid, 0, 0, 0, 0xcd, 0x82 }; 261 ((void (*)())buffer)(); 262 return Crash::Failure::DidNotCrash; 263 }).run(run_type); 264 } 265 266 if (do_legitimate_syscall || do_all_crash_types) { 267 any_failures |= !Crash("Regular syscall from outside syscall-code mapped region", []() { 268 // Since 'crash' is dynamically linked, and DynamicLoader only allows LibSystem to make syscalls, this should kill us: 269 Syscall::invoke(Syscall::SC_getuid); 270 return Crash::Failure::DidNotCrash; 271 }).run(run_type); 272 } 273 274 if (do_execute_non_executable_memory || do_all_crash_types) { 275 any_failures |= !Crash("Execute non executable memory", []() { 276 auto* ptr = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 277 if (ptr == MAP_FAILED) 278 return Crash::Failure::UnexpectedError; 279 280 ptr[0] = 0xc3; // ret 281 typedef void* (*CrashyFunctionPtr)(); 282 ((CrashyFunctionPtr)ptr)(); 283 return Crash::Failure::DidNotCrash; 284 }).run(run_type); 285 } 286 287 if (do_trigger_user_mode_instruction_prevention) { 288 any_failures |= !Crash("Trigger x86 User Mode Instruction Prevention", []() { 289#if ARCH(X86_64) 290 asm volatile("str %eax"); 291#elif ARCH(AARCH64) 292 TODO_AARCH64(); 293#else 294# error Unknown architecture 295#endif 296 return Crash::Failure::DidNotCrash; 297 }).run(run_type); 298 } 299 300#if ARCH(X86_64) 301 if (do_use_io_instruction || do_all_crash_types) { 302 any_failures |= !Crash("Attempt to use an I/O instruction", [] { 303 u8 keyboard_status = IO::in8(0x64); 304 outln("Keyboard status: {:#02x}", keyboard_status); 305 return Crash::Failure::DidNotCrash; 306 }).run(run_type); 307 } 308#endif 309 310 if (do_pledge_violation || do_all_crash_types) { 311 any_failures |= !Crash("Violate pledge()'d promises", [] { 312 if (pledge("", nullptr) < 0) { 313 perror("pledge"); 314 return Crash::Failure::DidNotCrash; 315 } 316 outln("Didn't pledge 'stdio', this should fail!"); 317 return Crash::Failure::DidNotCrash; 318 }).run(run_type); 319 } 320 321 if (do_failing_assertion || do_all_crash_types) { 322 any_failures |= !Crash("Perform a failing assertion", [] { 323 VERIFY(1 == 2); 324 return Crash::Failure::DidNotCrash; 325 }).run(run_type); 326 } 327 328 if (do_deref_null_refptr || do_all_crash_types) { 329 any_failures |= !Crash("Dereference a null RefPtr", [] { 330 RefPtr<Core::Object> p; 331 *p; 332 return Crash::Failure::DidNotCrash; 333 }).run(run_type); 334 } 335 336 return any_failures; 337}