mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:34:59 +00:00
Utilities+LibELF: Temporary promises for dynamic linker in "pledge"
This adds a "temporary promises for the dynamic-linker" flag ('-d') to the "pledge" utility. Example usage: pledge -d -p "stdio rpath" id Without the '-d' flag, id would crash because the dynamic linker requires 'prot_exec'. When this flag is used and the program to be run is dynamically linked, "pledge" adds promises that are required by the dynamic linker to the promise set provided by the user. The dynamic linker will later "give up" the pledge promises it no longer requires.
This commit is contained in:
parent
91a03bc6ae
commit
db11cfa2c5
2 changed files with 60 additions and 1 deletions
|
@ -55,6 +55,8 @@ static __pthread_mutex_t s_loader_lock = __PTHREAD_MUTEX_INITIALIZER;
|
|||
static bool s_allowed_to_check_environment_variables { false };
|
||||
static bool s_do_breakpoint_trap_before_entry { false };
|
||||
static StringView s_ld_library_path;
|
||||
static StringView s_main_program_pledge_promises;
|
||||
static String s_loader_pledge_promises;
|
||||
|
||||
static Result<void, DlErrorMessage> __dlclose(void* handle);
|
||||
static Result<void*, DlErrorMessage> __dlopen(char const* filename, int flags);
|
||||
|
@ -339,6 +341,25 @@ static NonnullRefPtrVector<DynamicLoader> collect_loaders_for_library(String con
|
|||
return loaders;
|
||||
}
|
||||
|
||||
static void drop_loader_promise(StringView promise_to_drop)
|
||||
{
|
||||
if (s_main_program_pledge_promises.is_empty() || s_loader_pledge_promises.is_empty())
|
||||
return;
|
||||
|
||||
s_loader_pledge_promises = s_loader_pledge_promises.replace(promise_to_drop, ""sv, ReplaceMode::All);
|
||||
|
||||
auto extended_promises = String::formatted("{} {}", s_main_program_pledge_promises, s_loader_pledge_promises);
|
||||
Syscall::SC_pledge_params params {
|
||||
{ extended_promises.characters(), extended_promises.length() },
|
||||
{ nullptr, 0 },
|
||||
};
|
||||
int rc = syscall(SC_pledge, ¶ms);
|
||||
if (rc < 0 && rc > -EMAXERRNO) {
|
||||
warnln("Failed to drop loader pledge promise: {}. errno={}", promise_to_drop, errno);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void, DlErrorMessage> link_main_library(String const& name, int flags)
|
||||
{
|
||||
auto loaders = collect_loaders_for_library(name);
|
||||
|
@ -375,6 +396,8 @@ static Result<void, DlErrorMessage> link_main_library(String const& name, int fl
|
|||
}
|
||||
}
|
||||
|
||||
drop_loader_promise("prot_exec"sv);
|
||||
|
||||
for (auto& loader : loaders) {
|
||||
loader.load_stage_4();
|
||||
}
|
||||
|
@ -562,6 +585,16 @@ static void read_environment_variables()
|
|||
if (env_string.starts_with(library_path_string)) {
|
||||
s_ld_library_path = env_string.substring_view(library_path_string.length());
|
||||
}
|
||||
|
||||
constexpr auto main_pledge_promises_key = "_LOADER_MAIN_PROGRAM_PLEDGE_PROMISES="sv;
|
||||
if (env_string.starts_with(main_pledge_promises_key)) {
|
||||
s_main_program_pledge_promises = env_string.substring_view(main_pledge_promises_key.length());
|
||||
}
|
||||
|
||||
constexpr auto loader_pledge_promises_key = "_LOADER_PLEDGE_PROMISES="sv;
|
||||
if (env_string.starts_with(loader_pledge_promises_key)) {
|
||||
s_loader_pledge_promises = env_string.substring_view(loader_pledge_promises_key.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,6 +641,9 @@ void ELF::DynamicLinker::linker_main(String&& main_program_name, int main_progra
|
|||
warnln("{}", result.error().text);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
drop_loader_promise("rpath"sv);
|
||||
|
||||
auto& main_executable_loader = *s_loaders.get(library_name);
|
||||
auto entry_point = main_executable_loader->image().entry();
|
||||
if (main_executable_loader->is_dynamic())
|
||||
|
|
|
@ -5,19 +5,42 @@
|
|||
*/
|
||||
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/MappedFile.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibELF/Image.h>
|
||||
#include <LibMain/Main.h>
|
||||
|
||||
static ErrorOr<bool> is_dynamically_linked_executable(StringView filename)
|
||||
{
|
||||
String exec_filename = filename;
|
||||
if (!filename.contains('/')) {
|
||||
exec_filename = TRY(Core::System::find_file_in_path(filename));
|
||||
}
|
||||
|
||||
auto file = TRY(Core::MappedFile::map(exec_filename));
|
||||
ELF::Image elf_image(file->bytes());
|
||||
return elf_image.is_dynamic();
|
||||
}
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
StringView promises;
|
||||
String promises;
|
||||
Vector<StringView> command;
|
||||
bool add_promises_for_dynamic_linker;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(promises, "Space-separated list of pledge promises", "promises", 'p', "promises");
|
||||
args_parser.add_option(add_promises_for_dynamic_linker, "Add temporary promises for dynamic linker", "dynamic-linker-promises", 'd');
|
||||
args_parser.add_positional_argument(command, "Command to execute", "command");
|
||||
args_parser.parse(arguments);
|
||||
|
||||
if (add_promises_for_dynamic_linker && TRY(is_dynamically_linked_executable(command[0]))) {
|
||||
auto constexpr loader_promises = "stdio rpath prot_exec"sv;
|
||||
MUST(Core::System::setenv("_LOADER_PLEDGE_PROMISES"sv, loader_promises, true));
|
||||
MUST(Core::System::setenv("_LOADER_MAIN_PROGRAM_PLEDGE_PROMISES"sv, promises, true));
|
||||
promises = String::formatted("{} {}", promises, loader_promises);
|
||||
}
|
||||
|
||||
TRY(Core::System::pledge(StringView(), promises));
|
||||
TRY(Core::System::exec(command[0], command.span(), Core::System::SearchInPath::Yes));
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue