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 >
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-10 16:29:28 -07:00
# include <AK/WeakPtr.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>
# include <Kernel/FileSystem/FileDescription.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>
# include <Kernel/Time/TimeManagement.h>
2020-09-05 15:52:14 -06:00
# include <Kernel/VM/AllocationStrategy.h>
2020-07-30 23:38:15 +02:00
# include <Kernel/VM/MemoryManager.h>
# include <Kernel/VM/PageDirectory.h>
# include <Kernel/VM/Region.h>
# include <Kernel/VM/SharedInodeVMObject.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-02-14 00:53:53 +01:00
extern Region * g_signal_trampoline_region ;
2021-02-08 15:45:40 +01:00
struct LoadResult {
OwnPtr < Space > space ;
FlatPtr load_base { 0 } ;
FlatPtr entry_eip { 0 } ;
size_t size { 0 } ;
WeakPtr < Region > tls_region ;
size_t tls_size { 0 } ;
size_t tls_alignment { 0 } ;
WeakPtr < Region > stack_region ;
} ;
2020-12-25 15:23:35 +01:00
static Vector < ELF : : AuxiliaryValue > generate_auxiliary_vector ( FlatPtr load_base , FlatPtr entry_eip , uid_t uid , uid_t euid , gid_t gid , gid_t egid , String executable_path , int main_program_fd ) ;
2020-10-10 12:13:21 +03:00
static bool validate_stack_size ( const Vector < String > & arguments , const Vector < String > & 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 ;
2020-07-30 23:38:15 +02:00
for ( auto & a : arguments )
2021-01-17 18:26:12 +01:00
total_arguments_size + = a . length ( ) + 1 ;
2020-07-30 23:38:15 +02:00
for ( auto & 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 ) ;
static constexpr size_t max_arguments_size = Thread : : default_userspace_stack_size / 8 ;
static constexpr size_t max_environment_size = Thread : : default_userspace_stack_size / 8 ;
if ( total_arguments_size > max_arguments_size )
return false ;
2020-07-30 23:38:15 +02:00
2021-01-17 18:26:12 +01:00
if ( total_environment_size > max_environment_size )
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-06-28 17:42:29 +02:00
static KResultOr < FlatPtr > make_userspace_context_for_main_thread ( [[maybe_unused]] ThreadRegisters & regs , Region & region , Vector < String > arguments ,
Vector < String > environment , Vector < ELF : : AuxiliaryValue > 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 ;
2020-12-25 16:20:26 +01:00
return copy_to_user ( stack_ptr , & value ) ;
} ;
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 ;
2020-12-25 16:20:26 +01:00
return copy_to_user ( stack_ptr , & value ) ;
} ;
2021-06-28 17:42:29 +02:00
auto push_string_on_new_stack = [ & new_sp ] ( const String & string ) {
new_sp - = round_up_to_power_of_two ( string . length ( ) + 1 , sizeof ( FlatPtr ) ) ;
Userspace < FlatPtr * > stack_ptr = new_sp ;
2020-12-25 16:20:26 +01:00
return copy_to_user ( stack_ptr , string . characters ( ) , string . length ( ) + 1 ) ;
} ;
Vector < FlatPtr > argv_entries ;
for ( auto & argument : arguments ) {
push_string_on_new_stack ( argument ) ;
2021-06-28 17:42:29 +02:00
if ( ! argv_entries . try_append ( new_sp ) )
2021-04-29 01:40:19 -07:00
return ENOMEM ;
2020-12-25 16:20:26 +01:00
}
Vector < FlatPtr > env_entries ;
for ( auto & variable : environment ) {
push_string_on_new_stack ( variable ) ;
2021-06-28 17:42:29 +02:00
if ( ! env_entries . try_append ( new_sp ) )
2021-04-29 01:40:19 -07:00
return ENOMEM ;
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
}
}
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 ( ) ) ;
# else
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 ;
# 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-02-12 16:30:29 +01:00
struct RequiredLoadRange {
FlatPtr start { 0 } ;
FlatPtr end { 0 } ;
} ;
static KResultOr < RequiredLoadRange > get_required_load_range ( FileDescription & program_description )
{
auto & inode = * ( program_description . inode ( ) ) ;
2021-07-11 17:52:07 +02:00
auto vmobject = SharedInodeVMObject : : try_create_with_inode ( inode ) ;
if ( ! vmobject ) {
dbgln ( " get_required_load_range: Unable to allocate SharedInodeVMObject " ) ;
return ENOMEM ;
}
2021-02-12 16:30:29 +01:00
size_t executable_size = inode . size ( ) ;
2021-02-14 09:57:19 +01:00
auto region = MM . allocate_kernel_region_with_vmobject ( * vmobject , page_round_up ( executable_size ) , " ELF memory range calculation " , Region : : Access : : Read ) ;
2021-02-12 16:30:29 +01:00
if ( ! region ) {
dbgln ( " Could not allocate memory for ELF " ) ;
return ENOMEM ;
}
auto elf_image = ELF : : Image ( region - > vaddr ( ) . as_ptr ( ) , executable_size ) ;
if ( ! elf_image . is_valid ( ) ) {
return EINVAL ;
}
RequiredLoadRange range { } ;
elf_image . for_each_program_header ( [ & range ] ( const auto & pheader ) {
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-06-28 17:24:08 +02:00
static KResultOr < FlatPtr > get_load_offset ( const ElfW ( Ehdr ) & main_program_header , FileDescription & main_program_description , FileDescription * 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-02-14 09:57:19 +01:00
return 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
auto main_program_load_range_result = get_required_load_range ( main_program_description ) ;
if ( main_program_load_range_result . is_error ( ) )
return main_program_load_range_result . error ( ) ;
auto main_program_load_range = main_program_load_range_result . value ( ) ;
2021-05-10 16:16:05 +02:00
RequiredLoadRange selected_range { } ;
2021-02-12 16:30:29 +01:00
2021-05-10 16:16:05 +02:00
if ( interpreter_description ) {
auto interpreter_load_range_result = get_required_load_range ( * interpreter_description ) ;
if ( interpreter_load_range_result . is_error ( ) )
return interpreter_load_range_result . error ( ) ;
2021-02-12 16:30:29 +01:00
2021-05-10 16:16:05 +02:00
auto interpreter_size_in_memory = interpreter_load_range_result . value ( ) . end - interpreter_load_range_result . value ( ) . start ;
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-05-10 16:16:05 +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 } ;
// 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 ,
} ;
static KResultOr < LoadResult > load_elf_object ( NonnullOwnPtr < Space > new_space , FileDescription & object_description ,
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-07-11 17:52:07 +02:00
auto vmobject = SharedInodeVMObject : : try_create_with_inode ( inode ) ;
if ( ! vmobject ) {
dbgln ( " load_elf_object: Unable to allocate SharedInodeVMObject " ) ;
return ENOMEM ;
}
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-02-14 09:57:19 +01:00
auto executable_region = MM . allocate_kernel_region_with_vmobject ( * vmobject , page_round_up ( executable_size ) , " ELF loading " , Region : : Access : : Read ) ;
2021-01-15 17:27:52 +01:00
if ( ! executable_region ) {
2020-12-25 12:51:35 +01:00
dbgln ( " Could not allocate memory for ELF loading " ) ;
2021-01-20 23:11:17 +01:00
return ENOMEM ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
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
2020-10-10 12:13:21 +03:00
Region * master_tls_region { nullptr } ;
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
2020-12-25 02:31:04 +01:00
String elf_name = object_description . absolute_path ( ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( ! Processor : : current ( ) . in_critical ( ) ) ;
2020-12-25 01:22:55 +01:00
2021-02-08 15:45:40 +01:00
MemoryManager : : enter_space ( * new_space ) ;
2020-12-25 14:42:42 +01:00
KResult ph_load_result = KSuccess ;
2020-12-25 01:22:55 +01:00
elf_image . for_each_program_header ( [ & ] ( const ELF : : Image : : ProgramHeader & program_header ) {
if ( program_header . type ( ) = = PT_TLS ) {
2021-02-23 20:42:32 +01:00
VERIFY ( should_allocate_tls = = ShouldAllocateTls : : Yes ) ;
VERIFY ( program_header . size_in_memory ( ) ) ;
2020-12-25 02:31:04 +01:00
if ( ! elf_image . is_within_image ( program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " Shenanigans! ELF PT_TLS header sneaks outside of executable. " ) ;
2021-01-20 23:11:17 +01:00
ph_load_result = ENOEXEC ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 02:31:04 +01:00
2021-02-08 15:45:40 +01:00
auto range = new_space - > allocate_range ( { } , program_header . size_in_memory ( ) ) ;
2021-01-27 21:01:45 +01:00
if ( ! range . has_value ( ) ) {
2021-01-26 14:13:57 +01:00
ph_load_result = ENOMEM ;
return IterationDecision : : Break ;
}
2021-02-08 15:45:40 +01:00
auto region_or_error = new_space - > allocate_region ( range . value ( ) , String : : formatted ( " {} (master-tls) " , elf_name ) , PROT_READ | PROT_WRITE , AllocationStrategy : : Reserve ) ;
2021-01-15 17:27:52 +01:00
if ( region_or_error . is_error ( ) ) {
ph_load_result = region_or_error . error ( ) ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2021-03-15 21:56:13 +02:00
2021-01-15 17:27:52 +01:00
master_tls_region = region_or_error . value ( ) ;
2020-12-25 02:31:04 +01:00
master_tls_size = program_header . size_in_memory ( ) ;
master_tls_alignment = program_header . alignment ( ) ;
if ( ! copy_to_user ( master_tls_region - > vaddr ( ) . as_ptr ( ) , program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
2021-01-20 23:11:17 +01:00
ph_load_result = EFAULT ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-12-25 01:22:55 +01:00
}
if ( program_header . type ( ) ! = PT_LOAD )
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-12-25 01:22:55 +01:00
if ( program_header . is_writable ( ) ) {
2020-12-25 14:42:42 +01:00
// Writable section: create a copy in memory.
2021-02-23 20:42:32 +01:00
VERIFY ( program_header . size_in_memory ( ) ) ;
VERIFY ( program_header . alignment ( ) = = PAGE_SIZE ) ;
2020-12-25 02:31:04 +01:00
if ( ! elf_image . is_within_image ( program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " Shenanigans! Writable ELF PT_LOAD header sneaks outside of executable. " ) ;
2021-01-20 23:11:17 +01:00
ph_load_result = ENOEXEC ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 02:31:04 +01:00
int prot = 0 ;
if ( program_header . is_readable ( ) )
prot | = PROT_READ ;
if ( program_header . is_writable ( ) )
prot | = PROT_WRITE ;
auto region_name = String : : formatted ( " {} (data-{}{}) " , elf_name , program_header . is_readable ( ) ? " r " : " " , program_header . is_writable ( ) ? " w " : " " ) ;
2021-03-12 17:26:24 +01:00
auto range_base = VirtualAddress { page_round_down ( program_header . vaddr ( ) . offset ( load_offset ) . get ( ) ) } ;
auto range_end = VirtualAddress { page_round_up ( program_header . vaddr ( ) . offset ( load_offset ) . offset ( program_header . size_in_memory ( ) ) . get ( ) ) } ;
auto range = new_space - > allocate_range ( range_base , range_end . get ( ) - range_base . get ( ) ) ;
2021-01-27 21:01:45 +01:00
if ( ! range . has_value ( ) ) {
2021-01-26 14:13:57 +01:00
ph_load_result = ENOMEM ;
return IterationDecision : : Break ;
}
2021-02-08 15:45:40 +01:00
auto region_or_error = new_space - > allocate_region ( range . value ( ) , region_name , prot , AllocationStrategy : : Reserve ) ;
2021-01-15 17:27:52 +01:00
if ( region_or_error . is_error ( ) ) {
ph_load_result = region_or_error . error ( ) ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 02:31:04 +01:00
2020-12-25 01:22:55 +01: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 ) ;
2021-01-15 17:27:52 +01:00
if ( ! copy_to_user ( ( u8 * ) region_or_error . value ( ) - > vaddr ( ) . as_ptr ( ) + page_offset . get ( ) , program_header . raw_data ( ) , program_header . size_in_image ( ) ) ) {
2021-01-20 23:11:17 +01:00
ph_load_result = EFAULT ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-12-25 01:22:55 +01:00
}
2020-12-25 14:42:42 +01:00
// Non-writable section: map the executable itself in memory.
2021-02-23 20:42:32 +01:00
VERIFY ( program_header . size_in_memory ( ) ) ;
VERIFY ( program_header . alignment ( ) = = PAGE_SIZE ) ;
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
auto range_base = VirtualAddress { page_round_down ( program_header . vaddr ( ) . offset ( load_offset ) . get ( ) ) } ;
auto range_end = VirtualAddress { page_round_up ( program_header . vaddr ( ) . offset ( load_offset ) . offset ( program_header . size_in_memory ( ) ) . get ( ) ) } ;
auto range = new_space - > allocate_range ( range_base , range_end . get ( ) - range_base . get ( ) ) ;
2021-01-27 21:01:45 +01:00
if ( ! range . has_value ( ) ) {
2021-01-26 14:13:57 +01:00
ph_load_result = ENOMEM ;
return IterationDecision : : Break ;
}
2021-02-08 15:45:40 +01:00
auto region_or_error = new_space - > allocate_region_with_vmobject ( range . value ( ) , * vmobject , program_header . offset ( ) , elf_name , prot , true ) ;
2021-01-15 17:27:52 +01:00
if ( region_or_error . is_error ( ) ) {
ph_load_result = region_or_error . error ( ) ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Break ;
}
2021-04-16 21:50:17 +02:00
if ( should_allow_syscalls = = ShouldAllowSyscalls : : Yes )
region_or_error . value ( ) - > set_syscall_region ( true ) ;
2020-12-25 14:42:42 +01:00
if ( program_header . offset ( ) = = 0 )
2021-01-15 17:27:52 +01:00
load_base_address = ( FlatPtr ) region_or_error . value ( ) - > vaddr ( ) . as_ptr ( ) ;
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-12-25 01:22:55 +01:00
} ) ;
2020-12-25 14:42:42 +01:00
if ( ph_load_result . is_error ( ) ) {
dbgln ( " do_exec: Failure loading program ({}) " , ph_load_result . error ( ) ) ;
return ph_load_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
}
2021-02-08 15:45:40 +01:00
auto stack_range = new_space - > allocate_range ( { } , Thread : : default_userspace_stack_size ) ;
2021-01-27 21:01:45 +01:00
if ( ! stack_range . has_value ( ) ) {
2021-01-26 14:13:57 +01:00
dbgln ( " do_exec: Failed to allocate VM range for stack " ) ;
return ENOMEM ;
}
2021-02-08 15:45:40 +01:00
auto stack_region_or_error = new_space - > allocate_region ( stack_range . value ( ) , " Stack (Main thread) " , PROT_READ | PROT_WRITE , AllocationStrategy : : Reserve ) ;
2021-01-15 17:27:52 +01:00
if ( stack_region_or_error . is_error ( ) )
return stack_region_or_error . error ( ) ;
auto & stack_region = * stack_region_or_error . value ( ) ;
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 ,
2021-01-10 16:29:28 -07:00
AK : : try_make_weak_ptr ( 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 ,
2021-01-15 17:27:52 +01:00
stack_region . make_weak_ptr ( )
2020-10-10 12:13:21 +03:00
} ;
}
2020-07-30 23:38:15 +02:00
2021-06-28 17:24:08 +02:00
KResultOr < LoadResult > Process : : load ( NonnullRefPtr < FileDescription > main_program_description ,
RefPtr < FileDescription > interpreter_description , const ElfW ( Ehdr ) & main_program_header )
2020-10-10 12:13:21 +03:00
{
2021-07-27 14:54:08 +02:00
auto new_space = Space : : try_create ( * this , nullptr ) ;
2021-02-08 15:45:40 +01:00
if ( ! new_space )
return ENOMEM ;
2020-07-30 23:38:15 +02:00
2021-02-08 15:45:40 +01:00
ScopeGuard space_guard ( [ & ] ( ) {
MemoryManager : : enter_process_paging_scope ( * this ) ;
2020-10-10 12:13:21 +03:00
} ) ;
2021-05-10 16:16:05 +02:00
auto load_offset = get_load_offset ( main_program_header , main_program_description , interpreter_description ) ;
if ( load_offset . is_error ( ) ) {
return load_offset . error ( ) ;
}
2021-01-10 21:07:08 +02:00
if ( interpreter_description . is_null ( ) ) {
2021-05-10 16:16:05 +02:00
auto result = load_elf_object ( new_space . release_nonnull ( ) , main_program_description , load_offset . value ( ) , ShouldAllocateTls : : Yes , ShouldAllowSyscalls : : No ) ;
2020-10-10 12:13:21 +03:00
if ( result . is_error ( ) )
return result . error ( ) ;
2021-03-15 21:56:13 +02:00
m_master_tls_region = result . value ( ) . tls_region ;
m_master_tls_size = result . value ( ) . tls_size ;
m_master_tls_alignment = result . value ( ) . tls_alignment ;
2020-12-25 15:23:35 +01:00
return result ;
2020-10-10 12:13:21 +03:00
}
2020-07-30 23:38:15 +02:00
2021-05-10 16:16:05 +02:00
auto interpreter_load_result = load_elf_object ( new_space . release_nonnull ( ) , * interpreter_description , load_offset . value ( ) , ShouldAllocateTls : : No , ShouldAllowSyscalls : : Yes ) ;
2021-01-02 21:31:01 +00:00
2020-10-10 12:13:21 +03:00
if ( interpreter_load_result . is_error ( ) )
return interpreter_load_result . error ( ) ;
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-02-23 20:42:32 +01:00
VERIFY ( ! interpreter_load_result . value ( ) . tls_region ) ;
VERIFY ( ! interpreter_load_result . value ( ) . tls_alignment ) ;
VERIFY ( ! interpreter_load_result . value ( ) . 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
2021-06-28 17:24:08 +02:00
KResult Process : : do_exec ( NonnullRefPtr < FileDescription > main_program_description , Vector < String > arguments , Vector < String > environment ,
RefPtr < FileDescription > 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 ( ) ) ;
VERIFY ( ! Processor : : current ( ) . in_critical ( ) ) ;
2020-10-10 12:13:21 +03:00
auto path = main_program_description - > 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
auto parts = path . split ( ' / ' ) ;
if ( parts . is_empty ( ) )
2021-02-18 08:51:06 +01:00
return ENOENT ;
2020-07-30 23:38:15 +02:00
2021-02-08 15:45:40 +01:00
auto main_program_metadata = main_program_description - > metadata ( ) ;
2020-12-20 18:35:29 +01:00
2021-02-08 15:45:40 +01:00
auto load_result_or_error = load ( main_program_description , interpreter_description , main_program_header ) ;
if ( load_result_or_error . is_error ( ) ) {
2021-02-18 08:51:06 +01:00
dbgln ( " do_exec: Failed to load main program or interpreter for {} " , path ) ;
2021-02-08 15:45:40 +01:00
return load_result_or_error . error ( ) ;
}
2020-12-20 18:35:29 +01:00
2021-02-14 00:53:53 +01:00
auto signal_trampoline_range = load_result_or_error . value ( ) . space - > allocate_range ( { } , PAGE_SIZE ) ;
if ( ! signal_trampoline_range . has_value ( ) ) {
dbgln ( " do_exec: Failed to allocate VM for signal trampoline " ) ;
2021-02-18 08:51:06 +01:00
return ENOMEM ;
2021-02-14 00:53:53 +01:00
}
2021-02-08 15:45:40 +01:00
// We commit to the new executable at this point. There is no turning back!
2020-12-20 18:35:29 +01:00
2021-02-08 23:01:53 +01:00
// Prevent other processes from attaching to us with ptrace while we're doing this.
2021-07-18 01:13:34 +02:00
MutexLocker ptrace_locker ( ptrace_lock ( ) ) ;
2021-02-08 23:01:53 +01:00
2021-02-08 15:45:40 +01:00
// Disable profiling temporarily in case it's running on this process.
2021-05-23 22:16:30 +02:00
auto was_profiling = m_profiling ;
2021-02-08 15:45:40 +01:00
TemporaryChange profiling_disabler ( m_profiling , false ) ;
2020-12-20 18:35:29 +01:00
2021-02-08 15:45:40 +01:00
kill_threads_except_self ( ) ;
2020-12-20 18:35:29 +01:00
2021-02-08 15:45:40 +01:00
auto & load_result = load_result_or_error . value ( ) ;
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 ) ) {
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 ;
2021-03-11 13:13:05 +01:00
ProtectedDataMutationScope scope { * this } ;
m_euid = main_program_metadata . uid ;
m_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 ;
2021-03-11 13:13:05 +01:00
ProtectedDataMutationScope scope { * this } ;
m_egid = main_program_metadata . gid ;
m_sgid = main_program_metadata . gid ;
2020-12-25 18:27:42 +01:00
}
2020-12-20 18:35:29 +01:00
}
2021-02-08 19:15:42 +01:00
set_dumpable ( ! executable_is_setid ) ;
2021-05-13 13:09:00 +02:00
{
// We must disable global profiling (especially kfree tracing) here because
// we might otherwise end up walking the stack into the process' space that
// is about to be destroyed.
TemporaryChange global_profiling_disabler ( g_profiling_all_threads , false ) ;
m_space = load_result . space . release_nonnull ( ) ;
}
2021-02-08 15:45:40 +01:00
MemoryManager : : enter_space ( * m_space ) ;
2020-10-10 12:13:21 +03:00
2021-02-14 00:53:53 +01:00
auto signal_trampoline_region = m_space - > allocate_region_with_vmobject ( signal_trampoline_range . value ( ) , g_signal_trampoline_region - > vmobject ( ) , 0 , " Signal trampoline " , PROT_READ | PROT_EXEC , true ) ;
if ( signal_trampoline_region . is_error ( ) ) {
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-02-14 00:53:53 +01:00
}
signal_trampoline_region . value ( ) - > set_syscall_region ( true ) ;
2020-07-30 23:38:15 +02:00
m_executable = main_program_description - > custody ( ) ;
2021-01-15 20:21:03 +01:00
m_arguments = arguments ;
m_environment = environment ;
2020-07-30 23:38:15 +02:00
m_veil_state = VeilState : : None ;
m_unveiled_paths . clear ( ) ;
2021-06-06 23:23:00 +02:00
m_unveiled_paths . set_metadata ( { " / " , UnveilAccess : : None , false } ) ;
2020-07-30 23:38:15 +02:00
2021-01-23 09:41:11 +01:00
m_coredump_metadata . clear ( ) ;
2021-02-08 15:45:40 +01:00
auto current_thread = Thread : : current ( ) ;
2020-09-08 20:37:15 -06:00
current_thread - > clear_signals ( ) ;
2020-07-30 23:38:15 +02:00
2020-12-21 23:21:58 -07:00
clear_futex_queues_on_exec ( ) ;
2020-07-30 23:38:15 +02:00
2021-06-22 21:22:17 +03:00
fds ( ) . change_each ( [ & ] ( auto & file_description_metadata ) {
if ( file_description_metadata . is_valid ( ) & & file_description_metadata . flags ( ) & FD_CLOEXEC )
file_description_metadata = { } ;
} ) ;
2020-07-30 23:38:15 +02:00
2020-12-25 15:23:35 +01:00
int main_program_fd = - 1 ;
2020-10-10 12:13:21 +03:00
if ( interpreter_description ) {
2021-07-27 23:59:24 -07:00
auto main_program_fd_wrapper = m_fds . allocate ( ) . release_value ( ) ;
VERIFY ( main_program_fd_wrapper . fd > = 0 ) ;
2021-03-19 10:43:58 +01:00
auto seek_result = main_program_description - > seek ( 0 , SEEK_SET ) ;
VERIFY ( ! seek_result . is_error ( ) ) ;
2020-10-10 12:13:21 +03:00
main_program_description - > set_readable ( true ) ;
2021-07-27 23:59:24 -07:00
m_fds [ main_program_fd_wrapper . fd ] . set ( move ( main_program_description ) , FD_CLOEXEC ) ;
main_program_fd = main_program_fd_wrapper . fd ;
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
2021-03-10 19:59:46 +01:00
auto auxv = generate_auxiliary_vector ( load_result . load_base , load_result . entry_eip , uid ( ) , euid ( ) , gid ( ) , egid ( ) , path , main_program_fd ) ;
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-06-28 17:42:29 +02:00
auto make_stack_result = make_userspace_context_for_main_thread ( new_main_thread - > regs ( ) , * load_result . stack_region . unsafe_ptr ( ) , move ( arguments ) , move ( environment ) , move ( auxv ) ) ;
2020-09-16 18:47:47 +01:00
if ( make_stack_result . is_error ( ) )
return make_stack_result . error ( ) ;
2021-06-28 17:42:29 +02:00
FlatPtr new_userspace_sp = make_stack_result . value ( ) ;
2020-07-30 23:38:15 +02:00
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-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().
Processor : : current ( ) . enter_critical ( prev_flags ) ;
// NOTE: Be careful to not trigger any page faults below!
m_name = parts . take_last ( ) ;
2021-08-05 22:22:26 +02:00
new_main_thread - > set_name ( KString : : try_create ( m_name ) ) ;
2020-07-30 23:38:15 +02:00
2021-03-10 22:50:00 +01:00
{
2021-03-11 13:13:05 +01:00
ProtectedDataMutationScope scope { * this } ;
m_promises = m_execpromises ;
m_has_promises = m_has_execpromises ;
2021-03-10 22:50:00 +01:00
2021-03-11 13:13:05 +01:00
m_execpromises = 0 ;
m_has_execpromises = false ;
2021-03-10 22:50:00 +01:00
2021-03-11 13:28:50 +01:00
m_signal_trampoline = signal_trampoline_region . value ( ) - > vaddr ( ) ;
2021-03-10 22:50:00 +01:00
// FIXME: PID/TID ISSUE
2021-03-11 13:13:05 +01:00
m_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 ;
2021-06-23 21:54:41 +02:00
# if ARCH(I386)
2021-06-26 19:57:16 +02:00
regs . cs = GDT_SELECTOR_CODE3 | 3 ;
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
2021-06-26 19:57:16 +02:00
regs . cr3 = 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-10-25 20:22:59 -06:00
{
ScopedSpinLock lock ( g_scheduler_lock ) ;
new_main_thread - > set_state ( Thread : : State : : Runnable ) ;
}
2020-12-14 16:36:22 -07:00
u32 lock_count_to_restore ;
2020-12-20 16:09:48 -07:00
[[maybe_unused]] auto rc = big_lock ( ) . force_unlock_if_locked ( lock_count_to_restore ) ;
2021-02-23 20:42:32 +01:00
VERIFY_INTERRUPTS_DISABLED ( ) ;
VERIFY ( Processor : : current ( ) . in_critical ( ) ) ;
2021-02-18 08:51:06 +01:00
return KSuccess ;
2020-07-30 23:38:15 +02:00
}
2020-12-25 15:23:35 +01:00
static Vector < ELF : : AuxiliaryValue > generate_auxiliary_vector ( FlatPtr load_base , FlatPtr entry_eip , uid_t uid , uid_t euid , gid_t gid , gid_t egid , String executable_path , int main_program_fd )
2020-07-30 23:38:15 +02:00
{
2020-12-25 14:48:30 +01:00
Vector < ELF : : AuxiliaryValue > auxv ;
2020-07-30 23:38:15 +02:00
// PHDR/EXECFD
// PH*
2020-12-25 14:48:30 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : PageSize , PAGE_SIZE } ) ;
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : BaseAddress , ( void * ) load_base } ) ;
2020-10-10 12:13:21 +03:00
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : Entry , ( void * ) entry_eip } ) ;
2020-07-30 23:38:15 +02:00
// NOTELF
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : Uid , ( long ) uid } ) ;
auxv . append ( { ELF : : AuxiliaryValue : : EUid , ( long ) euid } ) ;
auxv . append ( { ELF : : AuxiliaryValue : : Gid , ( long ) gid } ) ;
auxv . append ( { ELF : : AuxiliaryValue : : EGid , ( long ) egid } ) ;
2020-07-30 23:38:15 +02:00
2021-02-21 07:58:57 -08:00
auxv . append ( { ELF : : AuxiliaryValue : : Platform , Processor : : current ( ) . platform_string ( ) } ) ;
2020-07-30 23:38:15 +02:00
// FIXME: This is platform specific
2020-12-25 14:48:30 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : HwCap , ( long ) CPUID ( 1 ) . edx ( ) } ) ;
2020-07-30 23:38:15 +02:00
2020-12-25 14:48:30 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : ClockTick , ( long ) TimeManagement : : the ( ) . ticks_per_second ( ) } ) ;
2020-07-30 23:38:15 +02:00
// FIXME: Also take into account things like extended filesystem permissions? That's what linux does...
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : Secure , ( ( uid ! = euid ) | | ( gid ! = egid ) ) ? 1 : 0 } ) ;
2020-07-30 23:38:15 +02:00
char random_bytes [ 16 ] { } ;
get_fast_random_bytes ( ( u8 * ) random_bytes , sizeof ( random_bytes ) ) ;
2020-12-25 14:48:30 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : Random , String ( random_bytes , sizeof ( random_bytes ) ) } ) ;
2020-07-30 23:38:15 +02:00
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : ExecFilename , executable_path } ) ;
2020-07-30 23:38:15 +02:00
2020-12-25 15:23:35 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : ExecFileDescriptor , main_program_fd } ) ;
2020-10-10 12:13:21 +03:00
2020-12-25 14:48:30 +01:00
auxv . append ( { ELF : : AuxiliaryValue : : Null , 0L } ) ;
2020-07-30 23:38:15 +02:00
return auxv ;
}
static KResultOr < Vector < String > > find_shebang_interpreter_for_executable ( const char first_page [ ] , int nread )
{
int word_start = 2 ;
int word_length = 0 ;
if ( nread > 2 & & first_page [ 0 ] = = ' # ' & & first_page [ 1 ] = = ' ! ' ) {
Vector < String > interpreter_words ;
for ( int i = 2 ; i < nread ; + + i ) {
if ( first_page [ i ] = = ' \n ' ) {
break ;
}
if ( first_page [ i ] ! = ' ' ) {
+ + word_length ;
}
if ( first_page [ i ] = = ' ' ) {
if ( word_length > 0 ) {
interpreter_words . append ( String ( & first_page [ word_start ] , word_length ) ) ;
}
word_length = 0 ;
word_start = i + 1 ;
}
}
if ( word_length > 0 )
interpreter_words . append ( String ( & first_page [ word_start ] , word_length ) ) ;
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
}
2021-06-28 17:24:08 +02:00
KResultOr < RefPtr < FileDescription > > Process : : find_elf_interpreter_for_executable ( const String & path , const ElfW ( Ehdr ) & main_program_header , int nread , size_t file_size )
2020-07-30 23:38:15 +02:00
{
// Not using KResultOr here because we'll want to do the same thing in userspace in the RTLD
String interpreter_path ;
2021-01-10 21:07:08 +02:00
if ( ! ELF : : validate_program_headers ( main_program_header , file_size , ( const u8 * ) & main_program_header , nread , & interpreter_path ) ) {
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
}
if ( ! interpreter_path . is_empty ( ) ) {
2021-02-18 08:51:06 +01:00
dbgln_if ( EXEC_DEBUG , " exec({}): Using program interpreter {} " , path , interpreter_path ) ;
2021-07-11 00:25:24 +02:00
auto interp_result = VirtualFileSystem : : the ( ) . open ( interpreter_path , O_EXEC , 0 , current_directory ( ) ) ;
2020-07-30 23:38:15 +02:00
if ( interp_result . is_error ( ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " exec({}): Unable to open program interpreter {} " , path , interpreter_path ) ;
2020-07-30 23:38:15 +02:00
return interp_result . error ( ) ;
}
auto interpreter_description = interp_result . value ( ) ;
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 ) ;
auto nread_or_error = interpreter_description - > read ( first_page_buffer , sizeof ( first_page ) ) ;
2020-08-04 18:02:23 +02:00
if ( nread_or_error . is_error ( ) )
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-08-04 18:02:23 +02:00
nread = nread_or_error . value ( ) ;
2020-07-30 23:38:15 +02:00
2021-06-28 17:24:08 +02:00
if ( nread < ( int ) sizeof ( ElfW ( Ehdr ) ) )
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
2021-06-28 17:24:08 +02: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 ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " exec({}): Interpreter ({}) has invalid ELF header " , path , interpreter_description - > absolute_path ( ) ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
// Not using KResultOr here because we'll want to do the same thing in userspace in the RTLD
String interpreter_interpreter_path ;
2020-11-30 23:21:55 -07:00
if ( ! ELF : : validate_program_headers ( * elf_header , interp_metadata . size , ( u8 * ) first_page , nread , & interpreter_interpreter_path ) ) {
2020-12-25 12:51:35 +01:00
dbgln ( " exec({}): Interpreter ({}) has invalid ELF Program headers " , path , interpreter_description - > absolute_path ( ) ) ;
2021-01-20 23:11:17 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
}
2020-12-31 17:51:21 -07:00
if ( ! interpreter_interpreter_path . is_empty ( ) ) {
dbgln ( " exec({}): Interpreter ({}) has its own interpreter ({})! No thank you! " , path , interpreter_description - > absolute_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-01-10 21:07:08 +02:00
if ( main_program_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-01-10 21:07:08 +02:00
if ( main_program_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
return KResult ( KSuccess ) ;
}
2021-02-18 08:51:06 +01:00
KResult Process : : exec ( String path , Vector < String > arguments , Vector < String > environment , 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
//
2021-07-11 00:25:24 +02:00
auto file_or_error = VirtualFileSystem : : the ( ) . open ( path , O_EXEC , 0 , current_directory ( ) ) ;
2021-02-18 08:51:06 +01:00
if ( file_or_error . is_error ( ) )
return file_or_error . error ( ) ;
auto description = file_or_error . release_value ( ) ;
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 ) ;
auto nread_or_error = description - > read ( first_page_buffer , sizeof ( first_page ) ) ;
2020-08-04 18:02:23 +02:00
if ( nread_or_error . is_error ( ) )
2021-02-18 08:51:06 +01:00
return ENOEXEC ;
2020-07-30 23:38:15 +02:00
// 1) #! interpreted file
2020-08-04 18:02:23 +02:00
auto shebang_result = find_shebang_interpreter_for_executable ( first_page , nread_or_error . value ( ) ) ;
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 ( ) ;
auto shebang_path = shebang_words . first ( ) ;
2021-06-13 17:20:56 +02:00
arguments [ 0 ] = move ( path ) ;
2021-06-06 01:13:25 +02:00
if ( ! arguments . try_prepend ( move ( shebang_words ) ) )
return ENOMEM ;
2021-06-13 17:20:35 +02:00
return exec ( move ( shebang_path ) , move ( arguments ) , move ( environment ) , + + recursion_depth ) ;
2020-07-30 23:38:15 +02:00
}
// #2) ELF32 for i386
2021-01-10 21:07:08 +02:00
2021-06-28 17:24:08 +02:00
if ( nread_or_error . value ( ) < ( int ) sizeof ( ElfW ( Ehdr ) ) )
2021-02-18 08:51:06 +01:00
return ENOEXEC ;
2021-06-28 17:24:08 +02:00
auto 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
}
auto elf_result = find_elf_interpreter_for_executable ( path , * main_program_header , nread_or_error . value ( ) , metadata . size ) ;
2021-01-02 21:31:01 +00:00
// Assume a static ELF executable by default
2020-07-30 23:38:15 +02:00
RefPtr < FileDescription > interpreter_description ;
// We're getting either an interpreter, an error, or KSuccess (i.e. no interpreter but file checks out)
2021-01-02 21:31:01 +00:00
if ( ! elf_result . is_error ( ) ) {
// It's a dynamic ELF executable, with or without an interpreter. Do not allocate TLS
2020-07-30 23:38:15 +02:00
interpreter_description = elf_result . value ( ) ;
2021-01-02 21:31:01 +00:00
} else if ( elf_result . error ( ) . is_error ( ) )
2020-07-30 23:38:15 +02:00
return elf_result . error ( ) ;
// The bulk of exec() is done by do_exec(), which ensures that all locals
// are cleaned up by the time we yield-teleport below.
Thread * new_main_thread = nullptr ;
u32 prev_flags = 0 ;
2021-02-18 08:51:06 +01:00
auto result = do_exec ( move ( description ) , move ( arguments ) , move ( environment ) , move ( interpreter_description ) , new_main_thread , prev_flags , * main_program_header ) ;
if ( result . is_error ( ) )
return result ;
2020-07-30 23:38:15 +02:00
2021-02-23 20:42:32 +01:00
VERIFY_INTERRUPTS_DISABLED ( ) ;
VERIFY ( Processor : : current ( ) . in_critical ( ) ) ;
2020-07-30 23:38:15 +02:00
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
2021-02-23 20:42:32 +01:00
VERIFY ( ! g_scheduler_lock . own_lock ( ) ) ;
VERIFY ( Processor : : current ( ) . in_critical ( ) = = 1 ) ;
2020-07-30 23:38:15 +02:00
g_scheduler_lock . lock ( ) ;
current_thread - > set_state ( Thread : : State : : Running ) ;
Processor : : assume_context ( * current_thread , prev_flags ) ;
2021-02-23 20:42:32 +01:00
VERIFY_NOT_REACHED ( ) ;
2020-07-30 23:38:15 +02:00
}
Processor : : current ( ) . leave_critical ( prev_flags ) ;
2021-02-18 08:51:06 +01:00
return KSuccess ;
2020-07-30 23:38:15 +02:00
}
2021-06-28 20:59:35 +02:00
KResultOr < FlatPtr > Process : : sys $ execve ( Userspace < const Syscall : : SC_execve_params * > user_params )
2020-07-30 23:38:15 +02:00
{
2021-07-18 11:20:12 -07:00
VERIFY_PROCESS_BIG_LOCK_ACQUIRED ( this ) ;
2020-07-30 23:38:15 +02:00
REQUIRE_PROMISE ( exec ) ;
// NOTE: Be extremely careful with allocating any kernel memory in exec().
// On success, the kernel stack will be lost.
Syscall : : SC_execve_params params ;
2020-09-11 21:11:07 -06:00
if ( ! copy_from_user ( & params , user_params ) )
2021-03-01 13:49:16 +01:00
return EFAULT ;
2020-07-30 23:38:15 +02:00
if ( params . arguments . length > ARG_MAX | | params . environment . length > ARG_MAX )
2021-03-01 13:49:16 +01:00
return E2BIG ;
2020-07-30 23:38:15 +02:00
String path ;
{
auto path_arg = get_syscall_path_argument ( params . path ) ;
if ( path_arg . is_error ( ) )
return path_arg . error ( ) ;
2021-05-29 16:59:40 +02:00
path = path_arg . value ( ) - > view ( ) ;
2020-07-30 23:38:15 +02:00
}
2020-09-28 22:24:27 +02:00
auto copy_user_strings = [ ] ( const auto & list , auto & output ) {
2020-07-30 23:38:15 +02:00
if ( ! list . length )
return true ;
2021-07-04 20:23:26 +03:00
Checked < size_t > size = sizeof ( * list . strings ) ;
2020-09-11 21:11:07 -06:00
size * = list . length ;
if ( size . has_overflow ( ) )
2020-07-30 23:38:15 +02:00
return false ;
Vector < Syscall : : StringArgument , 32 > strings ;
2021-04-29 01:40:19 -07:00
if ( ! strings . try_resize ( list . length ) )
return false ;
2021-07-04 20:23:26 +03:00
if ( ! copy_from_user ( strings . data ( ) , list . strings , size . value ( ) ) )
2020-09-11 21:11:07 -06:00
return false ;
2020-07-30 23:38:15 +02:00
for ( size_t i = 0 ; i < list . length ; + + i ) {
2020-09-11 21:11:07 -06:00
auto string = copy_string_from_user ( strings [ i ] ) ;
2020-07-30 23:38:15 +02:00
if ( string . is_null ( ) )
return false ;
2021-04-29 01:40:19 -07:00
if ( ! output . try_append ( move ( string ) ) )
return false ;
2020-07-30 23:38:15 +02:00
}
return true ;
} ;
Vector < String > arguments ;
if ( ! copy_user_strings ( params . arguments , arguments ) )
2021-03-01 13:49:16 +01:00
return EFAULT ;
2020-07-30 23:38:15 +02:00
Vector < String > environment ;
if ( ! copy_user_strings ( params . environment , environment ) )
2021-03-01 13:49:16 +01:00
return EFAULT ;
2020-07-30 23:38:15 +02:00
2021-02-18 08:51:06 +01:00
auto result = exec ( move ( path ) , move ( arguments ) , move ( environment ) ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( result . is_error ( ) ) ; // We should never continue after a successful exec!
2021-02-18 08:51:06 +01:00
return result . error ( ) ;
2020-07-30 23:38:15 +02:00
}
2020-10-10 12:13:21 +03:00
2020-07-30 23:38:15 +02:00
}