feat: enable ASLR for PIE guest binaries#1655
Open
cshung wants to merge 2 commits into
Open
Conversation
Add support for running non-PIE (ET_EXEC) guest binaries by mapping code at the ELF's declared virtual address rather than assuming identity mapping (physical == virtual). Changes: - Add is_pie() and base_va() methods to ExeInfo/ElfInfo to detect ET_DYN vs ET_EXEC binaries and extract the base virtual address - Add SandboxMemoryLayout::code_virt_base() to compute the correct virtual base for the code region and validate it doesn't conflict with other memory regions - Update snapshot creation to use non-identity virtual mapping for non-PIE code regions - Add non-PIE guest build step to CI (cargo hyperlight with -C relocation-model=static -C link-args=--no-pie) - Add integration test verifying non-PIE guest execution - Add test helper for locating non-PIE guest binaries Signed-off-by: cshung <3410332+cshung@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6f20a05d-6bee-4e2e-b320-12f8d9759bbc Signed-off-by: cshung <3410332+cshung@users.noreply.github.com>
cshung
requested review from
andreiltd,
danbugs,
dblnz,
devigned,
jprendes,
jsturtevant,
ludfjig,
simongdavies,
squillace and
syntactically
as code owners
July 18, 2026 17:22
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces ASLR for PIE guest ELF binaries by randomizing the guest virtual base address of the code region, while preserving correct behavior for non-PIE binaries that must load at their declared ELF virtual addresses. It threads the chosen code_virt_base through snapshot creation/restore paths and updates tests and build infrastructure to cover non-PIE guests.
Changes:
- Randomize PIE guest code virtual base and validate it against other guest mappings.
- Preserve
code_virt_baseacross snapshot/restore and use it for code-region GVA mappings and entrypoint computation. - Add non-PIE guest build targets and an integration test exercising non-PIE ELF VA mapping.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hyperlight_testing/src/lib.rs | Adds helper to locate the non-PIE simpleguest binary. |
| src/hyperlight_host/tests/integration_test.rs | Adds an integration test that runs a non-PIE guest end-to-end. |
| src/hyperlight_host/src/sandbox/snapshot/mod.rs | Computes/stores code_virt_base, uses it for loading, mapping, and entrypoint calculation. |
| src/hyperlight_host/src/sandbox/snapshot/file/mod.rs | Wires new Snapshot field for file-loaded snapshots (currently placeholder value). |
| src/hyperlight_host/src/sandbox/snapshot/file/config.rs | Relaxes entrypoint validation to allow non-identity-mapped code GVAs. |
| src/hyperlight_host/src/sandbox/initialized_multi_use.rs | Updates trace-guest GVA tests to use code_virt_base. |
| src/hyperlight_host/src/mem/mgr.rs | Threads code_virt_base through the memory manager so it survives restore/evolve flows. |
| src/hyperlight_host/src/mem/layout.rs | Implements PIE code VA randomization and conflict validation for code mapping. |
| src/hyperlight_host/src/mem/exe.rs | Exposes ExeInfo::is_pie() for ELF type classification. |
| src/hyperlight_host/src/mem/elf.rs | Tracks PIE-ness (ET_DYN) in ELF metadata. |
| src/hyperlight_host/src/hypervisor/hyperlight_vm/x86_64.rs | Updates internal tests for the expanded memory manager constructor. |
| Justfile | Adds recipes to build and stage non-PIE guest binaries. |
| .gitignore | Ignores the new non-PIE guest build target directory. |
| .github/workflows/dep_build_guests.yml | Builds and stages non-PIE guests in CI guest-build workflow. |
Comment on lines
+561
to
+569
| /// For PIE binaries (`is_pie == true`), the code is identity-mapped so | ||
| /// the virtual base equals the physical load address and no conflict | ||
| /// is possible by construction. | ||
| /// | ||
| /// For non-PIE binaries, the code appears at the ELF's declared | ||
| /// virtual address (`elf_base_va`), which may differ from the physical | ||
| /// load address. This method checks that the resulting virtual range | ||
| /// `[elf_base_va, elf_base_va + loaded_size)` does not overlap any | ||
| /// non-Code region. |
Comment on lines
+585
to
+600
| let min_page = 0x1000_u64; // 0x1000 * PAGE_SIZE = 0x1000000 | ||
| let max_page = 0x7_FFFF_FFFF_u64 - code_size_pages; | ||
| let page_number = rng.random_range(min_page..max_page); | ||
| page_number * PAGE_SIZE_USIZE as u64 | ||
| }; | ||
|
|
||
| // Verify the code mapping does not conflict with other mappings | ||
| // (both non-PIE with declared VA and PIE with randomized ASLR base). | ||
| let code_virt_end = virt_base + loaded_size; | ||
| for rgn in self.get_memory_regions_::<GuestMemoryRegion>(())?.iter() { | ||
| if rgn.region_type == MemoryRegionType::Code { | ||
| continue; | ||
| } | ||
| let rgn_start = rgn.guest_region.start as u64; | ||
| let rgn_end = rgn_start + rgn.guest_region.len() as u64; | ||
| if virt_base < rgn_end && rgn_start < code_virt_end { |
Comment on lines
413
to
416
| sregs: None, | ||
| entrypoint: NextAction::Initialise(load_addr + entrypoint_va - base_va), | ||
| code_virt_base, | ||
| entrypoint: NextAction::Initialise(code_virt_base + entrypoint_offset), | ||
| snapshot_generation: 0, |
Comment on lines
+459
to
+463
| // Entrypoint address must point inside the guest snapshot | ||
| // region `[BASE_ADDRESS, BASE_ADDRESS + snapshot_size)`. The | ||
| // address is a GVA, bounded by the same range because guests | ||
| // identity-map the snapshot region at low VAs. A guest | ||
| // dispatching from a non-identity-mapped VA must relax this | ||
| // check. | ||
| let snap_lo = SandboxMemoryLayout::BASE_ADDRESS as u64; | ||
| let snap_hi = snap_lo | ||
| .checked_add(self.layout.snapshot_size as u64) | ||
| .ok_or_else(|| { | ||
| crate::new_error!( | ||
| "snapshot layout overflow: BASE_ADDRESS + snapshot_size ({}) does not fit in u64", | ||
| self.layout.snapshot_size | ||
| ) | ||
| })?; | ||
| if self.entrypoint_addr < snap_lo || self.entrypoint_addr >= snap_hi { | ||
| // `entrypoint_addr` is a GVA that will be loaded into RIP. For | ||
| // identity-mapped guests it falls inside the snapshot region | ||
| // `[BASE_ADDRESS, BASE_ADDRESS + snapshot_size)`. For ASLR or | ||
| // non-PIE guests the code may be mapped at a non-identity VA, |
Comment on lines
+874
to
+876
| // Deserialized snapshots don't record the original code_virt_base; | ||
| // use 0 as a placeholder (trace_guest tests won't rely on it here). | ||
| code_virt_base: 0, |
Comment on lines
+82
to
+86
| build-rust-guests-non-pie target=default-target: (ensure-cargo-hyperlight) | ||
| cd src/tests/rust_guests/simpleguest && cargo hyperlight build --target-dir ../target-non-pie --profile={{ if target == "debug" { "dev" } else { target } }} | ||
| {{ if os() == "windows" { "$env:RUSTC_BOOTSTRAP=1; $env:RUSTFLAGS='--sysroot=' + (Resolve-Path src/tests/rust_guests/target-non-pie/sysroot).Path + ' -C relocation-model=static -C link-args=--no-pie -C link-args=--image-base=0x1000000 --cfg=hyperlight --check-cfg=cfg(hyperlight) -Clink-args=-eentrypoint';" } else { "" } }} cd src/tests/rust_guests/simpleguest && {{ if os() == "windows" { "" } else { "RUSTC_BOOTSTRAP=1 RUSTFLAGS=\"--sysroot=$(cd .. && pwd)/target-non-pie/sysroot -C relocation-model=static -C link-args=--no-pie -C link-args=--image-base=0x1000000 --cfg=hyperlight --check-cfg=cfg(hyperlight) -Clink-args=-eentrypoint\"" } }} cargo build --target x86_64-hyperlight-none --target-dir ../target-non-pie/build --profile={{ if target == "debug" { "dev" } else { target } }} | ||
|
|
||
| non_pie_guests_target := "src/tests/rust_guests/target-non-pie/build/x86_64-hyperlight-none" |
Comment on lines
+90
to
+94
| - name: Build non-PIE Rust guests | ||
| run: | | ||
| just build-rust-guests-non-pie ${{ inputs.config }} | ||
| just move-rust-guests-non-pie ${{ inputs.config }} | ||
|
|
cshung
force-pushed
the
cshung/aslr-pie-guests
branch
3 times, most recently
from
July 18, 2026 18:19
cb0b212 to
09e0700
Compare
Randomize the virtual base address for PIE guest code regions instead of using identity mapping. This provides address space layout randomization (ASLR) for PIE guests, making the code region virtual address unpredictable across sandbox instantiations. The random base is chosen from a page-aligned range within 47-bit canonical user space [0x1000000, max - code_size). Non-PIE binaries continue to use their declared ELF base VA. Changes: - layout.rs: code_virt_base() now randomizes VA for PIE guests and always validates against memory region conflicts - mgr.rs: thread code_virt_base through SandboxMemoryManager - snapshot/mod.rs: store code_virt_base in Snapshot, use it for relocation processing in exe_info.load() - config.rs: relax entrypoint validation to allow non-identity-mapped virtual addresses (ASLR / non-PIE) - initialized_multi_use.rs: trace_guest tests use code_virt_base instead of assuming GVA == GPA Signed-off-by: cshung <3410332+cshung@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6f20a05d-6bee-4e2e-b320-12f8d9759bbc Signed-off-by: cshung <3410332+cshung@users.noreply.github.com>
cshung
force-pushed
the
cshung/aslr-pie-guests
branch
from
July 18, 2026 18:53
09e0700 to
7f2b79e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Randomize the virtual base address for PIE guest code regions instead of using identity mapping. This provides address space layout randomization (ASLR) for PIE guests, making the code region virtual address unpredictable across sandbox instantiations.
Changes
and::rng(), choosing a page-aligned address within 47-bit canonical user space. Conflict validation now applies to both PIE and non-PIE.
Design
Testing
Dependencies
This PR is based on #1530 (non-PIE ELF loading support).