Use PT_LOAD p_paddr directly when translating /proc/kcore segments#794
Open
demoray wants to merge 3 commits into
Open
Use PT_LOAD p_paddr directly when translating /proc/kcore segments#794demoray wants to merge 3 commits into
demoray wants to merge 3 commits into
Conversation
`kcore()` previously computed each segment's physical address as `phdr.p_vaddr - (first_phdr.p_vaddr - first_iomem.start)`. That assumes a single global virtual-to-physical offset across the entire kernel address space -- true on x86_64 (one direct map) but not on PPC64 or any architecture where the kernel maps physical memory through multiple non-contiguous virtual slabs. On those systems AVML read from the wrong file offsets, producing corrupt acquisitions. Use `phdr.p_paddr` directly. The kernel already populates it with the physical address backing each PT_LOAD; no arithmetic translation is needed. Skip the all-ones sentinel (`u64::MAX` on ELFCLASS64, `u32::MAX` widened on ELFCLASS32) the kernel uses to mark kernel virtual-only mappings (vmalloc, modules) that have no physical backing. Skip zero-length segments defensively. Pulled the translation out of `kcore()` into a free-standing `physical_ranges_from_segments` helper so it can be unit-tested without /proc/kcore. `find_kcore_blocks` is unchanged: the iomem ⋂ PT_LOAD intersection that bounds acquisition to actual System RAM is preserved. Added five unit tests: - `physical_ranges_use_paddr_not_vaddr` -- segments with garbage `p_vaddr` relative to `p_paddr` still produce correct output. This is the regression PPC64 hits; the old code would have mistranslated. - `physical_ranges_skip_non_pt_load_segments` -- PT_NOTE etc. are filtered out. - `physical_ranges_skip_sentinel_paddrs` -- both the 64-bit and zero-extended 32-bit sentinels are filtered. - `physical_ranges_skip_zero_size_segments` -- defensive. - `physical_ranges_sorted_by_paddr` -- output sort order is what `find_kcore_blocks` requires. Verified with: - `cargo clippy --all-features --all-targets -- -D warnings` - `cargo clippy --no-default-features --all-targets -- -D warnings` - `cargo test --all-features` - `cargo fmt --check`
# Conflicts: # src/snapshot.rs
# Conflicts: # src/snapshot.rs
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.
kcore()previously computed each segment's physical address asphdr.p_vaddr - (first_phdr.p_vaddr - first_iomem.start). Thatassumes a single global virtual-to-physical offset across the entire
kernel address space — true on x86_64 (one direct map) but not on
PPC64 or any architecture where the kernel maps physical memory
through multiple non-contiguous virtual slabs. On those systems AVML
read from the wrong file offsets, producing corrupt acquisitions.
Use
phdr.p_paddrdirectly. The kernel already populates it with thephysical address backing each PT_LOAD; no arithmetic translation is
needed. Skip the all-ones sentinel (
u64::MAXon ELFCLASS64,u32::MAXwidened on ELFCLASS32) the kernel uses to mark kernelvirtual-only mappings (vmalloc, modules) that have no physical
backing. Skip zero-length segments defensively.
Pulled the translation out of
kcore()into a free-standingphysical_ranges_from_segmentshelper so it can be unit-testedwithout /proc/kcore.
find_kcore_blocksis unchanged: the iomem ∩ PT_LOAD intersectionthat bounds acquisition to actual System RAM is preserved.
This addresses the same bug as #114 without that PR's regressions
(dropping the iomem cross-check, deleting the unit test, and the
silent zero-byte acquisition failure mode of the
found_firstgate).Added five unit tests:
physical_ranges_use_paddr_not_vaddr— segments with garbagep_vaddrrelative top_paddrstill produce correct output. Thisis the regression PPC64 hits; the old code would have mistranslated.
physical_ranges_skip_non_pt_load_segments— PT_NOTE etc. arefiltered out.
physical_ranges_skip_sentinel_paddrs— both the 64-bit andzero-extended 32-bit sentinels are filtered.
physical_ranges_skip_zero_size_segments— defensive.physical_ranges_sorted_by_paddr— output sort order is whatfind_kcore_blocksrequires.Verified with:
cargo clippy --all-features --all-targets -- -D warningscargo clippy --no-default-features --all-targets -- -D warningscargo test --all-featurescargo fmt --check