serenity/Userland/Utilities/pledge.cpp
Itamar db11cfa2c5 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.
2022-07-21 16:40:11 +02:00

47 lines
1.7 KiB
C++

/*
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#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)
{
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;
}