Repository navigation
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Complete resource-directory metadata for Before — the declared resource range crosses the mapped section boundary: cle master 752bce5After — the resource range ends at the containing section boundary: cle 9d20c44 |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head The affected binaries are unavailable for redistribution. They are identified by SHA-256:
The base and candidate used clean, separately rooted Nix environments with identical non-CLE component heads. Set ./nix/env.sh --feature fix-c-723 --source "cle=$CLEAN_BASE_TREE" --head cle=752bce544a058944b6bb2c49998fc4c22799ce75 --roots-dir "$PRIVATE_ROOTS/base" --clean env
./nix/env.sh --feature fix-c-723 --source "cle=$CLEAN_CANDIDATE_TREE" --head cle=9d20c44bea8ddccc0ddd685b08539cfbeb01dd7a --roots-dir "$PRIVATE_ROOTS/candidate" --clean envFor the measurement, set ./manager fix gate-slot acquire fix-c-723 --pid $$ || exit $?
unset PYTHONPATH
RTDB_BASE=$(mktemp -d "$PRIVATE_SCRATCH/c723-rtdb.XXXXXX")
cleanup_measurement() { test -n "$RTDB_BASE" && rm -r -- "$RTDB_BASE"; ./manager fix gate-slot release fix-c-723; }
trap cleanup_measurement EXIT
for ENV in "$BASE_ENV" "$CANDIDATE_ENV"; do
env -u PYTHONPATH \
ANGR_REPOS_ROOT="$REPOS_ROOT" \
ANGR_GATE_ENV="$ENV" \
RTDB_BASE="$RTDB_BASE" \
PYTHONHASHSEED=0 \
PYTHONSAFEPATH=1 \
OBJECT="$OBJECT" \
EXPECTED_SHA256="$EXPECTED_SHA256" \
"$ENV/bin/python" -P - <<'PY'
import hashlib
import json
import os
import sys
from pathlib import Path
import angr
import cle
from cle.backends.pe.regions import PESection
from cle.structs import MemRegionSort
env_root = Path(os.environ["ANGR_GATE_ENV"]).resolve()
repos_root = Path(os.environ["ANGR_REPOS_ROOT"]).resolve()
rtdb_root = Path(os.environ["RTDB_BASE"]).resolve()
assert Path(sys.prefix).resolve() == env_root
assert Path(angr.__file__).is_relative_to(env_root)
assert Path(cle.__file__).is_relative_to(env_root)
assert repos_root.is_dir() and rtdb_root.is_dir()
assert "PYTHONPATH" not in os.environ
with open(os.environ["OBJECT"], "rb") as stream:
assert hashlib.file_digest(stream, "sha256").hexdigest() == os.environ["EXPECTED_SHA256"]
original_executable = PESection.is_executable.fget
PESection.is_executable = property(
lambda section: original_executable(section)
or getattr(section, "executable_without_dep", False)
)
original_register = cle.backends.pe.PE._register_sections
def register_sections(pe):
original_register(pe)
for section in pe.sections:
section.executable_without_dep = False
if pe.supports_nx:
return
entry_section = pe.find_section_containing(pe._entry)
if entry_section is None or entry_section.is_executable:
return
for section in pe.sections:
if not section.only_contains_uninitialized_data:
section.executable_without_dep = True
cle.backends.pe.PE._register_sections = register_sections
project = angr.Project(os.environ["OBJECT"], auto_load_libs=False)
obj = project.loader.main_object
resource = next(
region for region in obj.meta_regions
if region.sort == MemRegionSort.RESOURCE_DIRECTORY
)
section = obj.find_section_containing(resource.vaddr)
cfg = project.analyses.CFGFast(
normalize=True,
data_references=False,
resolve_indirect_jumps=True,
show_progressbar=False,
)
print(json.dumps({
"cle": cle.__file__,
"resource": [resource.vaddr, resource.vaddr + resource.size],
"resource_section": [section.vaddr, section.vaddr + section.memsize],
"resource_covers_entry": resource.vaddr <= obj.entry < resource.vaddr + resource.size,
"functions": len(cfg.functions),
"blocks": len(list(cfg.model.nodes())),
"entry_is_function": obj.entry in cfg.functions,
}, sort_keys=True))
PY
doneThe embedded
Without the no-DEP behavior, the exact base and candidate each recover 0 functions and 0 blocks because section permissions prevent CFGFast from scanning code. That is an independent barrier. This PR directly changes the resource metadata geometry in either case: on the base the metadata covers each entry point, while on the candidate it ends at the containing resource section and no longer covers either entry point. The same command measured a deterministic regression set of 12 other x86 PE objects with campaign records and nonzero resource directories already contained by their mapped sections. For each affected sample's shard, the set used the first six eligible objects in lexical SHA-256 order. All 12 loaded and completed CFGFast. Every function count, block count, and entry-point recovery state was identical before and after; worse: 0. The public regression fixture was tested with: cd features/fix-c-723/repos/cle && ../../../../nix/run.sh --feature fix-c-723 -- pytest --import-mode=append -q tests/test_pe_meta_regions.pyResult: 20 passed. The regression verifies that the existing public fixture's resource metadata is clipped from its declared The finalized collection was built and gated with: ./feature.sh build fix-c-723
./feature.sh test fix-c-723Every one of the 14 gate suites ran and passed. Notable results were CLE 334 passed/9 skipped, angr 4,703 passed/47 skipped/42 xfailed with 1,206 subtests passed, and angr-management 737 passed. Worktree cleanliness passed. The merge-base lint/type delta was checked with: ./nix/run.sh --feature fix-c-723 -- python .agents/skills/angr-validate-workspace/scripts/run-ci-diff-checks.py --repository features/fix-c-723/repos/cleBoth changed files remain at pylint 10.00. Pyright errors remain 55 for |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_869 |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
A PE resource data directory can declare a size that extends far beyond the section containing it. CLE currently publishes that full declared range as metadata, so CFGFast treats later mapped code as data. Two unavailable corpus samples consequently produced only one function and did not recover their entry points once their non-DEP sections were made available for analysis.
Related work in #862 clips metadata to the image bounds, but that still leaves both affected resource ranges covering their entry points. The useful bound here is the mapped section that contains the resource directory start.
Root cause
PE._meta_resourcescopiedIMAGE_DIRECTORY_ENTRY_RESOURCE.Sizedirectly into aDataDirectory. The size is input-controlled and was not limited by the containing section's mapped extent.Fix
Compute each PE section's mapped size with the backend's existing
_mapped_sizerule. When the resource directory starts in a mapped section, clip its size at that section's end. A regression test uses the existing public PE fixture whose resource directory declares0x7400bytes inside a0x1000mapped resource section.Testing
The CFG recovery impact is coordinated with #867; the metadata boundary fixed here is independent of merge order.
Validation: #869 (comment)
sync: #867
session: sharpen