Serenity Operating System
at hosted 359 lines 15 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 * 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 28#include <AK/Function.h> 29#include <AK/String.h> 30#include <Kernel/Syscall.h> 31#include <LibBareMetal/IO.h> 32#include <LibCore/ArgsParser.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <sys/mman.h> 36#include <sys/wait.h> 37 38#pragma GCC optimize("O0") 39 40class Crash { 41public: 42 enum class RunType { 43 UsingChildProcess, 44 UsingCurrentProcess, 45 }; 46 47 enum class Failure { 48 DidNotCrash, 49 UnexpectedError, 50 }; 51 52 Crash(String test_type, Function<Crash::Failure()> crash_function) 53 : m_type(test_type) 54 , m_crash_function(move(crash_function)) 55 { 56 } 57 58 void run(RunType run_type) 59 { 60 printf("\x1B[33mTesting\x1B[0m: \"%s\"\n", m_type.characters()); 61 62 auto run_crash_and_print_if_error = [this]() { 63 auto failure = m_crash_function(); 64 65 // If we got here something went wrong 66 printf("\x1B[31mFAIL\x1B[0m: "); 67 switch (failure) { 68 case Failure::DidNotCrash: 69 printf("Did not crash!\n"); 70 break; 71 case Failure::UnexpectedError: 72 printf("Unexpected error!\n"); 73 break; 74 default: 75 ASSERT_NOT_REACHED(); 76 } 77 }; 78 79 if (run_type == RunType::UsingCurrentProcess) { 80 run_crash_and_print_if_error(); 81 } else { 82 83 // Run the test in a child process so that we do not crash the crash program :^) 84 pid_t pid = fork(); 85 if (pid < 0) { 86 perror("fork"); 87 ASSERT_NOT_REACHED(); 88 } else if (pid == 0) { 89 run_crash_and_print_if_error(); 90 exit(0); 91 } 92 93 int status; 94 waitpid(pid, &status, 0); 95 if (WIFSIGNALED(status)) 96 printf("\x1B[32mPASS\x1B[0m: Terminated with signal %d\n", WTERMSIG(status)); 97 } 98 } 99 100private: 101 String m_type; 102 Function<Crash::Failure()> m_crash_function; 103}; 104 105int main(int argc, char** argv) 106{ 107 bool do_all_crash_types = false; 108 bool do_segmentation_violation = false; 109 bool do_division_by_zero = false; 110 bool do_illegal_instruction = false; 111 bool do_abort = false; 112 bool do_write_to_uninitialized_malloc_memory = false; 113 bool do_write_to_freed_memory = false; 114 bool do_write_to_read_only_memory = false; 115 bool do_read_from_uninitialized_malloc_memory = false; 116 bool do_read_from_freed_memory = false; 117 bool do_invalid_stack_pointer_on_syscall = false; 118 bool do_invalid_stack_pointer_on_page_fault = false; 119 bool do_syscall_from_writeable_memory = false; 120 bool do_write_to_freed_memory_still_cached_by_malloc = false; 121 bool do_read_from_freed_memory_still_cached_by_malloc = false; 122 bool do_execute_non_executable_memory = false; 123 bool do_trigger_user_mode_instruction_prevention = false; 124 bool do_use_io_instruction = false; 125 bool do_read_cpu_counter = false; 126 127 auto args_parser = Core::ArgsParser(); 128 args_parser.add_option(do_all_crash_types, "Test that all of the following crash types crash as expected", nullptr, 'A'); 129 args_parser.add_option(do_segmentation_violation, "Perform a segmentation violation by dereferencing an invalid pointer", nullptr, 's'); 130 args_parser.add_option(do_division_by_zero, "Perform a division by zero", nullptr, 'd'); 131 args_parser.add_option(do_illegal_instruction, "Execute an illegal CPU instruction", nullptr, 'i'); 132 args_parser.add_option(do_abort, "Call `abort()`", nullptr, 'a'); 133 args_parser.add_option(do_read_from_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then read from it", nullptr, 'm'); 134 args_parser.add_option(do_read_from_freed_memory, "Read a pointer from memory freed using `free()`, then read from it", nullptr, 'f'); 135 args_parser.add_option(do_write_to_uninitialized_malloc_memory, "Read a pointer from uninitialized malloc memory, then write to it", nullptr, 'M'); 136 args_parser.add_option(do_write_to_freed_memory, "Read a pointer from memory freed using `free()`, then write to it", nullptr, 'F'); 137 args_parser.add_option(do_write_to_read_only_memory, "Write to read-only memory", nullptr, 'r'); 138 args_parser.add_option(do_invalid_stack_pointer_on_syscall, "Make a syscall while using an invalid stack pointer", nullptr, 'T'); 139 args_parser.add_option(do_invalid_stack_pointer_on_page_fault, "Trigger a page fault while using an invalid stack pointer", nullptr, 't'); 140 args_parser.add_option(do_syscall_from_writeable_memory, "Make a syscall from writeable memory", nullptr, 'S'); 141 args_parser.add_option(do_write_to_freed_memory_still_cached_by_malloc, "Read from recently freed memory (tests an opportunistic malloc guard)", nullptr, 'x'); 142 args_parser.add_option(do_read_from_freed_memory_still_cached_by_malloc, "Write to recently free memory (tests an opportunistic malloc guard)", nullptr, 'y'); 143 args_parser.add_option(do_execute_non_executable_memory, "Attempt to execute non-executable memory (not mapped with PROT_EXEC)", nullptr, 'X'); 144 args_parser.add_option(do_trigger_user_mode_instruction_prevention, "Attempt to trigger an x86 User Mode Instruction Prevention fault", nullptr, 'U'); 145 args_parser.add_option(do_use_io_instruction, "Use an x86 I/O instruction in userspace", nullptr, 'I'); 146 args_parser.add_option(do_read_cpu_counter, "Read the x86 TSC (Time Stamp Counter) directly", nullptr, 'c'); 147 148 if (argc != 2) { 149 args_parser.print_usage(stderr, argv[0]); 150 exit(1); 151 } 152 153 args_parser.parse(argc, argv); 154 155 Crash::RunType run_type = do_all_crash_types ? Crash::RunType::UsingChildProcess 156 : Crash::RunType::UsingCurrentProcess; 157 158 if (do_segmentation_violation || do_all_crash_types) { 159 Crash("Segmentation violation", []() { 160 volatile int* crashme = nullptr; 161 *crashme = 0xbeef; 162 return Crash::Failure::DidNotCrash; 163 }).run(run_type); 164 } 165 166 if (do_division_by_zero || do_all_crash_types) { 167 Crash("Division by zero", []() { 168 volatile int lala = 10; 169 volatile int zero = 0; 170 volatile int test = lala / zero; 171 UNUSED_PARAM(test); 172 return Crash::Failure::DidNotCrash; 173 }).run(run_type); 174 } 175 176 if (do_illegal_instruction|| do_all_crash_types) { 177 Crash("Illegal instruction", []() { 178 asm volatile("ud2"); 179 return Crash::Failure::DidNotCrash; 180 }).run(run_type); 181 } 182 183 if (do_abort || do_all_crash_types) { 184 Crash("Abort", []() { 185 abort(); 186 return Crash::Failure::DidNotCrash; 187 }).run(run_type); 188 } 189 190 if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) { 191 Crash("Read from uninitialized malloc memory", []() { 192 auto* uninitialized_memory = (volatile u32**)malloc(1024); 193 if (!uninitialized_memory) 194 return Crash::Failure::UnexpectedError; 195 196 volatile auto x = uninitialized_memory[0][0]; 197 UNUSED_PARAM(x); 198 return Crash::Failure::DidNotCrash; 199 }).run(run_type); 200 } 201 202 if (do_read_from_uninitialized_malloc_memory || do_all_crash_types) { 203 Crash("Read from freed memory", []() { 204 auto* uninitialized_memory = (volatile u32**)malloc(1024); 205 if (!uninitialized_memory) 206 return Crash::Failure::UnexpectedError; 207 208 free(uninitialized_memory); 209 volatile auto x = uninitialized_memory[4][0]; 210 UNUSED_PARAM(x); 211 return Crash::Failure::DidNotCrash; 212 }).run(run_type); 213 } 214 215 if (do_write_to_uninitialized_malloc_memory || do_all_crash_types) { 216 Crash("Write to uninitialized malloc memory", []() { 217 auto* uninitialized_memory = (volatile u32**)malloc(1024); 218 if (!uninitialized_memory) 219 return Crash::Failure::UnexpectedError; 220 221 uninitialized_memory[4][0] = 1; 222 return Crash::Failure::DidNotCrash; 223 }).run(run_type); 224 } 225 226 if (do_write_to_freed_memory || do_all_crash_types) { 227 Crash("Write to freed memory", []() { 228 auto* uninitialized_memory = (volatile u32**)malloc(1024); 229 if (!uninitialized_memory) 230 return Crash::Failure::UnexpectedError; 231 232 free(uninitialized_memory); 233 uninitialized_memory[4][0] = 1; 234 return Crash::Failure::DidNotCrash; 235 }).run(run_type); 236 } 237 238 if (do_write_to_read_only_memory || do_all_crash_types) { 239 Crash("Write to read only memory", []() { 240 auto* ptr = (u8*)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0); 241 if (ptr != MAP_FAILED) 242 return Crash::Failure::UnexpectedError; 243 244 *ptr = 'x'; // This should work fine. 245 int rc = mprotect(ptr, 4096, PROT_READ); 246 if (rc != 0 || *ptr != 'x') 247 return Crash::Failure::UnexpectedError; 248 249 *ptr = 'y'; // This should crash! 250 return Crash::Failure::DidNotCrash; 251 }).run(run_type); 252 } 253 254 if (do_invalid_stack_pointer_on_syscall || do_all_crash_types) { 255 Crash("Invalid stack pointer on syscall", []() { 256 u8* makeshift_stack = (u8*)mmap(nullptr, 0, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK, 0, 0); 257 if (!makeshift_stack) 258 return Crash::Failure::UnexpectedError; 259 260 u8* makeshift_esp = makeshift_stack + 2048; 261 asm volatile("mov %%eax, %%esp" ::"a"(makeshift_esp)); 262 getuid(); 263 dbgprintf("Survived syscall with MAP_STACK stack\n"); 264 265 u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 266 if (!bad_stack) 267 return Crash::Failure::UnexpectedError; 268 269 u8* bad_esp = bad_stack + 2048; 270 asm volatile("mov %%eax, %%esp" ::"a"(bad_esp)); 271 getuid(); 272 return Crash::Failure::DidNotCrash; 273 }).run(run_type); 274 } 275 276 if (do_invalid_stack_pointer_on_page_fault || do_all_crash_types) { 277 Crash("Invalid stack pointer on page fault", []() { 278 u8* bad_stack = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 279 if (!bad_stack) 280 return Crash::Failure::UnexpectedError; 281 282 u8* bad_esp = bad_stack + 2048; 283 asm volatile("mov %%eax, %%esp" ::"a"(bad_esp)); 284 asm volatile("pushl $0"); 285 return Crash::Failure::DidNotCrash; 286 }).run(run_type); 287 } 288 289 if (do_syscall_from_writeable_memory || do_all_crash_types) { 290 Crash("Syscall from writable memory", []() { 291 u8 buffer[] = { 0xb8, Syscall::SC_getuid, 0, 0, 0, 0xcd, 0x82 }; 292 ((void (*)())buffer)(); 293 return Crash::Failure::DidNotCrash; 294 }).run(run_type); 295 } 296 297 if (do_read_from_freed_memory_still_cached_by_malloc || do_all_crash_types) { 298 Crash("Read from memory still cached by malloc", []() { 299 auto* ptr = (u8*)malloc(1024); 300 if (!ptr) 301 return Crash::Failure::UnexpectedError; 302 303 free(ptr); 304 dbgprintf("ptr = %p\n", ptr); 305 volatile auto foo = *ptr; 306 UNUSED_PARAM(foo); 307 return Crash::Failure::DidNotCrash; 308 }).run(run_type); 309 } 310 311 if (do_write_to_freed_memory_still_cached_by_malloc || do_all_crash_types) { 312 Crash("Write to freed memory still cached by malloc", []() { 313 auto* ptr = (u8*)malloc(1024); 314 if (!ptr) 315 return Crash::Failure::UnexpectedError; 316 free(ptr); 317 dbgprintf("ptr = %p\n", ptr); 318 *ptr = 'x'; 319 return Crash::Failure::DidNotCrash; 320 }).run(run_type); 321 } 322 323 if (do_execute_non_executable_memory || do_all_crash_types) { 324 Crash("Execute non executable memory", []() { 325 auto* ptr = (u8*)mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 326 if (ptr == MAP_FAILED) 327 return Crash::Failure::UnexpectedError; 328 329 ptr[0] = 0xc3; // ret 330 typedef void* (*CrashyFunctionPtr)(); 331 ((CrashyFunctionPtr)ptr)(); 332 return Crash::Failure::DidNotCrash; 333 }).run(run_type); 334 } 335 336 if (do_trigger_user_mode_instruction_prevention || do_all_crash_types) { 337 Crash("Trigger x86 User Mode Instruction Prevention", []() { 338 asm volatile("str %eax"); 339 return Crash::Failure::DidNotCrash; 340 }).run(run_type); 341 } 342 343 if (do_use_io_instruction || do_all_crash_types) { 344 Crash("Attempt to use an I/O instruction", [] { 345 u8 keyboard_status = IO::in8(0x64); 346 printf("Keyboard status: %#02x\n", keyboard_status); 347 return Crash::Failure::DidNotCrash; 348 }).run(run_type); 349 } 350 351 if (do_read_cpu_counter || do_all_crash_types) { 352 Crash("Read the CPU timestamp counter", [] { 353 asm volatile("rdtsc"); 354 return Crash::Failure::DidNotCrash; 355 }).run(run_type); 356 } 357 358 return 0; 359}