Serenity Operating System
at master 150 lines 5.5 kB view raw
1/* 2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/DeprecatedString.h> 8#include <AK/LexicalPath.h> 9#include <AK/StringBuilder.h> 10#include <AK/StringView.h> 11#include <LibCore/ArgsParser.h> 12#include <LibCore/MappedFile.h> 13#include <LibCore/System.h> 14#include <LibELF/DynamicLinker.h> 15#include <LibELF/DynamicLoader.h> 16#include <LibELF/DynamicObject.h> 17#include <LibELF/Image.h> 18#include <LibELF/Validation.h> 19#include <LibMain/Main.h> 20#include <ctype.h> 21#include <fcntl.h> 22#include <stdio.h> 23#include <unistd.h> 24 25static Vector<DeprecatedString> found_libraries; 26 27static ErrorOr<void> recusively_resolve_all_necessary_libraries(StringView interpreter_path, size_t recursive_iteration_max, size_t recursive_iteration, ELF::DynamicObject& object) 28{ 29 if (recursive_iteration > recursive_iteration_max) 30 return ELOOP; 31 32 Vector<DeprecatedString> libraries; 33 object.for_each_needed_library([&libraries](StringView entry) { 34 libraries.append(DeprecatedString::formatted("{}", entry)); 35 }); 36 for (auto& library_name : libraries) { 37 auto possible_library_path = ELF::DynamicLinker::resolve_library(library_name, object); 38 if (!possible_library_path.has_value()) 39 continue; 40 auto library_path = LexicalPath::absolute_path(TRY(Core::System::getcwd()), possible_library_path.value()); 41 if (found_libraries.contains_slow(library_path)) 42 continue; 43 auto file = TRY(Core::MappedFile::map(library_path)); 44 45 auto elf_image_data = file->bytes(); 46 ELF::Image elf_image(elf_image_data); 47 if (!elf_image.is_valid()) { 48 outln("Shared library is not valid ELF: {}", library_path); 49 continue; 50 } 51 if (!elf_image.is_dynamic()) { 52 outln("Shared library is not dynamic loaded object: {}", library_path); 53 continue; 54 } 55 56 int fd = TRY(Core::System::open(library_path, O_RDONLY)); 57 auto result = ELF::DynamicLoader::try_create(fd, library_path); 58 if (result.is_error()) { 59 outln("{}", result.error().text); 60 continue; 61 } 62 auto& loader = result.value(); 63 if (!loader->is_valid()) { 64 outln("{} is not a valid ELF dynamic shared object!", library_path); 65 continue; 66 } 67 68 RefPtr<ELF::DynamicObject> library_object = loader->map(); 69 if (!library_object) { 70 outln("Failed to map dynamic ELF object {}", library_path); 71 continue; 72 } 73 outln("{} => {}", library_name, library_path); 74 recursive_iteration++; 75 found_libraries.append(library_path); 76 TRY(recusively_resolve_all_necessary_libraries(interpreter_path, recursive_iteration_max, recursive_iteration, *library_object)); 77 } 78 return {}; 79} 80 81ErrorOr<int> serenity_main(Main::Arguments arguments) 82{ 83 TRY(Core::System::pledge("stdio rpath")); 84 85 DeprecatedString path {}; 86 Optional<size_t> recursive_iteration_max; 87 bool force_without_valid_interpreter = false; 88 89 Core::ArgsParser args_parser; 90 args_parser.add_option(recursive_iteration_max, "Max library resolving recursion", "max-recursion", 'r', "max recursion-level"); 91 args_parser.add_option(force_without_valid_interpreter, "Force library resolving on ELF object without valid interpreter", "force-without-valid-interpreter", 'f'); 92 args_parser.add_positional_argument(path, "ELF path", "path"); 93 args_parser.parse(arguments); 94 95 path = LexicalPath::absolute_path(TRY(Core::System::getcwd()), path); 96 97 auto file_or_error = Core::MappedFile::map(path); 98 99 if (file_or_error.is_error()) { 100 warnln("Unable to map file {}: {}", path, file_or_error.error()); 101 return -1; 102 } 103 104 auto elf_image_data = file_or_error.value()->bytes(); 105 ELF::Image elf_image(elf_image_data); 106 107 if (!elf_image.is_valid()) { 108 warnln("File is not a valid ELF object"); 109 return -1; 110 } 111 112 StringBuilder interpreter_path_builder; 113 auto result_or_error = ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_image_data.data(), elf_image_data.size(), elf_image_data, &interpreter_path_builder); 114 if (result_or_error.is_error() || !result_or_error.value()) { 115 warnln("Invalid ELF headers"); 116 return -1; 117 } 118 auto interpreter_path = interpreter_path_builder.string_view(); 119 120 RefPtr<ELF::DynamicObject> object = nullptr; 121 if (elf_image.is_dynamic()) { 122 if (interpreter_path != "/usr/lib/Loader.so"sv && !force_without_valid_interpreter) { 123 warnln("ELF interpreter image is invalid"); 124 return 1; 125 } 126 127 int fd = TRY(Core::System::open(path, O_RDONLY)); 128 auto result = ELF::DynamicLoader::try_create(fd, path); 129 if (result.is_error()) { 130 outln("{}", result.error().text); 131 return 1; 132 } 133 auto& loader = result.value(); 134 if (!loader->is_valid()) { 135 outln("{} is not a valid ELF dynamic shared object!", path); 136 return 1; 137 } 138 139 object = loader->map(); 140 if (!object) { 141 outln("Failed to map dynamic ELF object {}", path); 142 return 1; 143 } 144 TRY(recusively_resolve_all_necessary_libraries(interpreter_path, recursive_iteration_max.value_or(10), 0, *object)); 145 } else { 146 outln("ELF program is not dynamic loaded!"); 147 return 1; 148 } 149 return 0; 150}