mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:37:46 +00:00
Kernel: Consolidate finding the ELF stack size with validation
Previously, we started parsing the ELF file again in a completely different place, and without the partial mapping that we do while validating. Instead of doing manual parsing in two places, just capture the requested stack size right after we validated it.
This commit is contained in:
parent
398f7ae988
commit
9d6372ff07
5 changed files with 29 additions and 49 deletions
|
@ -286,6 +286,9 @@ static ErrorOr<LoadResult> load_elf_object(Memory::AddressSpace& new_space, Open
|
||||||
FlatPtr load_base_address = 0;
|
FlatPtr load_base_address = 0;
|
||||||
size_t stack_size = Thread::default_userspace_stack_size;
|
size_t stack_size = Thread::default_userspace_stack_size;
|
||||||
|
|
||||||
|
if (minimum_stack_size.has_value() && minimum_stack_size.value() > stack_size)
|
||||||
|
stack_size = minimum_stack_size.value();
|
||||||
|
|
||||||
auto elf_name = TRY(object_description.pseudo_path());
|
auto elf_name = TRY(object_description.pseudo_path());
|
||||||
VERIFY(!Processor::in_critical());
|
VERIFY(!Processor::in_critical());
|
||||||
|
|
||||||
|
@ -380,13 +383,6 @@ static ErrorOr<LoadResult> load_elf_object(Memory::AddressSpace& new_space, Open
|
||||||
if (program_header.type() == PT_LOAD)
|
if (program_header.type() == PT_LOAD)
|
||||||
return load_section(program_header);
|
return load_section(program_header);
|
||||||
|
|
||||||
if (program_header.type() == PT_GNU_STACK) {
|
|
||||||
auto new_stack_size = program_header.size_in_memory();
|
|
||||||
|
|
||||||
if (new_stack_size > stack_size)
|
|
||||||
stack_size = new_stack_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: We ignore other program header types.
|
// NOTE: We ignore other program header types.
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
@ -405,9 +401,6 @@ static ErrorOr<LoadResult> load_elf_object(Memory::AddressSpace& new_space, Open
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minimum_stack_size.has_value() && minimum_stack_size.value() > stack_size)
|
|
||||||
stack_size = minimum_stack_size.value();
|
|
||||||
|
|
||||||
auto* stack_region = TRY(new_space.allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, stack_size, PAGE_SIZE, "Stack (Main thread)"sv, PROT_READ | PROT_WRITE, AllocationStrategy::Reserve));
|
auto* stack_region = TRY(new_space.allocate_region(Memory::RandomizeVirtualAddress::Yes, {}, stack_size, PAGE_SIZE, "Stack (Main thread)"sv, PROT_READ | PROT_WRITE, AllocationStrategy::Reserve));
|
||||||
stack_region->set_stack(true);
|
stack_region->set_stack(true);
|
||||||
|
|
||||||
|
@ -424,42 +417,19 @@ static ErrorOr<LoadResult> load_elf_object(Memory::AddressSpace& new_space, Open
|
||||||
|
|
||||||
ErrorOr<LoadResult>
|
ErrorOr<LoadResult>
|
||||||
Process::load(Memory::AddressSpace& new_space, NonnullRefPtr<OpenFileDescription> main_program_description,
|
Process::load(Memory::AddressSpace& new_space, NonnullRefPtr<OpenFileDescription> main_program_description,
|
||||||
RefPtr<OpenFileDescription> interpreter_description, const ElfW(Ehdr) & main_program_header)
|
RefPtr<OpenFileDescription> interpreter_description, const ElfW(Ehdr) & main_program_header, Optional<size_t> minimum_stack_size)
|
||||||
{
|
{
|
||||||
auto load_offset = TRY(get_load_offset(main_program_header, main_program_description, interpreter_description));
|
auto load_offset = TRY(get_load_offset(main_program_header, main_program_description, interpreter_description));
|
||||||
|
|
||||||
if (interpreter_description.is_null()) {
|
if (interpreter_description.is_null()) {
|
||||||
auto load_result = TRY(load_elf_object(new_space, main_program_description, load_offset, ShouldAllocateTls::Yes, ShouldAllowSyscalls::No));
|
auto load_result = TRY(load_elf_object(new_space, main_program_description, load_offset, ShouldAllocateTls::Yes, ShouldAllowSyscalls::No, minimum_stack_size));
|
||||||
m_master_tls_region = load_result.tls_region;
|
m_master_tls_region = load_result.tls_region;
|
||||||
m_master_tls_size = load_result.tls_size;
|
m_master_tls_size = load_result.tls_size;
|
||||||
m_master_tls_alignment = load_result.tls_alignment;
|
m_master_tls_alignment = load_result.tls_alignment;
|
||||||
return load_result;
|
return load_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<size_t> requested_main_program_stack_size;
|
auto interpreter_load_result = TRY(load_elf_object(new_space, *interpreter_description, load_offset, ShouldAllocateTls::No, ShouldAllowSyscalls::Yes, minimum_stack_size));
|
||||||
{
|
|
||||||
auto main_program_size = main_program_description->inode()->size();
|
|
||||||
auto main_program_rounded_size = TRY(Memory::page_round_up(main_program_size));
|
|
||||||
|
|
||||||
auto main_program_vmobject = TRY(Memory::SharedInodeVMObject::try_create_with_inode(*main_program_description->inode()));
|
|
||||||
auto main_program_region = TRY(MM.allocate_kernel_region_with_vmobject(*main_program_vmobject, main_program_rounded_size, "Loaded Main Program ELF"sv, Memory::Region::Access::Read));
|
|
||||||
|
|
||||||
auto main_program_image = ELF::Image(main_program_region->vaddr().as_ptr(), main_program_size);
|
|
||||||
if (!main_program_image.is_valid())
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
main_program_image.for_each_program_header([&requested_main_program_stack_size](ELF::Image::ProgramHeader const& program_header) {
|
|
||||||
if (program_header.type() != PT_GNU_STACK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (program_header.size_in_memory() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
requested_main_program_stack_size = program_header.size_in_memory();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto interpreter_load_result = TRY(load_elf_object(new_space, *interpreter_description, load_offset, ShouldAllocateTls::No, ShouldAllowSyscalls::Yes, requested_main_program_stack_size));
|
|
||||||
|
|
||||||
// TLS allocation will be done in userspace by the loader
|
// TLS allocation will be done in userspace by the loader
|
||||||
VERIFY(!interpreter_load_result.tls_region);
|
VERIFY(!interpreter_load_result.tls_region);
|
||||||
|
@ -489,7 +459,7 @@ void Process::clear_signal_handlers_for_exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_description, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment,
|
ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_description, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment,
|
||||||
RefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, const ElfW(Ehdr) & main_program_header)
|
RefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, const ElfW(Ehdr) & main_program_header, Optional<size_t> minimum_stack_size)
|
||||||
{
|
{
|
||||||
VERIFY(is_user_process());
|
VERIFY(is_user_process());
|
||||||
VERIFY(!Processor::in_critical());
|
VERIFY(!Processor::in_critical());
|
||||||
|
@ -537,7 +507,7 @@ ErrorOr<void> Process::do_exec(NonnullRefPtr<OpenFileDescription> main_program_d
|
||||||
Memory::MemoryManager::enter_process_address_space(*this);
|
Memory::MemoryManager::enter_process_address_space(*this);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto load_result = TRY(load(new_space, main_program_description, interpreter_description, main_program_header));
|
auto load_result = TRY(load(new_space, main_program_description, interpreter_description, main_program_header, minimum_stack_size));
|
||||||
|
|
||||||
// NOTE: We don't need the interpreter executable description after this point.
|
// NOTE: We don't need the interpreter executable description after this point.
|
||||||
// We destroy it here to prevent it from getting destroyed when we return from this function.
|
// We destroy it here to prevent it from getting destroyed when we return from this function.
|
||||||
|
@ -826,15 +796,18 @@ static ErrorOr<Vector<NonnullOwnPtr<KString>>> find_shebang_interpreter_for_exec
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<RefPtr<OpenFileDescription>> Process::find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size)
|
ErrorOr<RefPtr<OpenFileDescription>> Process::find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size, Optional<size_t>& minimum_stack_size)
|
||||||
{
|
{
|
||||||
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
|
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
|
||||||
StringBuilder interpreter_path_builder;
|
StringBuilder interpreter_path_builder;
|
||||||
if (!TRY(ELF::validate_program_headers(main_executable_header, file_size, { &main_executable_header, main_executable_header_size }, &interpreter_path_builder))) {
|
Optional<size_t> main_executable_requested_stack_size {};
|
||||||
|
if (!TRY(ELF::validate_program_headers(main_executable_header, file_size, { &main_executable_header, main_executable_header_size }, &interpreter_path_builder, &main_executable_requested_stack_size))) {
|
||||||
dbgln("exec({}): File has invalid ELF Program headers", path);
|
dbgln("exec({}): File has invalid ELF Program headers", path);
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
}
|
}
|
||||||
auto interpreter_path = interpreter_path_builder.string_view();
|
auto interpreter_path = interpreter_path_builder.string_view();
|
||||||
|
if (main_executable_requested_stack_size.has_value() && (!minimum_stack_size.has_value() || *minimum_stack_size < *main_executable_requested_stack_size))
|
||||||
|
minimum_stack_size = main_executable_requested_stack_size;
|
||||||
|
|
||||||
if (!interpreter_path.is_empty()) {
|
if (!interpreter_path.is_empty()) {
|
||||||
dbgln_if(EXEC_DEBUG, "exec({}): Using program interpreter {}", path, interpreter_path);
|
dbgln_if(EXEC_DEBUG, "exec({}): Using program interpreter {}", path, interpreter_path);
|
||||||
|
@ -863,11 +836,14 @@ ErrorOr<RefPtr<OpenFileDescription>> Process::find_elf_interpreter_for_executabl
|
||||||
|
|
||||||
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
|
// Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD
|
||||||
StringBuilder interpreter_interpreter_path_builder;
|
StringBuilder interpreter_interpreter_path_builder;
|
||||||
if (!TRY(ELF::validate_program_headers(*elf_header, interp_metadata.size, { first_page, nread }, &interpreter_interpreter_path_builder))) {
|
Optional<size_t> interpreter_requested_stack_size {};
|
||||||
|
if (!TRY(ELF::validate_program_headers(*elf_header, interp_metadata.size, { first_page, nread }, &interpreter_interpreter_path_builder, &interpreter_requested_stack_size))) {
|
||||||
dbgln("exec({}): Interpreter ({}) has invalid ELF Program headers", path, interpreter_path);
|
dbgln("exec({}): Interpreter ({}) has invalid ELF Program headers", path, interpreter_path);
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
}
|
}
|
||||||
auto interpreter_interpreter_path = interpreter_interpreter_path_builder.string_view();
|
auto interpreter_interpreter_path = interpreter_interpreter_path_builder.string_view();
|
||||||
|
if (interpreter_requested_stack_size.has_value() && (!minimum_stack_size.has_value() || *minimum_stack_size < *interpreter_requested_stack_size))
|
||||||
|
minimum_stack_size = interpreter_requested_stack_size;
|
||||||
|
|
||||||
if (!interpreter_interpreter_path.is_empty()) {
|
if (!interpreter_interpreter_path.is_empty()) {
|
||||||
dbgln("exec({}): Interpreter ({}) has its own interpreter ({})! No thank you!", path, interpreter_path, interpreter_interpreter_path);
|
dbgln("exec({}): Interpreter ({}) has its own interpreter ({})! No thank you!", path, interpreter_path, interpreter_interpreter_path);
|
||||||
|
@ -945,8 +921,9 @@ ErrorOr<void> Process::exec(NonnullOwnPtr<KString> path, Vector<NonnullOwnPtr<KS
|
||||||
return ENOEXEC;
|
return ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto interpreter_description = TRY(find_elf_interpreter_for_executable(path->view(), *main_program_header, nread, metadata.size));
|
Optional<size_t> minimum_stack_size {};
|
||||||
return do_exec(move(description), move(arguments), move(environment), move(interpreter_description), new_main_thread, previous_interrupts_state, *main_program_header);
|
auto interpreter_description = TRY(find_elf_interpreter_for_executable(path->view(), *main_program_header, nread, metadata.size, minimum_stack_size));
|
||||||
|
return do_exec(move(description), move(arguments), move(environment), move(interpreter_description), new_main_thread, previous_interrupts_state, *main_program_header, minimum_stack_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<FlatPtr> Process::sys$execve(Userspace<Syscall::SC_execve_params const*> user_params)
|
ErrorOr<FlatPtr> Process::sys$execve(Userspace<Syscall::SC_execve_params const*> user_params)
|
||||||
|
|
|
@ -494,7 +494,7 @@ public:
|
||||||
|
|
||||||
ErrorOr<void> exec(NonnullOwnPtr<KString> path, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, int recursion_depth = 0);
|
ErrorOr<void> exec(NonnullOwnPtr<KString> path, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, int recursion_depth = 0);
|
||||||
|
|
||||||
ErrorOr<LoadResult> load(Memory::AddressSpace& new_space, NonnullRefPtr<OpenFileDescription> main_program_description, RefPtr<OpenFileDescription> interpreter_description, const ElfW(Ehdr) & main_program_header);
|
ErrorOr<LoadResult> load(Memory::AddressSpace& new_space, NonnullRefPtr<OpenFileDescription> main_program_description, RefPtr<OpenFileDescription> interpreter_description, const ElfW(Ehdr) & main_program_header, Optional<size_t> minimum_stack_size = {});
|
||||||
|
|
||||||
void terminate_due_to_signal(u8 signal);
|
void terminate_due_to_signal(u8 signal);
|
||||||
ErrorOr<void> send_signal(u8 signal, Process* sender);
|
ErrorOr<void> send_signal(u8 signal, Process* sender);
|
||||||
|
@ -624,12 +624,12 @@ private:
|
||||||
bool create_perf_events_buffer_if_needed();
|
bool create_perf_events_buffer_if_needed();
|
||||||
void delete_perf_events_buffer();
|
void delete_perf_events_buffer();
|
||||||
|
|
||||||
ErrorOr<void> do_exec(NonnullRefPtr<OpenFileDescription> main_program_description, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, RefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, const ElfW(Ehdr) & main_program_header);
|
ErrorOr<void> do_exec(NonnullRefPtr<OpenFileDescription> main_program_description, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, RefPtr<OpenFileDescription> interpreter_description, Thread*& new_main_thread, InterruptsState& previous_interrupts_state, const ElfW(Ehdr) & main_program_header, Optional<size_t> minimum_stack_size = {});
|
||||||
ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t, Optional<off_t> = {});
|
ErrorOr<FlatPtr> do_write(OpenFileDescription&, UserOrKernelBuffer const&, size_t, Optional<off_t> = {});
|
||||||
|
|
||||||
ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf);
|
ErrorOr<FlatPtr> do_statvfs(FileSystem const& path, Custody const*, statvfs* buf);
|
||||||
|
|
||||||
ErrorOr<RefPtr<OpenFileDescription>> find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size);
|
ErrorOr<RefPtr<OpenFileDescription>> find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size, Optional<size_t>& minimum_stack_size);
|
||||||
|
|
||||||
ErrorOr<void> do_kill(Process&, int signal);
|
ErrorOr<void> do_kill(Process&, int signal);
|
||||||
ErrorOr<void> do_killpg(ProcessGroupID pgrp, int signal);
|
ErrorOr<void> do_killpg(ProcessGroupID pgrp, int signal);
|
||||||
|
|
|
@ -128,7 +128,7 @@ bool Image::parse()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result_or_error = validate_program_headers(header(), m_size, { m_buffer, m_size }, nullptr, m_verbose_logging);
|
auto result_or_error = validate_program_headers(header(), m_size, { m_buffer, m_size }, nullptr, nullptr, m_verbose_logging);
|
||||||
if (result_or_error.is_error()) {
|
if (result_or_error.is_error()) {
|
||||||
if (m_verbose_logging)
|
if (m_verbose_logging)
|
||||||
dbgln("ELF::Image::parse(): Failed validating ELF Program Headers");
|
dbgln("ELF::Image::parse(): Failed validating ELF Program Headers");
|
||||||
|
|
|
@ -187,7 +187,7 @@ bool validate_elf_header(ElfW(Ehdr) const& elf_header, size_t file_size, bool ve
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<bool> validate_program_headers(ElfW(Ehdr) const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder, bool verbose)
|
ErrorOr<bool> validate_program_headers(ElfW(Ehdr) const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder, Optional<size_t>* requested_stack_size, bool verbose)
|
||||||
{
|
{
|
||||||
Checked<size_t> total_size_of_program_headers = elf_header.e_phnum;
|
Checked<size_t> total_size_of_program_headers = elf_header.e_phnum;
|
||||||
total_size_of_program_headers *= elf_header.e_phentsize;
|
total_size_of_program_headers *= elf_header.e_phentsize;
|
||||||
|
@ -306,6 +306,9 @@ ErrorOr<bool> validate_program_headers(ElfW(Ehdr) const& elf_header, size_t file
|
||||||
dbgln("PT_GNU_STACK size is not page-aligned.");
|
dbgln("PT_GNU_STACK size is not page-aligned.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requested_stack_size)
|
||||||
|
*requested_stack_size = program_header.p_memsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
namespace ELF {
|
namespace ELF {
|
||||||
|
|
||||||
bool validate_elf_header(ElfW(Ehdr) const& elf_header, size_t file_size, bool verbose = true);
|
bool validate_elf_header(ElfW(Ehdr) const& elf_header, size_t file_size, bool verbose = true);
|
||||||
ErrorOr<bool> validate_program_headers(ElfW(Ehdr) const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder = nullptr, bool verbose = true);
|
ErrorOr<bool> validate_program_headers(ElfW(Ehdr) const& elf_header, size_t file_size, ReadonlyBytes buffer, StringBuilder* interpreter_path_builder = nullptr, Optional<size_t>* requested_stack_size = nullptr, bool verbose = true);
|
||||||
|
|
||||||
} // end namespace ELF
|
} // end namespace ELF
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue