Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/tinykvm/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ namespace tinykvm
};

struct MachineOptions {
enum class IRelativeMode {
BestEffort = 0,
StrictFail = 1,
ExecuteResolver = 2,
};

uint64_t max_mem = 16ULL << 20; /* 16MB */
uint32_t max_cow_mem = 0;
uint32_t stack_size = 1600UL << 10; /* 1600KB */
Expand Down Expand Up @@ -100,6 +106,8 @@ namespace tinykvm
bool relocate_fixed_mmap = true;
/* Make heap executable, to support JIT. */
bool executable_heap = false;
/* How to handle R_X86_64_IRELATIVE during bootstrap relocation. */
IRelativeMode irelative_mode = IRelativeMode::StrictFail;
/* Enable file-backed memory mappings for large files */
bool mmap_backed_files = false;
/* Enable VM snapshot by file-mapping all physical memory
Expand Down
5 changes: 5 additions & 0 deletions lib/tinykvm/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Machine::Machine(std::string_view binary, const MachineOptions& options)
: m_forked {false},
m_just_reset {false},
m_relocate_fixed_mmap {options.relocate_fixed_mmap},
m_irelative_mode {options.irelative_mode},
memory { vMemory::New(*this, options,
options.vmem_base_address, options.vmem_base_address + 0x100000, options.max_mem)
},
Expand Down Expand Up @@ -65,6 +66,7 @@ Machine::Machine(std::string_view binary, const MachineOptions& options)
}

this->setup_long_mode(options);
this->execute_pending_irelative_resolvers(options);

/* We need to adjust BRK if the kernel end address is
above the default BRK start address. */
Expand Down Expand Up @@ -94,6 +96,7 @@ Machine::Machine(const Machine& other, const MachineOptions& options)
m_forked {true},
m_just_reset {true},
m_relocate_fixed_mmap {options.relocate_fixed_mmap},
m_irelative_mode {options.irelative_mode},
m_binary {options.binary.empty() ? other.m_binary : options.binary},
memory {*this, options, other.memory},
m_image_base {other.m_image_base},
Expand Down Expand Up @@ -170,6 +173,7 @@ void Machine::reset_to(std::string_view binary, const MachineOptions& options)
this->remote_disconnect();

this->m_mmap_cache = {};
this->m_irelative_mode = options.irelative_mode;
this->m_mt.reset(nullptr);
this->m_signals.reset(nullptr);
this->m_fds.reset(nullptr);
Expand All @@ -178,6 +182,7 @@ void Machine::reset_to(std::string_view binary, const MachineOptions& options)

this->vcpu.init(0, *this, options);
this->setup_long_mode(options);
this->execute_pending_irelative_resolvers(options);
struct tinykvm_regs regs {};
/* Store the registers, so that Machine is ready to go */
this->setup_registers(regs);
Expand Down
7 changes: 7 additions & 0 deletions lib/tinykvm/machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ struct Machine
void elf_loader(std::string_view binary, const MachineOptions&);
void elf_load_ph(std::string_view binary, const MachineOptions&, const void*);
void dynamic_linking(std::string_view binary, const MachineOptions&);
void execute_pending_irelative_resolvers(const MachineOptions&);
bool relocate_section(const char* section_name, const char* sym_section);
bool relocate_relr_section(const char* section_name);
void setup_long_mode(const MachineOptions&);
Expand All @@ -349,9 +350,15 @@ struct Machine
bool m_verbose_system_calls = false;
bool m_verbose_mmap_syscalls = false;
bool m_verbose_thread_syscalls = false;
MachineOptions::IRelativeMode m_irelative_mode = MachineOptions::IRelativeMode::StrictFail;
void* m_userdata = nullptr;

std::string_view m_binary;
struct PendingIRelative {
address_t target_addr;
address_t resolver_addr;
};
std::vector<PendingIRelative> m_pending_irelative;

vMemory memory; // guest memory

Expand Down
62 changes: 58 additions & 4 deletions lib/tinykvm/machine_elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,10 +374,25 @@ bool Machine::relocate_section(const char* section_name, const char* sym_section
if (rtype == R_X86_64_RELATIVE) {
*(address_t*) memory.safely_at(addr, sizeof(address_t)) = this->m_image_base + rela_addr[i].r_addend;
} else {
/* Best-effort bootstrap handling for IFUNC relocations.
A full implementation must evaluate the resolver and write
its return value. */
*(address_t*) memory.safely_at(addr, sizeof(address_t)) = this->m_image_base + rela_addr[i].r_addend;
switch (this->m_irelative_mode)
{
case MachineOptions::IRelativeMode::StrictFail:
throw MachineException(
"R_X86_64_IRELATIVE encountered in strict mode", rela_addr[i].r_offset);
case MachineOptions::IRelativeMode::BestEffort:
/* Bootstrap fallback for IFUNC relocations.
Full correctness requires executing the guest resolver and
storing its return value. */
*(address_t*) memory.safely_at(addr, sizeof(address_t)) = this->m_image_base + rela_addr[i].r_addend;
break;
case MachineOptions::IRelativeMode::ExecuteResolver:
/* Defer resolver execution until long mode/register setup is complete. */
this->m_pending_irelative.push_back(PendingIRelative{
addr,
this->m_image_base + rela_addr[i].r_addend,
});
break;
}
}
} else {
if constexpr (VERBOSE_LOADER) {
Expand All @@ -388,6 +403,44 @@ bool Machine::relocate_section(const char* section_name, const char* sym_section
return true;
}

void Machine::execute_pending_irelative_resolvers(const MachineOptions& options)
{
if (this->m_pending_irelative.empty()) {
return;
}

if (this->m_irelative_mode != MachineOptions::IRelativeMode::ExecuteResolver) {
this->m_pending_irelative.clear();
return;
}

for (const auto& pending : this->m_pending_irelative)
{
if (!memory.safely_within(pending.target_addr, sizeof(address_t))) {
throw MachineException("IRELATIVE target is outside guest memory", pending.target_addr);
}
if (!memory.safely_within(pending.resolver_addr, 1)) {
throw MachineException("IRELATIVE resolver is outside guest memory", pending.resolver_addr);
}

/* Execute resolver in guest context and write returned function address. */
this->timed_vmcall(pending.resolver_addr, 0.25f);
const auto regs = this->registers();
const address_t resolved = regs.rax;

*(address_t*) memory.safely_at(pending.target_addr, sizeof(address_t)) = resolved;

if (options.verbose_loader) {
printf("* IRELATIVE resolver %p -> %p written to %p\n",
(void*) pending.resolver_addr,
(void*) resolved,
(void*) pending.target_addr);
}
}

this->m_pending_irelative.clear();
}

bool Machine::relocate_relr_section(const char* section_name)
{
const auto* relr = section_by_name(m_binary, section_name);
Expand Down Expand Up @@ -446,6 +499,7 @@ void Machine::dynamic_linking(std::string_view binary, const MachineOptions& opt
{
(void)binary;
(void)options;
this->m_pending_irelative.clear();
this->relocate_relr_section(".relr.dyn");
this->relocate_section(".rela.dyn", ".dynsym");
//this->relocate_section(".rela.plt", ".dynsym");
Expand Down
Loading
Loading