2020-07-30 23:38:15 +02:00
/*
2021-01-11 09:52:18 +01:00
* Copyright ( c ) 2018 - 2021 , Andreas Kling < kling @ serenityos . org >
2022-02-09 11:33:39 -07:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2020-07-30 23:38:15 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-07-30 23:38:15 +02:00
*/
# include <AK/ScopeGuard.h>
2020-10-15 20:46:52 +02:00
# include <AK/TemporaryChange.h>
2021-01-25 16:07:10 +01:00
# include <Kernel/Debug.h>
2020-07-30 23:38:15 +02:00
# include <Kernel/FileSystem/Custody.h>
2021-09-07 13:39:11 +02:00
# include <Kernel/FileSystem/OpenFileDescription.h>
2022-08-19 18:16:06 +03:00
# include <Kernel/FileSystem/VirtualFileSystem.h>
2021-08-06 10:45:34 +02:00
# include <Kernel/Memory/MemoryManager.h>
# include <Kernel/Memory/Region.h>
# include <Kernel/Memory/SharedInodeVMObject.h>
2021-06-23 21:54:41 +02:00
# include <Kernel/Panic.h>
2021-05-07 01:38:50 -07:00
# include <Kernel/PerformanceManager.h>
2020-07-30 23:38:15 +02:00
# include <Kernel/Process.h>
# include <Kernel/Random.h>
2022-01-29 13:08:37 +01:00
# include <Kernel/Scheduler.h>
2020-07-30 23:38:15 +02:00
# include <Kernel/Time/TimeManagement.h>
# include <LibC/limits.h>
2020-12-25 15:23:35 +01:00
# include <LibELF/AuxiliaryVector.h>
2020-12-25 01:22:55 +01:00
# include <LibELF/Image.h>
2020-07-30 23:38:15 +02:00
# include <LibELF/Validation.h>
namespace Kernel {
2021-08-06 13:49:36 +02:00
extern Memory : : Region * g_signal_trampoline_region ;
2021-02-14 00:53:53 +01:00
2021-02-08 15:45:40 +01:00
struct LoadResult {
2021-08-06 13:57:39 +02:00
OwnPtr < Memory : : AddressSpace > space ;
2021-02-08 15:45:40 +01:00
FlatPtr load_base { 0 } ;
FlatPtr entry_eip { 0 } ;
size_t size { 0 } ;
2022-08-19 20:53:40 +02:00
LockWeakPtr < Memory : : Region > tls_region ;
2021-02-08 15:45:40 +01:00
size_t tls_size { 0 } ;
size_t tls_alignment { 0 } ;
2022-08-19 20:53:40 +02:00
LockWeakPtr < Memory : : Region > stack_region ;
2021-02-08 15:45:40 +01:00
} ;
2022-01-25 15:44:07 +02:00
static constexpr size_t auxiliary_vector_size = 15 ;
static Array < ELF : : AuxiliaryValue , auxiliary_vector_size > generate_auxiliary_vector ( FlatPtr load_base , FlatPtr entry_eip , UserID uid , UserID euid , GroupID gid , GroupID egid , StringView executable_path , Optional < Process : : ScopedDescriptionAllocation > const & main_program_fd_allocation ) ;
2020-12-25 15:23:35 +01:00
2021-09-09 11:36:40 +02:00
static bool validate_stack_size ( NonnullOwnPtrVector < KString > const & arguments , NonnullOwnPtrVector < KString > & environment )
2020-07-30 23:38:15 +02:00
{
2021-01-17 18:26:12 +01:00
size_t total_arguments_size = 0 ;
size_t total_environment_size = 0 ;
2021-12-18 18:37:21 +01:00
for ( auto const & a : arguments )
2021-01-17 18:26:12 +01:00
total_arguments_size + = a . length ( ) + 1 ;
2021-12-18 18:37:21 +01:00
for ( auto const & e : environment )
2021-01-17 18:26:12 +01:00
total_environment_size + = e . length ( ) + 1 ;
total_arguments_size + = sizeof ( char * ) * ( arguments . size ( ) + 1 ) ;
total_environment_size + = sizeof ( char * ) * ( environment . size ( ) + 1 ) ;
2022-02-13 12:07:51 -07:00
if ( total_arguments_size > Process : : max_arguments_size )
2021-01-17 18:26:12 +01:00
return false ;
2020-07-30 23:38:15 +02:00
2022-02-13 12:07:51 -07:00
if ( total_environment_size > Process : : max_environment_size )
2021-01-17 18:26:12 +01:00
return false ;
2020-07-30 23:38:15 +02:00
2020-10-10 12:13:21 +03:00
// FIXME: This doesn't account for the size of the auxiliary vector
2021-01-17 18:26:12 +01:00
return true ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
2021-11-08 00:51:39 +01:00
static ErrorOr < FlatPtr > make_userspace_context_for_main_thread ( [[maybe_unused]] ThreadRegisters & regs , Memory : : Region & region , NonnullOwnPtrVector < KString > const & arguments ,
2022-01-25 15:44:07 +02:00
NonnullOwnPtrVector < KString > const & environment , Array < ELF : : AuxiliaryValue , auxiliary_vector_size > auxiliary_values )
2020-12-25 16:20:26 +01:00
{
2021-06-28 17:42:29 +02:00
FlatPtr new_sp = region . range ( ) . end ( ) . get ( ) ;
2021-02-14 11:47:25 +01:00
// Add some bits of randomness to the user stack pointer.
2021-06-28 17:42:29 +02:00
new_sp - = round_up_to_power_of_two ( get_fast_random < u32 > ( ) % 4096 , 16 ) ;
2020-12-25 16:20:26 +01:00
2021-06-28 17:42:29 +02:00
auto push_on_new_stack = [ & new_sp ] ( FlatPtr value ) {
new_sp - = sizeof ( FlatPtr ) ;
Userspace < FlatPtr * > stack_ptr = new_sp ;
2021-09-05 17:38:37 +02:00
auto result = copy_to_user ( stack_ptr , & value ) ;
2021-11-08 00:51:39 +01:00
VERIFY ( ! result . is_error ( ) ) ;
2020-12-25 16:20:26 +01:00
} ;
2021-06-28 17:42:29 +02:00
auto push_aux_value_on_new_stack = [ & new_sp ] ( auxv_t value ) {
new_sp - = sizeof ( auxv_t ) ;
Userspace < auxv_t * > stack_ptr = new_sp ;
2021-09-05 17:38:37 +02:00
auto result = copy_to_user ( stack_ptr , & value ) ;
2021-11-08 00:51:39 +01:00
VERIFY ( ! result . is_error ( ) ) ;
2020-12-25 16:20:26 +01:00
} ;
2021-09-07 13:19:40 +02:00
auto push_string_on_new_stack = [ & new_sp ] ( StringView string ) {
2021-06-28 17:42:29 +02:00
new_sp - = round_up_to_power_of_two ( string . length ( ) + 1 , sizeof ( FlatPtr ) ) ;
Userspace < FlatPtr * > stack_ptr = new_sp ;
2021-09-07 13:19:40 +02:00
auto result = copy_to_user ( stack_ptr , string . characters_without_null_termination ( ) , string . length ( ) + 1 ) ;
2021-11-08 00:51:39 +01:00
VERIFY ( ! result . is_error ( ) ) ;
2020-12-25 16:20:26 +01:00
} ;
Vector < FlatPtr > argv_entries ;
2021-12-18 18:37:21 +01:00
for ( auto const & argument : arguments ) {
2021-09-09 11:36:40 +02:00
push_string_on_new_stack ( argument . view ( ) ) ;
2021-11-10 11:55:37 +01:00
TRY ( argv_entries . try_append ( new_sp ) ) ;
2020-12-25 16:20:26 +01:00
}
Vector < FlatPtr > env_entries ;
2021-12-18 18:37:21 +01:00
for ( auto const & variable : environment ) {
2021-09-09 11:36:40 +02:00
push_string_on_new_stack ( variable . view ( ) ) ;
2021-11-10 11:55:37 +01:00
TRY ( env_entries . try_append ( new_sp ) ) ;
2020-12-25 16:20:26 +01:00
}
for ( auto & value : auxiliary_values ) {
if ( ! value . optional_string . is_empty ( ) ) {
push_string_on_new_stack ( value . optional_string ) ;
2021-06-28 17:42:29 +02:00
value . auxv . a_un . a_ptr = ( void * ) new_sp ;
2020-12-25 16:20:26 +01:00
}
2022-01-13 01:17:15 +02:00
if ( value . auxv . a_type = = ELF : : AuxiliaryValue : : Random ) {
u8 random_bytes [ 16 ] { } ;
get_fast_random_bytes ( { random_bytes , sizeof ( random_bytes ) } ) ;
push_string_on_new_stack ( { random_bytes , sizeof ( random_bytes ) } ) ;
value . auxv . a_un . a_ptr = ( void * ) new_sp ;
}
2020-12-25 16:20:26 +01:00
}
for ( ssize_t i = auxiliary_values . size ( ) - 1 ; i > = 0 ; - - i ) {
auto & value = auxiliary_values [ i ] ;
push_aux_value_on_new_stack ( value . auxv ) ;
}
push_on_new_stack ( 0 ) ;
for ( ssize_t i = env_entries . size ( ) - 1 ; i > = 0 ; - - i )
push_on_new_stack ( env_entries [ i ] ) ;
2021-06-28 17:42:29 +02:00
FlatPtr envp = new_sp ;
2020-12-25 16:20:26 +01:00
push_on_new_stack ( 0 ) ;
for ( ssize_t i = argv_entries . size ( ) - 1 ; i > = 0 ; - - i )
push_on_new_stack ( argv_entries [ i ] ) ;
2021-06-28 17:42:29 +02:00
FlatPtr argv = new_sp ;
2020-12-25 16:20:26 +01:00
// NOTE: The stack needs to be 16-byte aligned.
2021-06-28 17:42:29 +02:00
new_sp - = new_sp % 16 ;
# if ARCH(I386)
2021-05-02 03:22:00 +10:00
// GCC assumes that the return address has been pushed to the stack when it enters the function,
// so we need to reserve an extra pointer's worth of bytes below this to make GCC's stack alignment
// calculations work
2021-06-28 17:42:29 +02:00
new_sp - = sizeof ( void * ) ;
2020-12-25 16:20:26 +01:00
2021-06-28 17:42:29 +02:00
push_on_new_stack ( envp ) ;
push_on_new_stack ( argv ) ;
push_on_new_stack ( argv_entries . size ( ) ) ;
2022-07-22 20:48:24 +02:00
# elif ARCH(X86_64)
2021-06-29 11:02:43 +02:00
regs . rdi = argv_entries . size ( ) ;
regs . rsi = argv ;
2021-06-28 17:42:29 +02:00
regs . rdx = envp ;
2022-07-22 20:48:24 +02:00
# else
# error Unknown architecture
2021-06-28 17:42:29 +02:00
# endif
2020-12-25 16:20:26 +01:00
2021-07-09 00:58:43 +02:00
VERIFY ( new_sp % 16 = = 0 ) ;
2021-05-02 03:22:00 +10:00
2021-07-09 00:58:43 +02:00
// FIXME: The way we're setting up the stack and passing arguments to the entry point isn't ABI-compliant
2021-06-28 17:42:29 +02:00
return new_sp ;
2020-12-25 16:20:26 +01:00
}
2021-08-06 23:42:53 +02:00
struct RequiredLoadRange {
2021-02-12 16:30:29 +01:00
FlatPtr start { 0 } ;
FlatPtr end { 0 } ;
} ;
2021-11-08 00:51:39 +01:00
static ErrorOr < RequiredLoadRange > get_required_load_range ( OpenFileDescription & program_description )
2021-02-12 16:30:29 +01:00
{
auto & inode = * ( program_description . inode ( ) ) ;
2021-09-06 12:58:03 +02:00
auto vmobject = TRY ( Memory : : SharedInodeVMObject : : try_create_with_inode ( inode ) ) ;
2021-02-12 16:30:29 +01:00
size_t executable_size = inode . size ( ) ;
2021-12-24 11:22:11 -03:00
size_t rounded_executable_size = TRY ( Memory : : page_round_up ( executable_size ) ) ;
2022-07-11 17:32:29 +00:00
auto region = TRY ( MM . allocate_kernel_region_with_vmobject ( * vmobject , rounded_executable_size , " ELF memory range calculation " sv , Memory : : Region : : Access : : Read ) ) ;
2021-02-12 16:30:29 +01:00
auto elf_image = ELF : : Image ( region - > vaddr ( ) . as_ptr ( ) , executable_size ) ;
if ( ! elf_image . is_valid ( ) ) {
return EINVAL ;
}
2021-08-06 23:42:53 +02:00
RequiredLoadRange range { } ;
2022-04-01 20:58:27 +03:00
elf_image . for_each_program_header ( [ & range ] ( auto const & pheader ) {
2021-02-12 16:30:29 +01:00
if ( pheader . type ( ) ! = PT_LOAD )
2021-05-16 02:36:52 -07:00
return ;
2021-02-12 16:30:29 +01:00
auto region_start = ( FlatPtr ) pheader . vaddr ( ) . as_ptr ( ) ;
auto region_end = region_start + pheader . size_in_memory ( ) ;
if ( range . start = = 0 | | region_start < range . start )
range . start = region_start ;
if ( range . end = = 0 | | region_end > range . end )
range . end = region_end ;
} ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( range . end > range . start ) ;
2021-02-12 16:30:29 +01:00
return range ;
} ;
2021-11-08 00:51:39 +01:00
static ErrorOr < FlatPtr > get_load_offset ( const ElfW ( Ehdr ) & main_program_header , OpenFileDescription & main_program_description , OpenFileDescription * interpreter_description )
2021-02-12 16:30:29 +01:00
{
2021-05-10 16:16:05 +02:00
constexpr FlatPtr load_range_start = 0x08000000 ;
constexpr FlatPtr load_range_size = 65536 * PAGE_SIZE ; // 2**16 * PAGE_SIZE = 256MB
constexpr FlatPtr minimum_load_offset_randomization_size = 10 * MiB ;
2021-02-12 16:30:29 +01:00
auto random_load_offset_in_range ( [ ] ( auto start , auto size ) {
2021-08-06 13:49:36 +02:00
return Memory : : page_round_down ( start + get_good_random < FlatPtr > ( ) % size ) ;
2021-02-12 16:30:29 +01:00
} ) ;
if ( main_program_header . e_type = = ET_DYN ) {
2021-05-10 16:16:05 +02:00
return random_load_offset_in_range ( load_range_start , load_range_size ) ;
2021-02-12 16:30:29 +01:00
}
if ( main_program_header . e_type ! = ET_EXEC )
2021-03-01 13:49:16 +01:00
return EINVAL ;
2021-02-12 16:30:29 +01:00
2021-09-06 16:44:35 +02:00
auto main_program_load_range = TRY ( get_required_load_range ( main_program_description ) ) ;
2021-02-12 16:30:29 +01:00
2021-08-06 23:42:53 +02:00
RequiredLoadRange selected_range { } ;
2021-02-12 16:30:29 +01:00
2021-05-10 16:16:05 +02:00
if ( interpreter_description ) {
2021-09-06 16:44:35 +02:00
auto interpreter_load_range = TRY ( get_required_load_range ( * interpreter_description ) ) ;
2021-02-12 16:30:29 +01:00
2021-09-06 16:44:35 +02:00
auto interpreter_size_in_memory = interpreter_load_range . end - interpreter_load_range . start ;
2021-05-10 16:16:05 +02:00
auto interpreter_load_range_end = load_range_start + load_range_size - interpreter_size_in_memory ;
2021-02-12 16:30:29 +01:00
2021-05-10 16:16:05 +02:00
// No intersection
if ( main_program_load_range . end < load_range_start | | main_program_load_range . start > interpreter_load_range_end )
return random_load_offset_in_range ( load_range_start , load_range_size ) ;
2021-02-12 16:30:29 +01:00
2021-08-06 23:42:53 +02:00
RequiredLoadRange first_available_part = { load_range_start , main_program_load_range . start } ;
RequiredLoadRange second_available_part = { main_program_load_range . end , interpreter_load_range_end } ;
2021-05-10 16:16:05 +02:00
// Select larger part
if ( first_available_part . end - first_available_part . start > second_available_part . end - second_available_part . start )
selected_range = first_available_part ;
else
selected_range = second_available_part ;
} else
selected_range = main_program_load_range ;
// If main program is too big and leaves us without enough space for adequate loader randomization
if ( selected_range . end - selected_range . start < minimum_load_offset_randomization_size )
2021-03-01 13:49:16 +01:00
return E2BIG ;
2021-02-12 16:30:29 +01:00
return random_load_offset_in_range ( selected_range . start , selected_range . end - selected_range . start ) ;
}
2021-02-08 22:24:37 +01:00
enum class ShouldAllocateTls {
No ,
Yes ,
} ;
2021-04-16 21:50:17 +02:00
enum class ShouldAllowSyscalls {
No ,
Yes ,
} ;
2021-11-08 00:51:39 +01:00
static ErrorOr < LoadResult > load_elf_object ( NonnullOwnPtr < Memory : : AddressSpace > new_space , OpenFileDescription & object_description ,
2021-04-16 21:50:17 +02:00
FlatPtr load_offset , ShouldAllocateTls should_allocate_tls , ShouldAllowSyscalls should_allow_syscalls )
2020-10-10 12:13:21 +03:00
{
auto & inode = * ( object_description . inode ( ) ) ;
2021-09-06 12:58:03 +02:00
auto vmobject = TRY ( Memory : : SharedInodeVMObject : : try_create_with_inode ( inode ) ) ;
2021-07-11 17:52:07 +02:00
2020-12-25 14:16:35 +01:00
if ( vmobject - > writable_mappings ( ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " Refusing to execute a write-mapped program " ) ;
2021-01-20 23:11:17 +01:00
return ETXTBSY ;
2020-07-30 23:38:15 +02:00
}
2020-12-25 14:15:33 +01:00
size_t executable_size = inode . size ( ) ;
2021-12-24 11:22:11 -03:00
size_t rounded_executable_size = TRY ( Memory : : page_round_up ( executable_size ) ) ;
2020-12-25 14:15:33 +01:00
2022-07-11 17:32:29 +00:00
auto executable_region = TRY ( MM . allocate_kernel_region_with_vmobject ( * vmobject , rounded_executable_size , " ELF loading " sv , Memory : : Region : : Access : : Read ) ) ;
2021-01-15 17:27:52 +01:00
auto elf_image = ELF : : Image ( executable_region - > vaddr ( ) . as_ptr ( ) , executable_size ) ;
2020-12-25 14:06:19 +01:00
if ( ! elf_image . is_valid ( ) )
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-12-25 14:06:19 +01:00
2021-08-06 13:49:36 +02:00
Memory : : Region * master_tls_region { nullptr } ;
2020-10-10 12:13:21 +03:00
size_t master_tls_size = 0 ;
size_t master_tls_alignment = 0 ;
2020-10-17 14:39:36 +03:00
FlatPtr load_base_address = 0 ;
2020-10-10 12:13:21 +03:00
2021-10-30 00:45:23 +02:00
auto elf_name = TRY ( object_description . pseudo_path ( ) ) ;
2021-08-10 01:16:08 +02:00
VERIFY ( ! Processor : : in_critical ( ) ) ;
2020-12-25 01:22:55 +01:00
2021-09-06 17:11:33 +02:00
Memory : : MemoryManager : : enter_address_space ( * new_space ) ;
2021-02-08 15:45:40 +01:00
2021-11-08 00:51:39 +01:00
auto load_tls_section = [ & ] ( auto & program_header ) - > ErrorOr < void > {
2021-09-06 22:56:27 +02:00
VERIFY ( should_allocate_tls = = ShouldAllocateTls : : Yes ) ;
VERIFY ( program_header . size_in_memory ( ) ) ;
2020-12-25 02:31:04 +01:00
2021-09-06 22:56:27 +02:00
if ( ! elf_image . is_within_image ( program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
dbgln ( " Shenanigans! ELF PT_TLS header sneaks outside of executable. " ) ;
return ENOEXEC ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 14:42:42 +01:00
2022-01-11 22:16:34 +02:00
auto region_name = TRY ( KString : : formatted ( " {} (master-tls) " , elf_name ) ) ;
2022-04-03 23:32:03 +02:00
master_tls_region = TRY ( new_space - > allocate_region ( Memory : : RandomizeVirtualAddress : : Yes , { } , program_header . size_in_memory ( ) , PAGE_SIZE , region_name - > view ( ) , PROT_READ | PROT_WRITE , AllocationStrategy : : Reserve ) ) ;
2021-09-06 22:56:27 +02:00
master_tls_size = program_header . size_in_memory ( ) ;
master_tls_alignment = program_header . alignment ( ) ;
2021-08-31 16:33:26 +02:00
2021-09-06 22:56:27 +02:00
TRY ( copy_to_user ( master_tls_region - > vaddr ( ) . as_ptr ( ) , program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) ;
2021-11-08 00:51:39 +01:00
return { } ;
2021-09-06 22:56:27 +02:00
} ;
2020-12-25 02:31:04 +01:00
2021-11-08 00:51:39 +01:00
auto load_writable_section = [ & ] ( auto & program_header ) - > ErrorOr < void > {
2021-09-06 22:56:27 +02:00
// Writable section: create a copy in memory.
2022-01-22 00:30:42 +01:00
VERIFY ( program_header . alignment ( ) % PAGE_SIZE = = 0 ) ;
2020-12-25 02:31:04 +01:00
2021-09-06 22:56:27 +02:00
if ( ! elf_image . is_within_image ( program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
dbgln ( " Shenanigans! Writable ELF PT_LOAD header sneaks outside of executable. " ) ;
return ENOEXEC ;
}
2021-03-12 17:26:24 +01:00
2021-09-06 22:56:27 +02:00
int prot = 0 ;
if ( program_header . is_readable ( ) )
prot | = PROT_READ ;
if ( program_header . is_writable ( ) )
prot | = PROT_WRITE ;
2022-01-11 22:16:34 +02:00
auto region_name = TRY ( KString : : formatted ( " {} (data-{}{}) " , elf_name , program_header . is_readable ( ) ? " r " : " " , program_header . is_writable ( ) ? " w " : " " ) ) ;
2021-03-12 17:26:24 +01:00
2021-09-06 22:56:27 +02:00
auto range_base = VirtualAddress { Memory : : page_round_down ( program_header . vaddr ( ) . offset ( load_offset ) . get ( ) ) } ;
2021-12-24 11:22:11 -03:00
size_t rounded_range_end = TRY ( Memory : : page_round_up ( program_header . vaddr ( ) . offset ( load_offset ) . offset ( program_header . size_in_memory ( ) ) . get ( ) ) ) ;
auto range_end = VirtualAddress { rounded_range_end } ;
2021-09-05 23:12:16 +02:00
2022-04-03 23:32:03 +02:00
auto region = TRY ( new_space - > allocate_region ( Memory : : RandomizeVirtualAddress : : Yes , range_base , range_end . get ( ) - range_base . get ( ) , PAGE_SIZE , region_name - > view ( ) , prot , AllocationStrategy : : Reserve ) ) ;
2021-09-06 22:56:27 +02:00
// It's not always the case with PIE executables (and very well shouldn't be) that the
// virtual address in the program header matches the one we end up giving the process.
// In order to copy the data image correctly into memory, we need to copy the data starting at
// the right initial page offset into the pages allocated for the elf_alloc-XX section.
// FIXME: There's an opportunity to munmap, or at least mprotect, the padding space between
// the .text and .data PT_LOAD sections of the executable.
// Accessing it would definitely be a bug.
auto page_offset = program_header . vaddr ( ) ;
page_offset . mask ( ~ PAGE_MASK ) ;
TRY ( copy_to_user ( ( u8 * ) region - > vaddr ( ) . as_ptr ( ) + page_offset . get ( ) , program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) ;
2021-11-08 00:51:39 +01:00
return { } ;
2021-09-06 22:56:27 +02:00
} ;
2020-12-25 02:31:04 +01:00
2021-11-08 00:51:39 +01:00
auto load_section = [ & ] ( auto & program_header ) - > ErrorOr < void > {
2021-09-06 22:56:27 +02:00
if ( program_header . size_in_memory ( ) = = 0 )
2021-11-08 00:51:39 +01:00
return { } ;
2021-09-06 22:56:27 +02:00
if ( program_header . is_writable ( ) )
return load_writable_section ( program_header ) ;
2020-12-25 14:42:42 +01:00
// Non-writable section: map the executable itself in memory.
2022-01-22 00:30:42 +01:00
VERIFY ( program_header . alignment ( ) % PAGE_SIZE = = 0 ) ;
2020-12-25 14:42:42 +01:00
int prot = 0 ;
if ( program_header . is_readable ( ) )
prot | = PROT_READ ;
if ( program_header . is_writable ( ) )
prot | = PROT_WRITE ;
if ( program_header . is_executable ( ) )
prot | = PROT_EXEC ;
2021-07-07 20:38:54 +02:00
2021-08-06 13:49:36 +02:00
auto range_base = VirtualAddress { Memory : : page_round_down ( program_header . vaddr ( ) . offset ( load_offset ) . get ( ) ) } ;
2021-12-24 11:22:11 -03:00
size_t rounded_range_end = TRY ( Memory : : page_round_up ( program_header . vaddr ( ) . offset ( load_offset ) . offset ( program_header . size_in_memory ( ) ) . get ( ) ) ) ;
auto range_end = VirtualAddress { rounded_range_end } ;
2022-04-03 23:32:03 +02:00
auto region = TRY ( new_space - > allocate_region_with_vmobject ( Memory : : RandomizeVirtualAddress : : Yes , range_base , range_end . get ( ) - range_base . get ( ) , program_header . alignment ( ) , * vmobject , program_header . offset ( ) , elf_name - > view ( ) , prot , true ) ) ;
2021-09-06 22:56:27 +02:00
2021-04-16 21:50:17 +02:00
if ( should_allow_syscalls = = ShouldAllowSyscalls : : Yes )
2021-09-06 22:56:27 +02:00
region - > set_syscall_region ( true ) ;
2020-12-25 14:42:42 +01:00
if ( program_header . offset ( ) = = 0 )
2021-09-06 22:56:27 +02:00
load_base_address = ( FlatPtr ) region - > vaddr ( ) . as_ptr ( ) ;
2021-11-08 00:51:39 +01:00
return { } ;
2021-09-06 22:56:27 +02:00
} ;
2020-12-25 01:22:55 +01:00
2021-11-08 00:51:39 +01:00
auto load_elf_program_header = [ & ] ( auto & program_header ) - > ErrorOr < void > {
2021-09-06 22:56:27 +02:00
if ( program_header . type ( ) = = PT_TLS )
return load_tls_section ( program_header ) ;
if ( program_header . type ( ) = = PT_LOAD )
return load_section ( program_header ) ;
// NOTE: We ignore other program header types.
2021-11-08 00:51:39 +01:00
return { } ;
2021-09-06 22:56:27 +02:00
} ;
TRY ( [ & ] {
2021-11-08 00:51:39 +01:00
ErrorOr < void > result ;
2021-09-06 22:56:27 +02:00
elf_image . for_each_program_header ( [ & ] ( ELF : : Image : : ProgramHeader const & program_header ) {
result = load_elf_program_header ( program_header ) ;
return result . is_error ( ) ? IterationDecision : : Break : IterationDecision : : Continue ;
} ) ;
return result ;
} ( ) ) ;
2020-10-10 12:13:21 +03:00
2020-12-25 01:22:55 +01:00
if ( ! elf_image . entry ( ) . offset ( load_offset ) . get ( ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " do_exec: Failure loading program, entry pointer is invalid! {}) " , elf_image . entry ( ) . offset ( load_offset ) ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-10-10 12:13:21 +03:00
}
2022-07-11 17:32:29 +00:00
auto * stack_region = TRY ( new_space - > allocate_region ( Memory : : RandomizeVirtualAddress : : Yes , { } , Thread : : default_userspace_stack_size , PAGE_SIZE , " Stack (Main thread) " sv , PROT_READ | PROT_WRITE , AllocationStrategy : : Reserve ) ) ;
2021-09-05 14:19:51 +02:00
stack_region - > set_stack ( true ) ;
2020-12-25 16:20:26 +01:00
2020-10-10 12:13:21 +03:00
return LoadResult {
2021-02-08 15:45:40 +01:00
move ( new_space ) ,
2020-10-17 14:39:36 +03:00
load_base_address ,
2020-12-25 01:22:55 +01:00
elf_image . entry ( ) . offset ( load_offset ) . get ( ) ,
2020-12-25 14:15:33 +01:00
executable_size ,
2022-02-13 21:21:14 +02:00
TRY ( AK : : try_make_weak_ptr_if_nonnull ( master_tls_region ) ) ,
2020-10-10 12:13:21 +03:00
master_tls_size ,
2020-12-25 16:20:26 +01:00
master_tls_alignment ,
2022-02-13 21:21:14 +02:00
TRY ( stack_region - > try_make_weak_ptr ( ) )
2020-10-10 12:13:21 +03:00
} ;
}
2020-07-30 23:38:15 +02:00
2021-11-08 00:51:39 +01:00
ErrorOr < LoadResult >
2022-08-19 20:53:40 +02:00
Process : : load ( NonnullLockRefPtr < OpenFileDescription > main_program_description ,
LockRefPtr < OpenFileDescription > interpreter_description , const ElfW ( Ehdr ) & main_program_header )
2020-10-10 12:13:21 +03:00
{
2021-09-05 15:13:20 +02:00
auto new_space = TRY ( Memory : : AddressSpace : : try_create ( nullptr ) ) ;
2020-07-30 23:38:15 +02:00
2021-02-08 15:45:40 +01:00
ScopeGuard space_guard ( [ & ] ( ) {
2021-09-06 17:11:33 +02:00
Memory : : MemoryManager : : enter_process_address_space ( * this ) ;
2020-10-10 12:13:21 +03:00
} ) ;
2021-09-06 16:44:35 +02:00
auto load_offset = TRY ( get_load_offset ( main_program_header , main_program_description , interpreter_description ) ) ;
2021-05-10 16:16:05 +02:00
2021-01-10 21:07:08 +02:00
if ( interpreter_description . is_null ( ) ) {
2021-09-06 16:44:35 +02:00
auto load_result = TRY ( load_elf_object ( move ( new_space ) , main_program_description , load_offset , ShouldAllocateTls : : Yes , ShouldAllowSyscalls : : No ) ) ;
m_master_tls_region = load_result . tls_region ;
m_master_tls_size = load_result . tls_size ;
m_master_tls_alignment = load_result . tls_alignment ;
return load_result ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
2021-09-06 16:44:35 +02:00
auto interpreter_load_result = TRY ( load_elf_object ( move ( new_space ) , * interpreter_description , load_offset , ShouldAllocateTls : : No , ShouldAllowSyscalls : : Yes ) ) ;
2020-07-30 23:38:15 +02:00
2020-10-10 12:13:21 +03:00
// TLS allocation will be done in userspace by the loader
2021-09-06 16:44:35 +02:00
VERIFY ( ! interpreter_load_result . tls_region ) ;
VERIFY ( ! interpreter_load_result . tls_alignment ) ;
VERIFY ( ! interpreter_load_result . tls_size ) ;
2020-07-30 23:38:15 +02:00
2020-12-25 15:23:35 +01:00
return interpreter_load_result ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
2022-07-02 11:42:17 +02:00
void Process : : clear_signal_handlers_for_exec ( )
{
// Comments are as they are presented in the POSIX specification, but slightly out of order.
for ( size_t signal = 0 ; signal < m_signal_action_data . size ( ) ; signal + + ) {
// Except for SIGCHLD, signals set to be ignored by the calling process image shall be set to be ignored by the new process image.
// If the SIGCHLD signal is set to be ignored by the calling process image, it is unspecified whether the SIGCHLD signal is set
// to be ignored or to the default action in the new process image.
if ( signal ! = SIGCHLD & & m_signal_action_data [ signal ] . handler_or_sigaction . get ( ) = = reinterpret_cast < FlatPtr > ( SIG_IGN ) ) {
m_signal_action_data [ signal ] = { } ;
m_signal_action_data [ signal ] . handler_or_sigaction . set ( reinterpret_cast < FlatPtr > ( SIG_IGN ) ) ;
continue ;
}
// Signals set to the default action in the calling process image shall be set to the default action in the new process image.
// Signals set to be caught by the calling process image shall be set to the default action in the new process image.
m_signal_action_data [ signal ] = { } ;
}
}
2022-08-19 20:53:40 +02:00
ErrorOr < void > Process : : do_exec ( NonnullLockRefPtr < OpenFileDescription > main_program_description , NonnullOwnPtrVector < KString > arguments , NonnullOwnPtrVector < KString > environment ,
LockRefPtr < OpenFileDescription > interpreter_description , Thread * & new_main_thread , u32 & prev_flags , const ElfW ( Ehdr ) & main_program_header )
2020-10-10 12:13:21 +03:00
{
2021-02-23 20:42:32 +01:00
VERIFY ( is_user_process ( ) ) ;
2021-08-10 01:16:08 +02:00
VERIFY ( ! Processor : : in_critical ( ) ) ;
2021-10-30 00:45:23 +02:00
// Although we *could* handle a pseudo_path here, trying to execute something that doesn't have
// a custody (e.g. BlockDevice or RandomDevice) is pretty suspicious anyway.
auto path = TRY ( main_program_description - > original_absolute_path ( ) ) ;
2021-02-18 08:51:06 +01:00
dbgln_if ( EXEC_DEBUG , " do_exec: {} " , path ) ;
2020-07-30 23:38:15 +02:00
2020-10-10 12:13:21 +03:00
// FIXME: How much stack space does process startup need?
if ( ! validate_stack_size ( arguments , environment ) )
2021-02-18 08:51:06 +01:00
return E2BIG ;
2020-10-10 12:13:21 +03:00
2022-06-18 18:36:23 +02:00
auto last_part = path - > view ( ) . find_last_split_view ( ' / ' ) ;
2020-07-30 23:38:15 +02:00
2022-06-18 18:36:23 +02:00
auto new_process_name = TRY ( KString : : try_create ( last_part ) ) ;
2021-09-07 12:53:28 +02:00
auto new_main_thread_name = TRY ( new_process_name - > try_clone ( ) ) ;
2021-09-06 12:44:27 +02:00
2021-09-05 14:19:51 +02:00
auto load_result = TRY ( load ( main_program_description , interpreter_description , main_program_header ) ) ;
2021-09-06 17:07:00 +02:00
2021-09-07 01:07:50 +02:00
// NOTE: We don't need the interpreter executable description after this point.
// We destroy it here to prevent it from getting destroyed when we return from this function.
// That's important because when we're returning from this function, we're in a very delicate
// state where we can't block (e.g by trying to acquire a mutex in description teardown.)
bool has_interpreter = interpreter_description ;
interpreter_description = nullptr ;
2022-07-11 17:32:29 +00:00
auto * signal_trampoline_region = TRY ( load_result . space - > allocate_region_with_vmobject ( Memory : : RandomizeVirtualAddress : : Yes , { } , PAGE_SIZE , PAGE_SIZE , g_signal_trampoline_region - > vmobject ( ) , 0 , " Signal trampoline " sv , PROT_READ | PROT_EXEC , true ) ) ;
2021-09-06 17:07:00 +02:00
signal_trampoline_region - > set_syscall_region ( true ) ;
2021-02-14 00:53:53 +01:00
2021-09-06 23:36:18 +02:00
// (For dynamically linked executable) Allocate an FD for passing the main executable to the dynamic loader.
Optional < ScopedDescriptionAllocation > main_program_fd_allocation ;
2021-09-07 01:07:50 +02:00
if ( has_interpreter )
2022-01-29 01:22:28 +01:00
main_program_fd_allocation = TRY ( allocate_fd ( ) ) ;
2021-09-06 23:36:18 +02:00
2022-08-20 18:25:54 +02:00
auto old_credentials = this - > credentials ( ) ;
auto new_credentials = old_credentials ;
2022-11-02 22:26:02 +02:00
auto old_process_attached_jail = m_attached_jail . with ( [ & ] ( auto & jail ) - > RefPtr < Jail > { return jail ; } ) ;
2020-12-20 18:35:29 +01:00
2020-12-26 01:18:41 +01:00
bool executable_is_setid = false ;
2020-12-20 18:35:29 +01:00
if ( ! ( main_program_description - > custody ( ) - > mount_flags ( ) & MS_NOSUID ) ) {
2021-09-15 23:49:08 -07:00
auto main_program_metadata = main_program_description - > metadata ( ) ;
2022-08-20 18:25:54 +02:00
auto new_euid = old_credentials - > euid ( ) ;
auto new_egid = old_credentials - > egid ( ) ;
auto new_suid = old_credentials - > suid ( ) ;
auto new_sgid = old_credentials - > sgid ( ) ;
2020-12-25 18:27:42 +01:00
if ( main_program_metadata . is_setuid ( ) ) {
2020-12-26 01:18:41 +01:00
executable_is_setid = true ;
2022-08-20 18:25:54 +02:00
new_euid = main_program_metadata . uid ;
new_suid = main_program_metadata . uid ;
2020-12-25 18:27:42 +01:00
}
if ( main_program_metadata . is_setgid ( ) ) {
2020-12-26 01:18:41 +01:00
executable_is_setid = true ;
2022-08-20 18:25:54 +02:00
new_egid = main_program_metadata . gid ;
new_sgid = main_program_metadata . gid ;
}
if ( executable_is_setid ) {
new_credentials = TRY ( Credentials : : create (
old_credentials - > uid ( ) ,
old_credentials - > gid ( ) ,
new_euid ,
new_egid ,
new_suid ,
new_sgid ,
old_credentials - > extra_gids ( ) ) ) ;
2020-12-25 18:27:42 +01:00
}
2020-12-20 18:35:29 +01:00
}
2022-08-20 18:25:54 +02:00
// We commit to the new executable at this point. There is no turning back!
// Prevent other processes from attaching to us with ptrace while we're doing this.
MutexLocker ptrace_locker ( ptrace_lock ( ) ) ;
// Disable profiling temporarily in case it's running on this process.
auto was_profiling = m_profiling ;
TemporaryChange profiling_disabler ( m_profiling , false ) ;
kill_threads_except_self ( ) ;
2022-08-21 12:18:26 +02:00
with_mutable_protected_data ( [ & ] ( auto & protected_data ) {
protected_data . credentials = move ( new_credentials ) ;
protected_data . dumpable = ! executable_is_setid ;
} ) ;
2021-02-08 19:15:42 +01:00
2021-12-23 00:42:30 +01:00
// We make sure to enter the new address space before destroying the old one.
// This ensures that the process always has a valid page directory.
Memory : : MemoryManager : : enter_address_space ( * load_result . space ) ;
2022-08-23 17:58:05 +02:00
m_space . with ( [ & ] ( auto & space ) { space = load_result . space . release_nonnull ( ) ; } ) ;
2020-10-10 12:13:21 +03:00
2022-08-21 01:04:35 +02:00
m_executable . with ( [ & ] ( auto & executable ) { executable = main_program_description - > custody ( ) ; } ) ;
2021-09-09 11:36:40 +02:00
m_arguments = move ( arguments ) ;
2022-11-02 22:26:02 +02:00
m_attached_jail . with ( [ & ] ( auto & jail ) {
jail = old_process_attached_jail ;
} ) ;
2021-09-09 11:36:40 +02:00
m_environment = move ( environment ) ;
2020-07-30 23:38:15 +02:00
2022-03-07 21:23:08 +01:00
TRY ( m_unveil_data . with ( [ & ] ( auto & unveil_data ) - > ErrorOr < void > {
2022-11-04 19:20:11 +02:00
TRY ( m_exec_unveil_data . with ( [ & ] ( auto & exec_unveil_data ) - > ErrorOr < void > {
// Note: If we have exec unveil data being waiting to be dispatched
// to the current execve'd program, then we apply the unveil data and
// ensure it is locked in the new program.
if ( exec_unveil_data . state = = VeilState : : Dropped ) {
unveil_data . state = VeilState : : LockedInherited ;
exec_unveil_data . state = VeilState : : None ;
unveil_data . paths = TRY ( exec_unveil_data . paths . deep_copy ( ) ) ;
} else {
unveil_data . state = VeilState : : None ;
exec_unveil_data . state = VeilState : : None ;
unveil_data . paths . clear ( ) ;
unveil_data . paths . set_metadata ( { TRY ( KString : : try_create ( " / " sv ) ) , UnveilAccess : : None , false } ) ;
}
exec_unveil_data . paths . clear ( ) ;
exec_unveil_data . paths . set_metadata ( { TRY ( KString : : try_create ( " / " sv ) ) , UnveilAccess : : None , false } ) ;
return { } ;
} ) ) ;
2022-03-07 21:23:08 +01:00
return { } ;
} ) ) ;
2020-07-30 23:38:15 +02:00
2022-04-09 18:30:20 +01:00
m_coredump_properties . for_each ( [ ] ( auto & property ) {
2021-08-05 23:43:10 +02:00
property = { } ;
2022-04-09 18:30:20 +01:00
} ) ;
2021-01-23 09:41:11 +01:00
2021-12-11 17:18:39 +02:00
auto * current_thread = Thread : : current ( ) ;
2021-12-11 17:40:50 +02:00
current_thread - > reset_signals_for_exec ( ) ;
2020-07-30 23:38:15 +02:00
2022-07-02 11:42:17 +02:00
clear_signal_handlers_for_exec ( ) ;
2020-12-21 23:21:58 -07:00
clear_futex_queues_on_exec ( ) ;
2020-07-30 23:38:15 +02:00
2022-01-29 01:29:07 +01:00
m_fds . with_exclusive ( [ & ] ( auto & fds ) {
2022-01-29 01:22:28 +01:00
fds . change_each ( [ & ] ( auto & file_description_metadata ) {
if ( file_description_metadata . is_valid ( ) & & file_description_metadata . flags ( ) & FD_CLOEXEC )
file_description_metadata = { } ;
} ) ;
2021-06-22 21:22:17 +03:00
} ) ;
2020-07-30 23:38:15 +02:00
2021-09-06 23:36:18 +02:00
if ( main_program_fd_allocation . has_value ( ) ) {
2020-10-10 12:13:21 +03:00
main_program_description - > set_readable ( true ) ;
2022-01-29 01:29:07 +01:00
m_fds . with_exclusive ( [ & ] ( auto & fds ) { fds [ main_program_fd_allocation - > fd ] . set ( move ( main_program_description ) , FD_CLOEXEC ) ; } ) ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
new_main_thread = nullptr ;
if ( & current_thread - > process ( ) = = this ) {
new_main_thread = current_thread ;
} else {
for_each_thread ( [ & ] ( auto & thread ) {
new_main_thread = & thread ;
return IterationDecision : : Break ;
} ) ;
}
2021-02-23 20:42:32 +01:00
VERIFY ( new_main_thread ) ;
2020-07-30 23:38:15 +02:00
2022-08-20 18:21:01 -04:00
auto credentials = this - > credentials ( ) ;
auto auxv = generate_auxiliary_vector ( load_result . load_base , load_result . entry_eip , credentials - > uid ( ) , credentials - > euid ( ) , credentials - > gid ( ) , credentials - > egid ( ) , path - > view ( ) , main_program_fd_allocation ) ;
2020-07-30 23:38:15 +02:00
// NOTE: We create the new stack before disabling interrupts since it will zero-fault
// and we don't want to deal with faults after this point.
2021-11-08 00:51:39 +01:00
auto new_userspace_sp = TRY ( make_userspace_context_for_main_thread ( new_main_thread - > regs ( ) , * load_result . stack_region . unsafe_ptr ( ) , m_arguments , m_environment , move ( auxv ) ) ) ;
2020-07-30 23:38:15 +02:00
2022-02-12 08:17:42 -08:00
m_name = move ( new_process_name ) ;
new_main_thread - > set_name ( move ( new_main_thread_name ) ) ;
2021-02-19 12:10:29 +01:00
if ( wait_for_tracer_at_next_execve ( ) ) {
// Make sure we release the ptrace lock here or the tracer will block forever.
ptrace_locker . unlock ( ) ;
2020-08-15 10:57:53 +03:00
Thread : : current ( ) - > send_urgent_signal_to_self ( SIGSTOP ) ;
2021-08-31 18:57:42 -06:00
} else {
// Unlock regardless before disabling interrupts.
// Ensure we always unlock after checking ptrace status to avoid TOCTOU ptrace issues
ptrace_locker . unlock ( ) ;
2021-02-19 12:10:29 +01:00
}
2020-08-15 10:57:53 +03:00
2020-07-30 23:38:15 +02:00
// We enter a critical section here because we don't want to get interrupted between do_exec()
// and Processor::assume_context() or the next context switch.
// If we used an InterruptDisabler that sti()'d on exit, we might timer tick'd too soon in exec().
2021-08-10 01:56:21 +02:00
Processor : : enter_critical ( ) ;
prev_flags = cpu_flags ( ) ;
cli ( ) ;
2020-07-30 23:38:15 +02:00
// NOTE: Be careful to not trigger any page faults below!
2022-08-21 12:18:26 +02:00
with_mutable_protected_data ( [ & ] ( auto & protected_data ) {
protected_data . promises = protected_data . execpromises . load ( ) ;
protected_data . has_promises = protected_data . has_execpromises . load ( ) ;
2021-03-10 22:50:00 +01:00
2022-08-21 12:18:26 +02:00
protected_data . execpromises = 0 ;
protected_data . has_execpromises = false ;
2021-03-10 22:50:00 +01:00
2022-08-21 12:18:26 +02:00
protected_data . signal_trampoline = signal_trampoline_region - > vaddr ( ) ;
2021-03-11 13:28:50 +01:00
2021-03-10 22:50:00 +01:00
// FIXME: PID/TID ISSUE
2022-08-21 12:18:26 +02:00
protected_data . pid = new_main_thread - > tid ( ) . value ( ) ;
} ) ;
2021-03-10 22:50:00 +01:00
2020-09-16 18:47:47 +01:00
auto tsr_result = new_main_thread - > make_thread_specific_region ( { } ) ;
2021-02-08 15:45:40 +01:00
if ( tsr_result . is_error ( ) ) {
// FIXME: We cannot fail this late. Refactor this so the allocation happens before we commit to the new executable.
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-02-08 15:45:40 +01:00
}
2020-07-30 23:38:15 +02:00
new_main_thread - > reset_fpu_state ( ) ;
2021-06-26 19:57:16 +02:00
auto & regs = new_main_thread - > m_regs ;
regs . cs = GDT_SELECTOR_CODE3 | 3 ;
2022-02-26 22:47:12 +02:00
# if ARCH(I386)
2021-06-26 19:57:16 +02:00
regs . ds = GDT_SELECTOR_DATA3 | 3 ;
regs . es = GDT_SELECTOR_DATA3 | 3 ;
regs . ss = GDT_SELECTOR_DATA3 | 3 ;
regs . fs = GDT_SELECTOR_DATA3 | 3 ;
regs . gs = GDT_SELECTOR_TLS | 3 ;
regs . eip = load_result . entry_eip ;
2021-06-28 17:42:29 +02:00
regs . esp = new_userspace_sp ;
2021-06-23 21:54:41 +02:00
# else
2021-06-26 19:57:16 +02:00
regs . rip = load_result . entry_eip ;
2021-06-28 17:42:29 +02:00
regs . rsp = new_userspace_sp ;
2021-06-23 21:54:41 +02:00
# endif
2022-08-23 17:58:05 +02:00
regs . cr3 = address_space ( ) . with ( [ ] ( auto & space ) { return space - > page_directory ( ) . cr3 ( ) ; } ) ;
2020-07-30 23:38:15 +02:00
2021-05-23 22:16:30 +02:00
{
TemporaryChange profiling_disabler ( m_profiling , was_profiling ) ;
PerformanceManager : : add_process_exec_event ( * this ) ;
}
2020-07-30 23:38:15 +02:00
2020-12-14 16:36:22 -07:00
u32 lock_count_to_restore ;
2022-01-29 01:47:18 +02:00
[[maybe_unused]] auto rc = big_lock ( ) . force_unlock_exclusive_if_locked ( lock_count_to_restore ) ;
2021-02-23 20:42:32 +01:00
VERIFY_INTERRUPTS_DISABLED ( ) ;
2021-08-10 01:16:08 +02:00
VERIFY ( Processor : : in_critical ( ) ) ;
2021-11-08 00:51:39 +01:00
return { } ;
2020-07-30 23:38:15 +02:00
}
2022-01-25 15:44:07 +02:00
static Array < ELF : : AuxiliaryValue , auxiliary_vector_size > generate_auxiliary_vector ( FlatPtr load_base , FlatPtr entry_eip , UserID uid , UserID euid , GroupID gid , GroupID egid , StringView executable_path , Optional < Process : : ScopedDescriptionAllocation > const & main_program_fd_allocation )
2020-07-30 23:38:15 +02:00
{
2022-01-25 15:44:07 +02:00
return { {
// PHDR/EXECFD
// PH*
{ ELF : : AuxiliaryValue : : PageSize , PAGE_SIZE } ,
{ ELF : : AuxiliaryValue : : BaseAddress , ( void * ) load_base } ,
2020-10-10 12:13:21 +03:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : Entry , ( void * ) entry_eip } ,
// NOTELF
{ ELF : : AuxiliaryValue : : Uid , ( long ) uid . value ( ) } ,
{ ELF : : AuxiliaryValue : : EUid , ( long ) euid . value ( ) } ,
{ ELF : : AuxiliaryValue : : Gid , ( long ) gid . value ( ) } ,
{ ELF : : AuxiliaryValue : : EGid , ( long ) egid . value ( ) } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : Platform , Processor : : platform_string ( ) } ,
// FIXME: This is platform specific
{ ELF : : AuxiliaryValue : : HwCap , ( long ) CPUID ( 1 ) . edx ( ) } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : ClockTick , ( long ) TimeManagement : : the ( ) . ticks_per_second ( ) } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
// FIXME: Also take into account things like extended filesystem permissions? That's what linux does...
{ ELF : : AuxiliaryValue : : Secure , ( ( uid ! = euid ) | | ( gid ! = egid ) ) ? 1 : 0 } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : Random , nullptr } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : ExecFilename , executable_path } ,
2020-07-30 23:38:15 +02:00
2022-01-25 15:44:07 +02:00
main_program_fd_allocation . has_value ( ) ? ELF : : AuxiliaryValue { ELF : : AuxiliaryValue : : ExecFileDescriptor , main_program_fd_allocation - > fd } : ELF : : AuxiliaryValue { ELF : : AuxiliaryValue : : Ignore , 0L } ,
2020-10-10 12:13:21 +03:00
2022-01-25 15:44:07 +02:00
{ ELF : : AuxiliaryValue : : Null , 0L } ,
} } ;
2020-07-30 23:38:15 +02:00
}
2021-11-08 00:51:39 +01:00
static ErrorOr < NonnullOwnPtrVector < KString > > find_shebang_interpreter_for_executable ( char const first_page [ ] , size_t nread )
2020-07-30 23:38:15 +02:00
{
int word_start = 2 ;
2021-09-09 11:36:40 +02:00
size_t word_length = 0 ;
2020-07-30 23:38:15 +02:00
if ( nread > 2 & & first_page [ 0 ] = = ' # ' & & first_page [ 1 ] = = ' ! ' ) {
2021-09-09 11:36:40 +02:00
NonnullOwnPtrVector < KString > interpreter_words ;
2020-07-30 23:38:15 +02:00
2021-09-06 13:05:20 +02:00
for ( size_t i = 2 ; i < nread ; + + i ) {
2020-07-30 23:38:15 +02:00
if ( first_page [ i ] = = ' \n ' ) {
break ;
}
if ( first_page [ i ] ! = ' ' ) {
+ + word_length ;
}
if ( first_page [ i ] = = ' ' ) {
if ( word_length > 0 ) {
2021-09-09 11:36:40 +02:00
auto word = TRY ( KString : : try_create ( StringView { & first_page [ word_start ] , word_length } ) ) ;
2022-01-25 15:45:48 +02:00
TRY ( interpreter_words . try_append ( move ( word ) ) ) ;
2020-07-30 23:38:15 +02:00
}
word_length = 0 ;
word_start = i + 1 ;
}
}
2021-09-09 11:36:40 +02:00
if ( word_length > 0 ) {
auto word = TRY ( KString : : try_create ( StringView { & first_page [ word_start ] , word_length } ) ) ;
2022-01-25 15:45:48 +02:00
TRY ( interpreter_words . try_append ( move ( word ) ) ) ;
2021-09-09 11:36:40 +02:00
}
2020-07-30 23:38:15 +02:00
if ( ! interpreter_words . is_empty ( ) )
return interpreter_words ;
}
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2022-08-19 20:53:40 +02:00
ErrorOr < LockRefPtr < OpenFileDescription > > Process : : find_elf_interpreter_for_executable ( StringView path , ElfW ( Ehdr ) const & main_executable_header , size_t main_executable_header_size , size_t file_size )
2020-07-30 23:38:15 +02:00
{
2021-11-08 00:51:39 +01:00
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
2022-01-13 18:50:17 +02:00
StringBuilder interpreter_path_builder ;
2022-01-13 20:54:53 +02:00
if ( ! TRY ( ELF : : validate_program_headers ( main_executable_header , file_size , { & main_executable_header , main_executable_header_size } , & interpreter_path_builder ) ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " exec({}): File has invalid ELF Program headers " , path ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2022-01-13 18:50:17 +02:00
auto interpreter_path = interpreter_path_builder . string_view ( ) ;
2020-07-30 23:38:15 +02:00
if ( ! interpreter_path . is_empty ( ) ) {
2021-02-18 08:51:06 +01:00
dbgln_if ( EXEC_DEBUG , " exec({}): Using program interpreter {} " , path , interpreter_path ) ;
2022-08-21 16:02:24 +02:00
auto interpreter_description = TRY ( VirtualFileSystem : : the ( ) . open ( credentials ( ) , interpreter_path , O_EXEC , 0 , current_directory ( ) ) ) ;
2020-07-30 23:38:15 +02:00
auto interp_metadata = interpreter_description - > metadata ( ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( interpreter_description - > inode ( ) ) ;
2020-07-30 23:38:15 +02:00
// Validate the program interpreter as a valid elf binary.
// If your program interpreter is a #! file or something, it's time to stop playing games :)
2021-06-28 17:24:08 +02:00
if ( interp_metadata . size < ( int ) sizeof ( ElfW ( Ehdr ) ) )
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
2021-01-10 21:07:08 +02:00
char first_page [ PAGE_SIZE ] = { } ;
2020-09-11 21:11:07 -06:00
auto first_page_buffer = UserOrKernelBuffer : : for_kernel_buffer ( ( u8 * ) & first_page ) ;
2021-09-06 13:05:20 +02:00
auto nread = TRY ( interpreter_description - > read ( first_page_buffer , sizeof ( first_page ) ) ) ;
2020-07-30 23:38:15 +02:00
2021-09-06 13:05:20 +02:00
if ( nread < sizeof ( ElfW ( Ehdr ) ) )
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
2021-12-18 18:37:21 +01:00
auto * elf_header = ( ElfW ( Ehdr ) * ) first_page ;
2020-07-30 23:38:15 +02:00
if ( ! ELF : : validate_elf_header ( * elf_header , interp_metadata . size ) ) {
2021-10-29 21:21:26 +02:00
dbgln ( " exec({}): Interpreter ({}) has invalid ELF header " , path , interpreter_path ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2021-11-08 00:51:39 +01:00
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
2022-01-13 18:50:17 +02:00
StringBuilder interpreter_interpreter_path_builder ;
2022-01-13 20:54:53 +02:00
if ( ! TRY ( ELF : : validate_program_headers ( * elf_header , interp_metadata . size , { first_page , nread } , & interpreter_interpreter_path_builder ) ) ) {
2021-10-29 21:21:26 +02:00
dbgln ( " exec({}): Interpreter ({}) has invalid ELF Program headers " , path , interpreter_path ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2022-01-13 18:50:17 +02:00
auto interpreter_interpreter_path = interpreter_interpreter_path_builder . string_view ( ) ;
2020-07-30 23:38:15 +02:00
2020-12-31 17:51:21 -07:00
if ( ! interpreter_interpreter_path . is_empty ( ) ) {
2021-10-29 21:21:26 +02:00
dbgln ( " exec({}): Interpreter ({}) has its own interpreter ({})! No thank you! " , path , interpreter_path , interpreter_interpreter_path ) ;
2021-01-20 23:11:17 +01:00
return ELOOP ;
2020-12-31 17:51:21 -07:00
}
2020-07-30 23:38:15 +02:00
return interpreter_description ;
}
2021-09-06 16:29:34 +02:00
if ( main_executable_header . e_type = = ET_REL ) {
2020-07-30 23:38:15 +02:00
// We can't exec an ET_REL, that's just an object file from the compiler
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2021-09-06 16:29:34 +02:00
if ( main_executable_header . e_type = = ET_DYN ) {
2021-01-02 21:31:01 +00:00
// If it's ET_DYN with no PT_INTERP, then it's a dynamic executable responsible
// for its own relocation (i.e. it's /usr/lib/Loader.so)
if ( path ! = " /usr/lib/Loader.so " )
2021-01-16 21:34:53 +00:00
dbgln ( " exec({}): WARNING - Dynamic ELF executable without a PT_INTERP header, and isn't /usr/lib/Loader.so " , path ) ;
2021-01-02 21:31:01 +00:00
return nullptr ;
}
2020-07-30 23:38:15 +02:00
// No interpreter, but, path refers to a valid elf image
2021-09-07 01:07:50 +02:00
return nullptr ;
2020-07-30 23:38:15 +02:00
}
2022-01-13 23:12:51 +01:00
ErrorOr < void > Process : : exec ( NonnullOwnPtr < KString > path , NonnullOwnPtrVector < KString > arguments , NonnullOwnPtrVector < KString > environment , Thread * & new_main_thread , u32 & prev_flags , int recursion_depth )
2020-07-30 23:38:15 +02:00
{
if ( recursion_depth > 2 ) {
2020-12-25 12:51:35 +01:00
dbgln ( " exec({}): SHENANIGANS! recursed too far trying to find #! interpreter " , path ) ;
2021-02-18 08:51:06 +01:00
return ELOOP ;
2020-07-30 23:38:15 +02:00
}
// Open the file to check what kind of binary format it is
// Currently supported formats:
// - #! interpreted file
// - ELF32
// * ET_EXEC binary that just gets loaded
// * ET_DYN binary that requires a program interpreter
//
2022-08-21 16:02:24 +02:00
auto description = TRY ( VirtualFileSystem : : the ( ) . open ( credentials ( ) , path - > view ( ) , O_EXEC , 0 , current_directory ( ) ) ) ;
2020-07-30 23:38:15 +02:00
auto metadata = description - > metadata ( ) ;
2021-06-04 22:51:04 +02:00
if ( ! metadata . is_regular_file ( ) )
return EACCES ;
2020-07-30 23:38:15 +02:00
// Always gonna need at least 3 bytes. these are for #!X
if ( metadata . size < 3 )
2021-02-18 08:51:06 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
2021-02-23 20:42:32 +01:00
VERIFY ( description - > inode ( ) ) ;
2020-07-30 23:38:15 +02:00
// Read the first page of the program into memory so we can validate the binfmt of it
char first_page [ PAGE_SIZE ] ;
2020-09-11 21:11:07 -06:00
auto first_page_buffer = UserOrKernelBuffer : : for_kernel_buffer ( ( u8 * ) & first_page ) ;
2021-09-06 13:05:20 +02:00
auto nread = TRY ( description - > read ( first_page_buffer , sizeof ( first_page ) ) ) ;
2020-07-30 23:38:15 +02:00
// 1) #! interpreted file
2021-09-06 13:05:20 +02:00
auto shebang_result = find_shebang_interpreter_for_executable ( first_page , nread ) ;
2020-07-30 23:38:15 +02:00
if ( ! shebang_result . is_error ( ) ) {
2021-06-06 01:13:25 +02:00
auto shebang_words = shebang_result . release_value ( ) ;
2021-09-09 11:36:40 +02:00
auto shebang_path = TRY ( shebang_words . first ( ) . try_clone ( ) ) ;
arguments . ptr_at ( 0 ) = move ( path ) ;
2021-11-10 11:55:37 +01:00
TRY ( arguments . try_prepend ( move ( shebang_words ) ) ) ;
2022-01-13 23:12:51 +01:00
return exec ( move ( shebang_path ) , move ( arguments ) , move ( environment ) , new_main_thread , prev_flags , + + recursion_depth ) ;
2020-07-30 23:38:15 +02:00
}
// #2) ELF32 for i386
2021-01-10 21:07:08 +02:00
2021-09-06 13:05:20 +02:00
if ( nread < sizeof ( ElfW ( Ehdr ) ) )
2021-02-18 08:51:06 +01:00
return ENOEXEC ;
2021-12-18 18:37:21 +01:00
auto const * main_program_header = ( ElfW ( Ehdr ) * ) first_page ;
2021-01-10 21:07:08 +02:00
if ( ! ELF : : validate_elf_header ( * main_program_header , metadata . size ) ) {
dbgln ( " exec({}): File has invalid ELF header " , path ) ;
2021-02-18 08:51:06 +01:00
return ENOEXEC ;
2021-01-10 21:07:08 +02:00
}
2021-09-07 13:31:12 +02:00
auto interpreter_description = TRY ( find_elf_interpreter_for_executable ( path - > view ( ) , * main_program_header , nread , metadata . size ) ) ;
2022-01-13 23:12:51 +01:00
return do_exec ( move ( description ) , move ( arguments ) , move ( environment ) , move ( interpreter_description ) , new_main_thread , prev_flags , * main_program_header ) ;
2020-07-30 23:38:15 +02:00
}
2022-04-01 20:58:27 +03:00
ErrorOr < FlatPtr > Process : : sys $ execve ( Userspace < Syscall : : SC_execve_params const * > user_params )
2020-07-30 23:38:15 +02:00
{
2021-07-18 11:20:12 -07:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2021-12-29 01:11:45 -08:00
TRY ( require_promise ( Pledge : : exec ) ) ;
2020-07-30 23:38:15 +02:00
2022-01-13 23:17:52 +01:00
Thread * new_main_thread = nullptr ;
u32 prev_flags = 0 ;
2022-01-13 23:12:51 +01:00
// NOTE: Be extremely careful with allocating any kernel memory in this function.
2020-07-30 23:38:15 +02:00
// On success, the kernel stack will be lost.
2022-01-13 23:17:52 +01:00
// The explicit block scope below is specifically placed to minimize the number
// of stack locals in this function.
{
auto params = TRY ( copy_typed_from_user ( user_params ) ) ;
if ( params . arguments . length > ARG_MAX | | params . environment . length > ARG_MAX )
return E2BIG ;
2022-01-26 03:13:06 -08:00
// NOTE: The caller is expected to always pass at least one argument by convention,
// the program path that was passed as params.path.
if ( params . arguments . length = = 0 )
return EINVAL ;
2022-01-13 23:17:52 +01:00
auto path = TRY ( get_syscall_path_argument ( params . path ) ) ;
2022-04-01 20:58:27 +03:00
auto copy_user_strings = [ ] ( auto const & list , auto & output ) - > ErrorOr < void > {
2022-01-13 23:17:52 +01:00
if ( ! list . length )
return { } ;
Checked < size_t > size = sizeof ( * list . strings ) ;
size * = list . length ;
if ( size . has_overflow ( ) )
return EOVERFLOW ;
Vector < Syscall : : StringArgument , 32 > strings ;
TRY ( strings . try_resize ( list . length ) ) ;
TRY ( copy_from_user ( strings . data ( ) , list . strings , size . value ( ) ) ) ;
for ( size_t i = 0 ; i < list . length ; + + i ) {
auto string = TRY ( try_copy_kstring_from_user ( strings [ i ] ) ) ;
TRY ( output . try_append ( move ( string ) ) ) ;
}
2021-11-08 00:51:39 +01:00
return { } ;
2022-01-13 23:17:52 +01:00
} ;
2020-07-30 23:38:15 +02:00
2022-01-13 23:17:52 +01:00
NonnullOwnPtrVector < KString > arguments ;
TRY ( copy_user_strings ( params . arguments , arguments ) ) ;
2020-07-30 23:38:15 +02:00
2022-01-13 23:17:52 +01:00
NonnullOwnPtrVector < KString > environment ;
TRY ( copy_user_strings ( params . environment , environment ) ) ;
2020-07-30 23:38:15 +02:00
2022-01-13 23:17:52 +01:00
TRY ( exec ( move ( path ) , move ( arguments ) , move ( environment ) , new_main_thread , prev_flags ) ) ;
}
2022-01-13 23:12:51 +01:00
// NOTE: If we're here, the exec has succeeded and we've got a new executable image!
// We will not return normally from this function. Instead, the next time we
// get scheduled, it'll be at the entry point of the new executable.
VERIFY_INTERRUPTS_DISABLED ( ) ;
VERIFY ( Processor : : in_critical ( ) ) ;
auto * current_thread = Thread : : current ( ) ;
if ( current_thread = = new_main_thread ) {
// We need to enter the scheduler lock before changing the state
// and it will be released after the context switch into that
// thread. We should also still be in our critical section
VERIFY ( ! g_scheduler_lock . is_locked_by_current_processor ( ) ) ;
VERIFY ( Processor : : in_critical ( ) = = 1 ) ;
g_scheduler_lock . lock ( ) ;
current_thread - > set_state ( Thread : : State : : Running ) ;
Processor : : assume_context ( * current_thread , prev_flags ) ;
VERIFY_NOT_REACHED ( ) ;
}
// NOTE: This code path is taken in the non-syscall case, i.e when the kernel spawns
// a userspace process directly (such as /bin/SystemServer on startup)
if ( prev_flags & 0x200 )
sti ( ) ;
Processor : : leave_critical ( ) ;
return 0 ;
2020-07-30 23:38:15 +02:00
}
2021-11-08 00:51:39 +01:00
2020-07-30 23:38:15 +02:00
}