diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 174781592d..6df64da6a8 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -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 __dlclose(void* handle); static Result __dlopen(char const* filename, int flags); @@ -339,6 +341,25 @@ static NonnullRefPtrVector 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 link_main_library(String const& name, int flags) { auto loaders = collect_loaders_for_library(name); @@ -375,6 +396,8 @@ static Result 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()) diff --git a/Userland/Utilities/pledge.cpp b/Userland/Utilities/pledge.cpp index d54892dbab..5d4b5e4653 100644 --- a/Userland/Utilities/pledge.cpp +++ b/Userland/Utilities/pledge.cpp @@ -5,19 +5,42 @@ */ #include +#include #include +#include #include +static ErrorOr 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 serenity_main(Main::Arguments arguments) { - StringView promises; + String promises; Vector 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;