2022-12-18 09:52:22 -05:00
/*
* Copyright ( c ) 2022 , Liav A . < liavalb @ hotmail . co . il >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2023-12-16 09:19:34 -05:00
# include <AK/ByteString.h>
2022-12-18 09:52:22 -05:00
# include <AK/LexicalPath.h>
# include <AK/StringBuilder.h>
# include <AK/StringView.h>
# include <LibCore/ArgsParser.h>
# include <LibCore/MappedFile.h>
# include <LibCore/System.h>
# include <LibELF/DynamicLinker.h>
# include <LibELF/DynamicLoader.h>
# include <LibELF/DynamicObject.h>
# include <LibELF/Image.h>
# include <LibELF/Validation.h>
# include <LibMain/Main.h>
# include <ctype.h>
# include <fcntl.h>
# include <stdio.h>
# include <unistd.h>
2023-12-16 09:19:34 -05:00
static Vector < ByteString > found_libraries ;
2022-12-18 09:52:22 -05:00
2024-08-03 02:55:54 -04:00
static ErrorOr < void > recusively_resolve_all_necessary_libraries ( StringView interpreter_path , bool path_only_formatting , size_t recursive_iteration_max , size_t recursive_iteration , ELF : : DynamicObject & object )
2022-12-18 09:52:22 -05:00
{
if ( recursive_iteration > recursive_iteration_max )
return ELOOP ;
2023-12-16 09:19:34 -05:00
Vector < ByteString > libraries ;
2022-12-18 09:52:22 -05:00
object . for_each_needed_library ( [ & libraries ] ( StringView entry ) {
2023-12-16 09:19:34 -05:00
libraries . append ( ByteString : : formatted ( " {} " , entry ) ) ;
2022-12-18 09:52:22 -05:00
} ) ;
for ( auto & library_name : libraries ) {
auto possible_library_path = ELF : : DynamicLinker : : resolve_library ( library_name , object ) ;
if ( ! possible_library_path . has_value ( ) )
continue ;
auto library_path = LexicalPath : : absolute_path ( TRY ( Core : : System : : getcwd ( ) ) , possible_library_path . value ( ) ) ;
if ( found_libraries . contains_slow ( library_path ) )
continue ;
auto file = TRY ( Core : : MappedFile : : map ( library_path ) ) ;
auto elf_image_data = file - > bytes ( ) ;
ELF : : Image elf_image ( elf_image_data ) ;
if ( ! elf_image . is_valid ( ) ) {
outln ( " Shared library is not valid ELF: {} " , library_path ) ;
continue ;
}
if ( ! elf_image . is_dynamic ( ) ) {
outln ( " Shared library is not dynamic loaded object: {} " , library_path ) ;
continue ;
}
int fd = TRY ( Core : : System : : open ( library_path , O_RDONLY ) ) ;
auto result = ELF : : DynamicLoader : : try_create ( fd , library_path ) ;
if ( result . is_error ( ) ) {
outln ( " {} " , result . error ( ) . text ) ;
continue ;
}
auto & loader = result . value ( ) ;
if ( ! loader - > is_valid ( ) ) {
outln ( " {} is not a valid ELF dynamic shared object! " , library_path ) ;
continue ;
}
RefPtr < ELF : : DynamicObject > library_object = loader - > map ( ) ;
if ( ! library_object ) {
outln ( " Failed to map dynamic ELF object {} " , library_path ) ;
continue ;
}
2024-08-03 02:55:54 -04:00
if ( path_only_formatting )
outln ( " {} " , library_path ) ;
else
outln ( " {} => {} " , library_name , library_path ) ;
2022-12-18 09:52:22 -05:00
recursive_iteration + + ;
found_libraries . append ( library_path ) ;
2024-08-03 02:55:54 -04:00
TRY ( recusively_resolve_all_necessary_libraries ( interpreter_path , path_only_formatting , recursive_iteration_max , recursive_iteration , * library_object ) ) ;
2022-12-18 09:52:22 -05:00
}
return { } ;
}
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
2023-04-17 06:26:58 -04:00
TRY ( Core : : System : : pledge ( " stdio rpath map_fixed " ) ) ;
2022-12-18 09:52:22 -05:00
2023-12-16 09:19:34 -05:00
ByteString path { } ;
2022-12-18 09:52:22 -05:00
Optional < size_t > recursive_iteration_max ;
bool force_without_valid_interpreter = false ;
2024-08-03 02:55:54 -04:00
bool path_only_formatting = false ;
2022-12-18 09:52:22 -05:00
Core : : ArgsParser args_parser ;
args_parser . add_option ( recursive_iteration_max , " Max library resolving recursion " , " max-recursion " , ' r ' , " max recursion-level " ) ;
2024-08-03 02:55:54 -04:00
args_parser . add_option ( path_only_formatting , " Path-only format printing " , " path-only-format " , ' s ' ) ;
2022-12-18 09:52:22 -05:00
args_parser . add_option ( force_without_valid_interpreter , " Force library resolving on ELF object without valid interpreter " , " force-without-valid-interpreter " , ' f ' ) ;
args_parser . add_positional_argument ( path , " ELF path " , " path " ) ;
args_parser . parse ( arguments ) ;
path = LexicalPath : : absolute_path ( TRY ( Core : : System : : getcwd ( ) ) , path ) ;
auto file_or_error = Core : : MappedFile : : map ( path ) ;
if ( file_or_error . is_error ( ) ) {
warnln ( " Unable to map file {}: {} " , path , file_or_error . error ( ) ) ;
return - 1 ;
}
auto elf_image_data = file_or_error . value ( ) - > bytes ( ) ;
ELF : : Image elf_image ( elf_image_data ) ;
if ( ! elf_image . is_valid ( ) ) {
warnln ( " File is not a valid ELF object " ) ;
return - 1 ;
}
2024-07-19 22:53:13 -04:00
Optional < Elf_Phdr > interpreter_path_program_header { } ;
if ( ! ELF : : validate_program_headers ( * bit_cast < Elf_Ehdr const * > ( elf_image_data . data ( ) ) , elf_image_data . size ( ) , elf_image_data , interpreter_path_program_header ) ) {
2022-12-18 09:52:22 -05:00
warnln ( " Invalid ELF headers " ) ;
return - 1 ;
}
2024-07-19 22:53:13 -04:00
StringBuilder interpreter_path_builder ;
if ( interpreter_path_program_header . has_value ( ) )
TRY ( interpreter_path_builder . try_append ( { elf_image_data . offset ( interpreter_path_program_header . value ( ) . p_offset ) , static_cast < size_t > ( interpreter_path_program_header . value ( ) . p_filesz ) - 1 } ) ) ;
2022-12-18 09:52:22 -05:00
auto interpreter_path = interpreter_path_builder . string_view ( ) ;
RefPtr < ELF : : DynamicObject > object = nullptr ;
if ( elf_image . is_dynamic ( ) ) {
if ( interpreter_path ! = " /usr/lib/Loader.so " sv & & ! force_without_valid_interpreter ) {
warnln ( " ELF interpreter image is invalid " ) ;
return 1 ;
}
int fd = TRY ( Core : : System : : open ( path , O_RDONLY ) ) ;
auto result = ELF : : DynamicLoader : : try_create ( fd , path ) ;
if ( result . is_error ( ) ) {
outln ( " {} " , result . error ( ) . text ) ;
return 1 ;
}
auto & loader = result . value ( ) ;
if ( ! loader - > is_valid ( ) ) {
outln ( " {} is not a valid ELF dynamic shared object! " , path ) ;
return 1 ;
}
object = loader - > map ( ) ;
if ( ! object ) {
outln ( " Failed to map dynamic ELF object {} " , path ) ;
return 1 ;
}
2024-08-03 02:55:54 -04:00
TRY ( recusively_resolve_all_necessary_libraries ( interpreter_path , path_only_formatting , recursive_iteration_max . value_or ( 10 ) , 0 , * object ) ) ;
2022-12-18 09:52:22 -05:00
} else {
outln ( " ELF program is not dynamic loaded! " ) ;
return 1 ;
}
return 0 ;
}