From 4e1898df99d7a858c34bb088fe882a2071f83d20 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Fri, 24 Dec 2021 22:54:26 +0100 Subject: [PATCH] UserspaceEmulator: Exclude special ranges from RangeAllocator If we do not mark these ranges as reserved, RangeAllocator might later give us addresses that overlap these, which then causes an assertion failure in the SoftMMU. This behavior led to recurring CI failures, and sometimes made programs as simple as `/bin/true` fail. Fixes "Crash 1" reported in #9104 --- Userland/DevTools/UserspaceEmulator/Emulator.cpp | 10 ++++++++-- .../DevTools/UserspaceEmulator/Emulator_syscalls.cpp | 4 +++- Userland/DevTools/UserspaceEmulator/RangeAllocator.cpp | 7 +++++++ Userland/DevTools/UserspaceEmulator/RangeAllocator.h | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Userland/DevTools/UserspaceEmulator/Emulator.cpp b/Userland/DevTools/UserspaceEmulator/Emulator.cpp index 829dca0a26..b02bf7c692 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator.cpp @@ -34,6 +34,8 @@ namespace UserspaceEmulator { static constexpr u32 stack_location = 0x10000000; static constexpr size_t stack_size = 1 * MiB; +static constexpr u32 signal_trampoline_location = 0xb0000000; + static Emulator* s_the; Emulator& Emulator::the() @@ -95,6 +97,7 @@ Vector Emulator::generate_auxiliary_vector(FlatPtr load_bas void Emulator::setup_stack(Vector aux_vector) { + m_range_allocator.reserve_user_range(VirtualAddress(stack_location), stack_size); auto stack_region = make(stack_location, stack_size); stack_region->set_stack(true); m_mmu.add_region(move(stack_region)); @@ -183,7 +186,9 @@ bool Emulator::load_elf() VERIFY(program_header.type() != PT_TLS); if (program_header.type() == PT_LOAD) { - auto region = make(program_header.vaddr().offset(interpreter_load_offset).get(), program_header.size_in_memory()); + auto start_address = program_header.vaddr().offset(interpreter_load_offset); + m_range_allocator.reserve_user_range(start_address, program_header.size_in_memory()); + auto region = make(start_address.get(), program_header.size_in_memory()); if (program_header.is_executable() && !program_header.is_writable()) region->set_text(true); memcpy(region->data(), program_header.raw_data(), program_header.size_in_image()); @@ -666,7 +671,8 @@ extern "C" void asm_signal_trampoline_end(void); void Emulator::setup_signal_trampoline() { - auto trampoline_region = make(0xb0000000, 4096); + m_range_allocator.reserve_user_range(VirtualAddress(signal_trampoline_location), 4096); + auto trampoline_region = make(signal_trampoline_location, 4096); u8* trampoline = (u8*)asm_signal_trampoline; u8* trampoline_end = (u8*)asm_signal_trampoline_end; diff --git a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp index 704127175a..6672409ef4 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp @@ -1533,7 +1533,9 @@ u32 Emulator::virt$allocate_tls(FlatPtr initial_data, size_t size) // TODO: This matches what Thread::make_thread_specific_region does. The kernel // ends up allocating one more page. Figure out if this is intentional. auto region_size = align_up_to(size, PAGE_SIZE) + PAGE_SIZE; - auto tcb_region = make(0x20000000, region_size); + constexpr auto tls_location = VirtualAddress(0x20000000); + m_range_allocator.reserve_user_range(tls_location, region_size); + auto tcb_region = make(tls_location.get(), region_size); size_t offset = 0; while (size - offset > 0) { diff --git a/Userland/DevTools/UserspaceEmulator/RangeAllocator.cpp b/Userland/DevTools/UserspaceEmulator/RangeAllocator.cpp index e22980b397..8ed75c51cd 100644 --- a/Userland/DevTools/UserspaceEmulator/RangeAllocator.cpp +++ b/Userland/DevTools/UserspaceEmulator/RangeAllocator.cpp @@ -181,4 +181,11 @@ void RangeAllocator::deallocate(const Range& range) } } +void RangeAllocator::reserve_user_range(VirtualAddress begin, size_t size) +{ + auto end = round_up_to_power_of_two(begin.offset(size).get(), PAGE_SIZE); + auto allocated_range = allocate_specific(begin.page_base(), end - begin.page_base().get()); + VERIFY(allocated_range.has_value()); +} + } diff --git a/Userland/DevTools/UserspaceEmulator/RangeAllocator.h b/Userland/DevTools/UserspaceEmulator/RangeAllocator.h index c8264bd190..c0957d8021 100644 --- a/Userland/DevTools/UserspaceEmulator/RangeAllocator.h +++ b/Userland/DevTools/UserspaceEmulator/RangeAllocator.h @@ -22,6 +22,8 @@ public: Optional allocate_randomized(size_t, size_t alignment); void deallocate(const Range&); + void reserve_user_range(VirtualAddress, size_t); + void dump() const; bool contains(const Range& range) const { return m_total_range.contains(range); }