Serenity Operating System
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}