2020-01-18 05:38:21 -03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2020-03-06 18:41:12 -03:00
* Copyright ( c ) 2019 - 2020 , Shannon Booth < shannon . ml . booth @ gmail . com >
2020-01-18 05:38:21 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 05:38:21 -03:00
*/
2021-05-15 07:34:40 -03:00
# include <AK/Assertions.h>
2019-12-29 23:07:57 -03:00
# include <AK/Function.h>
2019-09-06 10:34:26 -03:00
# include <AK/String.h>
2020-05-16 07:00:04 -03:00
# include <Kernel/IO.h>
2020-03-06 18:41:12 -03:00
# include <LibCore/ArgsParser.h>
2021-06-06 12:40:48 -03:00
# include <LibCore/Object.h>
2021-05-07 07:43:41 -03:00
# include <LibTest/CrashTest.h>
2019-05-25 21:21:31 -03:00
# include <stdio.h>
# include <stdlib.h>
2019-08-12 14:33:24 -03:00
# include <sys/mman.h>
2019-12-29 23:07:57 -03:00
# include <sys/wait.h>
2021-02-05 08:16:30 -03:00
# include <syscall.h>
2021-03-12 13:29:37 -03:00
# include <unistd.h>
2019-12-29 23:07:57 -03:00
2021-05-07 07:43:41 -03:00
using Test : : Crash ;
2019-12-29 23:07:57 -03:00
2021-07-06 01:27:27 -03:00
# ifdef __clang__
# pragma clang optimize off
# else
# pragma GCC optimize("O0")
# endif
2019-12-29 23:07:57 -03:00
2019-05-25 21:21:31 -03:00
int main ( int argc , char * * argv )
{
2020-03-06 18:41:12 -03:00
bool do_all_crash_types = false ;
bool do_segmentation_violation = false ;
bool do_division_by_zero = false ;
bool do_illegal_instruction = false ;
bool do_abort = false ;
bool do_write_to_uninitialized_malloc_memory = false ;
bool do_write_to_freed_memory = false ;
bool do_write_to_read_only_memory = false ;
bool do_read_from_uninitialized_malloc_memory = false ;
bool do_read_from_freed_memory = false ;
bool do_invalid_stack_pointer_on_syscall = false ;
2020-09-18 04:49:51 -03:00
bool do_invalid_stack_pointer_on_page_fault = false ;
2020-03-06 18:41:12 -03:00
bool do_syscall_from_writeable_memory = false ;
2021-03-12 18:18:45 -03:00
bool do_legitimate_syscall = false ;
2020-03-06 18:41:12 -03:00
bool do_execute_non_executable_memory = false ;
bool do_trigger_user_mode_instruction_prevention = false ;
bool do_use_io_instruction = false ;
bool do_read_cpu_counter = false ;
2021-01-25 18:43:54 -03:00
bool do_pledge_violation = false ;
2021-01-25 18:44:36 -03:00
bool do_failing_assertion = false ;
2021-06-06 12:40:48 -03:00
bool do_deref_null_refptr = false ;
2020-03-06 18:41:12 -03:00
auto args_parser = Core : : ArgsParser ( ) ;
2020-12-05 12:22:58 -03:00
args_parser . set_general_help (
" Exercise error-handling paths of the execution environment "
" (i.e., Kernel or UE) by crashing in many different ways. " ) ;
2021-09-15 18:38:21 -03:00
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 ' ) ;
2020-03-06 18:41:12 -03:00
args_parser . add_option ( do_segmentation_violation , " Perform a segmentation violation by dereferencing an invalid pointer " , nullptr , ' s ' ) ;
args_parser . add_option ( do_division_by_zero , " Perform a division by zero " , nullptr , ' d ' ) ;
args_parser . add_option ( do_illegal_instruction , " Execute an illegal CPU instruction " , nullptr , ' i ' ) ;
args_parser . add_option ( do_abort , " Call `abort()` " , nullptr , ' a ' ) ;
args_parser . add_option ( do_read_from_uninitialized_malloc_memory , " Read a pointer from uninitialized malloc memory, then read from it " , nullptr , ' m ' ) ;
args_parser . add_option ( do_read_from_freed_memory , " Read a pointer from memory freed using `free()`, then read from it " , nullptr , ' f ' ) ;
args_parser . add_option ( do_write_to_uninitialized_malloc_memory , " Read a pointer from uninitialized malloc memory, then write to it " , nullptr , ' M ' ) ;
args_parser . add_option ( do_write_to_freed_memory , " Read a pointer from memory freed using `free()`, then write to it " , nullptr , ' F ' ) ;
args_parser . add_option ( do_write_to_read_only_memory , " Write to read-only memory " , nullptr , ' r ' ) ;
args_parser . add_option ( do_invalid_stack_pointer_on_syscall , " Make a syscall while using an invalid stack pointer " , nullptr , ' T ' ) ;
args_parser . add_option ( do_invalid_stack_pointer_on_page_fault , " Trigger a page fault while using an invalid stack pointer " , nullptr , ' t ' ) ;
args_parser . add_option ( do_syscall_from_writeable_memory , " Make a syscall from writeable memory " , nullptr , ' S ' ) ;
2021-03-12 18:18:45 -03:00
args_parser . add_option ( do_legitimate_syscall , " Make a syscall from legitimate memory (but outside msyscall) " , nullptr , ' y ' ) ;
2020-03-06 18:41:12 -03:00
args_parser . add_option ( do_execute_non_executable_memory , " Attempt to execute non-executable memory (not mapped with PROT_EXEC) " , nullptr , ' X ' ) ;
2021-09-15 18:38:21 -03:00
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 ' ) ;
2020-03-06 18:41:12 -03:00
args_parser . add_option ( do_use_io_instruction , " Use an x86 I/O instruction in userspace " , nullptr , ' I ' ) ;
args_parser . add_option ( do_read_cpu_counter , " Read the x86 TSC (Time Stamp Counter) directly " , nullptr , ' c ' ) ;
2021-01-25 18:43:54 -03:00
args_parser . add_option ( do_pledge_violation , " Violate pledge()'d promises " , nullptr , ' p ' ) ;
2021-01-25 18:44:36 -03:00
args_parser . add_option ( do_failing_assertion , " Perform a failing assertion " , nullptr , ' n ' ) ;
2021-06-06 12:40:48 -03:00
args_parser . add_option ( do_deref_null_refptr , " Dereference a null RefPtr " , nullptr , ' R ' ) ;
2020-03-06 18:41:12 -03:00
2021-09-15 16:51:40 -03:00
if ( argc = = 1 ) {
do_all_crash_types = true ;
} else if ( argc ! = 2 ) {
2020-03-06 18:41:12 -03:00
args_parser . print_usage ( stderr , argv [ 0 ] ) ;
exit ( 1 ) ;
}
args_parser . parse ( argc , argv ) ;
Crash : : RunType run_type = do_all_crash_types ? Crash : : RunType : : UsingChildProcess
: Crash : : RunType : : UsingCurrentProcess ;
2021-09-15 16:51:40 -03:00
bool any_failures = false ;
2020-03-06 18:41:12 -03:00
if ( do_segmentation_violation | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Segmentation violation " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
volatile int * crashme = nullptr ;
* crashme = 0xbeef ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-25 21:21:31 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_division_by_zero | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Division by zero " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
volatile int lala = 10 ;
volatile int zero = 0 ;
2020-12-20 20:09:48 -03:00
[[maybe_unused]] volatile int test = lala / zero ;
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-25 21:21:31 -03:00
}
2020-09-18 04:49:51 -03:00
if ( do_illegal_instruction | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Illegal instruction " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
asm volatile ( " ud2 " ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-25 21:21:31 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_abort | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Abort " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
abort ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 15:52:12 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_read_from_uninitialized_malloc_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Read from uninitialized malloc memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
if ( ! uninitialized_memory )
return Crash : : Failure : : UnexpectedError ;
2019-06-19 15:52:12 -03:00
2020-12-20 20:09:48 -03:00
[[maybe_unused]] volatile auto x = uninitialized_memory [ 0 ] [ 0 ] ;
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 15:52:12 -03:00
}
2021-03-10 16:33:01 -03:00
if ( do_read_from_freed_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Read from freed memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
2019-12-30 22:41:08 -03:00
if ( ! uninitialized_memory )
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : UnexpectedError ;
free ( uninitialized_memory ) ;
2020-12-20 20:09:48 -03:00
[[maybe_unused]] volatile auto x = uninitialized_memory [ 4 ] [ 0 ] ;
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 15:52:12 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_write_to_uninitialized_malloc_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Write to uninitialized malloc memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
if ( ! uninitialized_memory )
return Crash : : Failure : : UnexpectedError ;
uninitialized_memory [ 4 ] [ 0 ] = 1 ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-08-12 14:33:24 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_write_to_freed_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Write to freed memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
if ( ! uninitialized_memory )
return Crash : : Failure : : UnexpectedError ;
2019-11-17 08:11:43 -03:00
2019-12-29 23:07:57 -03:00
free ( uninitialized_memory ) ;
uninitialized_memory [ 4 ] [ 0 ] = 1 ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-11-17 08:11:43 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_write_to_read_only_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Write to read only memory " , [ ] ( ) {
2021-03-10 16:33:01 -03:00
auto * ptr = ( u8 * ) mmap ( nullptr , 4096 , PROT_READ | PROT_WRITE , MAP_ANON | MAP_PRIVATE , 0 , 0 ) ;
2021-03-10 16:02:48 -03:00
if ( ptr = = MAP_FAILED )
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : UnexpectedError ;
* ptr = ' x ' ; // This should work fine.
int rc = mprotect ( ptr , 4096 , PROT_READ ) ;
if ( rc ! = 0 | | * ptr ! = ' x ' )
return Crash : : Failure : : UnexpectedError ;
* ptr = ' y ' ; // This should crash!
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-11-17 08:11:43 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_invalid_stack_pointer_on_syscall | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Invalid stack pointer on syscall " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
u8 * makeshift_stack = ( u8 * ) mmap ( nullptr , 0 , PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK , 0 , 0 ) ;
if ( ! makeshift_stack )
return Crash : : Failure : : UnexpectedError ;
u8 * makeshift_esp = makeshift_stack + 2048 ;
asm volatile ( " mov %%eax, %%esp " : : " a " ( makeshift_esp ) ) ;
getuid ( ) ;
2021-01-10 06:02:20 -03:00
dbgln ( " Survived syscall with MAP_STACK stack " ) ;
2019-12-29 23:07:57 -03:00
u8 * bad_stack = ( u8 * ) mmap ( nullptr , PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE , 0 , 0 ) ;
if ( ! bad_stack )
return Crash : : Failure : : UnexpectedError ;
u8 * bad_esp = bad_stack + 2048 ;
asm volatile ( " mov %%eax, %%esp " : : " a " ( bad_esp ) ) ;
getuid ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-11-29 12:15:30 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_invalid_stack_pointer_on_page_fault | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Invalid stack pointer on page fault " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
u8 * bad_stack = ( u8 * ) mmap ( nullptr , PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE , 0 , 0 ) ;
if ( ! bad_stack )
return Crash : : Failure : : UnexpectedError ;
u8 * bad_esp = bad_stack + 2048 ;
2021-07-13 10:50:19 -03:00
# if ARCH(I386)
2019-12-29 23:07:57 -03:00
asm volatile ( " mov %%eax, %%esp " : : " a " ( bad_esp ) ) ;
asm volatile ( " pushl $0 " ) ;
2021-05-01 19:00:52 -03:00
# else
asm volatile ( " movq %%rax, %%rsp " : : " a " ( bad_esp ) ) ;
asm volatile ( " pushq $0 " ) ;
# endif
2019-12-29 23:07:57 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-02 15:14:16 -03:00
}
2020-03-06 18:41:12 -03:00
if ( do_syscall_from_writeable_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Syscall from writable memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
u8 buffer [ ] = { 0xb8 , Syscall : : SC_getuid , 0 , 0 , 0 , 0xcd , 0x82 } ;
( ( void ( * ) ( ) ) buffer ) ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-02 15:14:16 -03:00
}
2021-03-12 18:18:45 -03:00
if ( do_legitimate_syscall | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Regular syscall from outside msyscall " , [ ] ( ) {
2021-03-12 18:18:45 -03:00
// Since 'crash' is dynamically linked, and DynamicLoader only allows LibSystem to make syscalls, this should kill us:
Syscall : : invoke ( Syscall : : SC_getuid ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2020-03-06 18:41:12 -03:00
if ( do_execute_non_executable_memory | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Execute non executable memory " , [ ] ( ) {
2019-12-29 23:07:57 -03:00
auto * ptr = ( u8 * ) mmap ( nullptr , PAGE_SIZE , PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE , 0 , 0 ) ;
if ( ptr = = MAP_FAILED )
return Crash : : Failure : : UnexpectedError ;
2019-12-25 07:52:21 -03:00
2019-12-29 23:07:57 -03:00
ptr [ 0 ] = 0xc3 ; // ret
typedef void * ( * CrashyFunctionPtr ) ( ) ;
( ( CrashyFunctionPtr ) ptr ) ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-25 07:52:21 -03:00
}
2021-09-15 18:38:21 -03:00
if ( do_trigger_user_mode_instruction_prevention ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Trigger x86 User Mode Instruction Prevention " , [ ] ( ) {
2020-01-01 09:02:32 -03:00
asm volatile ( " str %eax " ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2020-03-06 18:41:12 -03:00
if ( do_use_io_instruction | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Attempt to use an I/O instruction " , [ ] {
2020-01-01 13:26:25 -03:00
u8 keyboard_status = IO : : in8 ( 0x64 ) ;
2021-05-31 11:43:25 -03:00
outln ( " Keyboard status: {:#02x} " , keyboard_status ) ;
2020-01-01 13:26:25 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2020-03-06 18:41:12 -03:00
if ( do_read_cpu_counter | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Read the CPU timestamp counter " , [ ] {
2020-01-01 14:18:02 -03:00
asm volatile ( " rdtsc " ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-01-25 18:43:54 -03:00
if ( do_pledge_violation | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Violate pledge()'d promises " , [ ] {
2021-01-25 18:43:54 -03:00
if ( pledge ( " " , nullptr ) < 0 ) {
perror ( " pledge " ) ;
return Crash : : Failure : : DidNotCrash ;
}
2021-05-31 11:43:25 -03:00
outln ( " Didn't pledge 'stdio', this should fail! " ) ;
2021-01-25 18:43:54 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-01-25 18:44:36 -03:00
if ( do_failing_assertion | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Perform a failing assertion " , [ ] {
2021-02-23 16:42:32 -03:00
VERIFY ( 1 = = 2 ) ;
2021-01-25 18:44:36 -03:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-06-06 12:40:48 -03:00
if ( do_deref_null_refptr | | do_all_crash_types ) {
2021-09-15 16:51:40 -03:00
any_failures | = ! Crash ( " Dereference a null RefPtr " , [ ] {
2021-06-06 12:40:48 -03:00
RefPtr < Core : : Object > p ;
* p ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-09-15 16:51:40 -03:00
return any_failures ;
2019-05-25 21:21:31 -03:00
}