2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2020-03-07 10:41:12 +13:00
* Copyright ( c ) 2019 - 2020 , Shannon Booth < shannon . ml . booth @ gmail . com >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2021-05-15 12:34:40 +02:00
# include <AK/Assertions.h>
2019-12-30 15:07:57 +13:00
# include <AK/Function.h>
2019-09-06 15:34:26 +02:00
# include <AK/String.h>
2022-09-02 17:35:54 +03:00
# if ARCH(I386) || ARCH(X86_64)
# include <Kernel / Arch / x86 / IO.h>
# endif
2020-03-07 10:41:12 +13:00
# include <LibCore/ArgsParser.h>
2021-06-06 17:40:48 +02:00
# include <LibCore/Object.h>
2021-05-07 03:43:41 -07:00
# include <LibTest/CrashTest.h>
2019-05-26 02:21:31 +02:00
# include <stdio.h>
# include <stdlib.h>
2019-08-12 19:33:24 +02:00
# include <sys/mman.h>
2019-12-30 15:07:57 +13:00
# include <sys/wait.h>
2021-02-05 12:16:30 +01:00
# include <syscall.h>
2021-03-12 17:29:37 +01:00
# include <unistd.h>
2019-12-30 15:07:57 +13:00
2021-05-07 03:43:41 -07:00
using Test : : Crash ;
2019-12-30 15:07:57 +13:00
2022-10-04 15:04:13 -04:00
# if defined(AK_COMPILER_CLANG)
2021-07-06 06:27:27 +02:00
# pragma clang optimize off
# else
# pragma GCC optimize("O0")
# endif
2019-12-30 15:07:57 +13:00
2019-05-26 02:21:31 +02:00
int main ( int argc , char * * argv )
{
2020-03-07 10:41:12 +13: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 09:49:51 +02:00
bool do_invalid_stack_pointer_on_page_fault = false ;
2020-03-07 10:41:12 +13:00
bool do_syscall_from_writeable_memory = false ;
2021-03-12 22:18:45 +01:00
bool do_legitimate_syscall = false ;
2020-03-07 10:41:12 +13:00
bool do_execute_non_executable_memory = false ;
bool do_trigger_user_mode_instruction_prevention = false ;
2022-09-02 17:35:54 +03:00
# if ARCH(I386) || ARCH(X86_64)
2020-03-07 10:41:12 +13:00
bool do_use_io_instruction = false ;
2022-09-02 17:35:54 +03:00
# endif
2021-01-25 22:43:54 +01:00
bool do_pledge_violation = false ;
2021-01-25 22:44:36 +01:00
bool do_failing_assertion = false ;
2021-06-06 17:40:48 +02:00
bool do_deref_null_refptr = false ;
2020-03-07 10:41:12 +13:00
auto args_parser = Core : : ArgsParser ( ) ;
2020-12-05 16:22:58 +01: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 23:38:21 +02: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-07 10:41:12 +13: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 22:18:45 +01:00
args_parser . add_option ( do_legitimate_syscall , " Make a syscall from legitimate memory (but outside msyscall) " , nullptr , ' y ' ) ;
2020-03-07 10:41:12 +13: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 23:38:21 +02: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 ' ) ;
2022-09-02 17:35:54 +03:00
# if ARCH(I386) || ARCH(X86_64)
2020-03-07 10:41:12 +13:00
args_parser . add_option ( do_use_io_instruction , " Use an x86 I/O instruction in userspace " , nullptr , ' I ' ) ;
2022-09-02 17:35:54 +03:00
# endif
2021-01-25 22:43:54 +01:00
args_parser . add_option ( do_pledge_violation , " Violate pledge()'d promises " , nullptr , ' p ' ) ;
2021-01-25 22:44:36 +01:00
args_parser . add_option ( do_failing_assertion , " Perform a failing assertion " , nullptr , ' n ' ) ;
2021-06-06 17:40:48 +02:00
args_parser . add_option ( do_deref_null_refptr , " Dereference a null RefPtr " , nullptr , ' R ' ) ;
2020-03-07 10:41:12 +13:00
2021-09-15 21:51:40 +02:00
if ( argc = = 1 ) {
do_all_crash_types = true ;
} else if ( argc ! = 2 ) {
2020-03-07 10:41:12 +13: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 21:51:40 +02:00
bool any_failures = false ;
2020-03-07 10:41:12 +13:00
if ( do_segmentation_violation | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Segmentation violation " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
volatile int * crashme = nullptr ;
* crashme = 0xbeef ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-26 02:21:31 +02:00
}
2020-03-07 10:41:12 +13:00
if ( do_division_by_zero | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Division by zero " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
volatile int lala = 10 ;
volatile int zero = 0 ;
2020-12-20 16:09:48 -07:00
[[maybe_unused]] volatile int test = lala / zero ;
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-26 02:21:31 +02:00
}
2020-09-18 09:49:51 +02:00
if ( do_illegal_instruction | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Illegal instruction " , [ ] ( ) {
2022-10-12 22:07:37 +02:00
__builtin_trap ( ) ;
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-05-26 02:21:31 +02:00
}
2020-03-07 10:41:12 +13:00
if ( do_abort | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Abort " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
abort ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 20:52:12 +02:00
}
2020-03-07 10:41:12 +13:00
if ( do_read_from_uninitialized_malloc_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Read from uninitialized malloc memory " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
if ( ! uninitialized_memory )
return Crash : : Failure : : UnexpectedError ;
2019-06-19 20:52:12 +02:00
2020-12-20 16:09:48 -07:00
[[maybe_unused]] volatile auto x = uninitialized_memory [ 0 ] [ 0 ] ;
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 20:52:12 +02:00
}
2021-03-10 20:33:01 +01:00
if ( do_read_from_freed_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Read from freed memory " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
2019-12-31 14:41:08 +13:00
if ( ! uninitialized_memory )
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : UnexpectedError ;
free ( uninitialized_memory ) ;
2022-05-07 17:49:44 +02:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wuse-after-free"
2020-12-20 16:09:48 -07:00
[[maybe_unused]] volatile auto x = uninitialized_memory [ 4 ] [ 0 ] ;
2022-05-07 17:49:44 +02:00
# pragma GCC diagnostic pop
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-06-19 20:52:12 +02:00
}
2020-03-07 10:41:12 +13:00
if ( do_write_to_uninitialized_malloc_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Write to uninitialized malloc memory " , [ ] ( ) {
2019-12-30 15:07:57 +13: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 19:33:24 +02:00
}
2020-03-07 10:41:12 +13:00
if ( do_write_to_freed_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Write to freed memory " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
auto * uninitialized_memory = ( volatile u32 * * ) malloc ( 1024 ) ;
if ( ! uninitialized_memory )
return Crash : : Failure : : UnexpectedError ;
2019-11-17 12:11:43 +01:00
2022-05-07 17:49:44 +02:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wuse-after-free"
2019-12-30 15:07:57 +13:00
free ( uninitialized_memory ) ;
uninitialized_memory [ 4 ] [ 0 ] = 1 ;
2022-05-07 17:49:44 +02:00
# pragma GCC diagnostic pop
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-11-17 12:11:43 +01:00
}
2020-03-07 10:41:12 +13:00
if ( do_write_to_read_only_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Write to read only memory " , [ ] ( ) {
2021-03-10 20:33:01 +01:00
auto * ptr = ( u8 * ) mmap ( nullptr , 4096 , PROT_READ | PROT_WRITE , MAP_ANON | MAP_PRIVATE , 0 , 0 ) ;
2021-03-10 20:02:48 +01:00
if ( ptr = = MAP_FAILED )
2019-12-30 15:07:57 +13: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 12:11:43 +01:00
}
2020-03-07 10:41:12 +13:00
if ( do_invalid_stack_pointer_on_syscall | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Invalid stack pointer on syscall " , [ ] ( ) {
2019-12-30 15:07:57 +13: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 ;
2022-10-12 21:55:05 +02:00
# if ARCH(I386) || ARCH(X86_64)
2019-12-30 15:07:57 +13:00
asm volatile ( " mov %%eax, %%esp " : : " a " ( makeshift_esp ) ) ;
2022-10-12 21:55:05 +02:00
# elif ARCH(AARCH64)
( void ) makeshift_esp ;
TODO_AARCH64 ( ) ;
# else
# error Unknown architecture
# endif
2019-12-30 15:07:57 +13:00
getuid ( ) ;
2021-01-10 10:02:20 +01:00
dbgln ( " Survived syscall with MAP_STACK stack " ) ;
2019-12-30 15:07:57 +13: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 ;
2022-10-12 21:55:05 +02:00
# if ARCH(I386) || ARCH(X86_64)
2019-12-30 15:07:57 +13:00
asm volatile ( " mov %%eax, %%esp " : : " a " ( bad_esp ) ) ;
2022-10-12 21:55:05 +02:00
# elif ARCH(AARCH64)
( void ) bad_esp ;
TODO_AARCH64 ( ) ;
# else
# error Unknown architecture
# endif
2019-12-30 15:07:57 +13:00
getuid ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-11-29 16:15:30 +01:00
}
2020-03-07 10:41:12 +13:00
if ( do_invalid_stack_pointer_on_page_fault | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Invalid stack pointer on page fault " , [ ] ( ) {
2019-12-30 15:07:57 +13: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 15:50:19 +02:00
# if ARCH(I386)
2019-12-30 15:07:57 +13:00
asm volatile ( " mov %%eax, %%esp " : : " a " ( bad_esp ) ) ;
asm volatile ( " pushl $0 " ) ;
2022-07-22 20:48:24 +02:00
# elif ARCH(X86_64)
2021-05-02 00:00:52 +02:00
asm volatile ( " movq %%rax, %%rsp " : : " a " ( bad_esp ) ) ;
asm volatile ( " pushq $0 " ) ;
2022-10-12 21:55:05 +02:00
# elif ARCH(AARCH64)
( void ) bad_esp ;
TODO_AARCH64 ( ) ;
2022-07-22 20:48:24 +02:00
# else
# error Unknown architecture
2021-05-02 00:00:52 +02:00
# endif
2019-12-30 15:07:57 +13:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-02 19:14:16 +01:00
}
2020-03-07 10:41:12 +13:00
if ( do_syscall_from_writeable_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Syscall from writable memory " , [ ] ( ) {
2019-12-30 15:07:57 +13:00
u8 buffer [ ] = { 0xb8 , Syscall : : SC_getuid , 0 , 0 , 0 , 0xcd , 0x82 } ;
( ( void ( * ) ( ) ) buffer ) ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-02 19:14:16 +01:00
}
2021-03-12 22:18:45 +01:00
if ( do_legitimate_syscall | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Regular syscall from outside msyscall " , [ ] ( ) {
2021-03-12 22:18:45 +01: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-07 10:41:12 +13:00
if ( do_execute_non_executable_memory | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Execute non executable memory " , [ ] ( ) {
2019-12-30 15:07:57 +13: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 11:52:21 +01:00
2019-12-30 15:07:57 +13:00
ptr [ 0 ] = 0xc3 ; // ret
typedef void * ( * CrashyFunctionPtr ) ( ) ;
( ( CrashyFunctionPtr ) ptr ) ( ) ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
2019-12-25 11:52:21 +01:00
}
2021-09-15 23:38:21 +02:00
if ( do_trigger_user_mode_instruction_prevention ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Trigger x86 User Mode Instruction Prevention " , [ ] ( ) {
2022-10-12 21:55:05 +02:00
# if ARCH(I386) || ARCH(X86_64)
2020-01-01 13:02:32 +01:00
asm volatile ( " str %eax " ) ;
2022-10-12 21:55:05 +02:00
# elif ARCH(AARCH64)
TODO_AARCH64 ( ) ;
# else
# error Unknown architecture
# endif
2020-01-01 13:02:32 +01:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2022-09-02 17:35:54 +03:00
# if ARCH(I386) || ARCH(X86_64)
2020-03-07 10:41:12 +13:00
if ( do_use_io_instruction | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Attempt to use an I/O instruction " , [ ] {
2020-01-01 17:26:25 +01:00
u8 keyboard_status = IO : : in8 ( 0x64 ) ;
2021-05-31 15:43:25 +01:00
outln ( " Keyboard status: {:#02x} " , keyboard_status ) ;
2020-01-01 17:26:25 +01:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2022-09-02 17:35:54 +03:00
# endif
2020-01-01 17:26:25 +01:00
2021-01-25 22:43:54 +01:00
if ( do_pledge_violation | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Violate pledge()'d promises " , [ ] {
2021-01-25 22:43:54 +01:00
if ( pledge ( " " , nullptr ) < 0 ) {
perror ( " pledge " ) ;
return Crash : : Failure : : DidNotCrash ;
}
2021-05-31 15:43:25 +01:00
outln ( " Didn't pledge 'stdio', this should fail! " ) ;
2021-01-25 22:43:54 +01:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-01-25 22:44:36 +01:00
if ( do_failing_assertion | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Perform a failing assertion " , [ ] {
2021-02-23 20:42:32 +01:00
VERIFY ( 1 = = 2 ) ;
2021-01-25 22:44:36 +01:00
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-06-06 17:40:48 +02:00
if ( do_deref_null_refptr | | do_all_crash_types ) {
2021-09-15 21:51:40 +02:00
any_failures | = ! Crash ( " Dereference a null RefPtr " , [ ] {
2021-06-06 17:40:48 +02:00
RefPtr < Core : : Object > p ;
* p ;
return Crash : : Failure : : DidNotCrash ;
} ) . run ( run_type ) ;
}
2021-09-15 21:51:40 +02:00
return any_failures ;
2019-05-26 02:21:31 +02:00
}