inspect-native-exports treated any nonzero byte in .dynsym entry 0 as a
malformed table. That is right when the reserved slot holds a real symbol,
which was #7389, but some Android arm64 libraries set only st_name. Those
files were rejected before any export could be read.
Skip that entry, keep the inventory complete, and record the nonzero
st_name in limitations. Any other nonzero field still fails the table.
Fixes#9700
Supersedes #9752
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
A base APK whose manifest requires ABI or density splits keeps its native
libraries in those splits, yet inspect_android_jni_bindings reported a
complete library inventory with zero libraries. The bridge's native
declaration inventory now also decodes the root binary manifest without a
session and reports its requiredSplitTypes and isSplitRequired facts, or why
they are unknown (bridge identity 11). When splits are required or unknown,
the library inventory is partial with an unknown that says so, and a binding
without a candidate is unknown instead of unmatched.
The binary manifest fixture from #9769 was used to check the bridge with the
real jadx-headless-mcp 0.7.1 JAR, including stripped attribute names that
resolve through framework resource IDs.
Fixes#9756
Co-Authored-By: 2SinceJuly <202121119+2SinceJuly@users.noreply.github.com>
Co-Authored-By: Phon <twilyt1@proton.me>
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
trace_native_values ended at a provider-classified thunk whose model
holds only a synthetic return (an external import) or borrows its
target's operations, without saying the target was never examined, so
a stub's small model read as the end of the call chain. Thunk targets
are now reconciled after traversal: one another path traced, attempted
or queued is left to that path, and the rest are reported in unknowns
with the target in a new optional related_procedure field.
Fixes#8476
Supersedes #8678
Based on #8678 and rebased onto main's separate call-binding module.
related_procedure is exactOptional and set only on the thunk unknown,
so other unknowns and retained traces keep their shape.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
A worker heap too small for REA's bridge stops the JVM before the protocol
handshake, so the launcher's retained stderr is the only evidence, and the
failure was reported as capability_unavailable with configuration advice.
When that stderr carries HotSpot's java.lang.OutOfMemoryError heap reasons,
report resource_constraint for memory with observed_max_heap_bytes null and
the same REA_JADX_HEAP_MIB remediation the bridge-reported heap failure uses,
now shared and stating -Xmx precedence. Other launcher stops are unchanged.
Refs #3517
Supersedes #3573
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
A successful batch_decompile item carried no item-level provenance:
only the batch Evidence aggregated limitations, so when a provider such
as Kuna answered repeated selectors from different sources, the caveat
did not say which occurrence it applied to. Successful items now keep
their own observation's limitations (exactOptional, so retained records
still parse), and the retained items view projects them.
The batch unavailable item also dropped the provider's typed
pseudocodeAbsence reason; it now carries pseudocode_absence.
Fixes#8350
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
MCP passes progress to observeWebSession, but the CLI did not, so a
caller of `rea observe-web-session` never saw the armed observation
window it must wait for before acting. Three CLI commands also each
wrote their own copy of the same stderr progress line.
One cliProgress module now owns the stderr progress line and reporter.
observe-web-session uses it, as do web runtime, JavaScript application
and desktop capture progress. The CDP session also stops reporting
readiness once collection is no longer active, so a stopped capture does
not invite the external action.
Fixes#8141
Supersedes #8149
Based on #8149; the desktop capture copy now shares the line writer too.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
A cursor for another target, profile, pattern, mask, bounds, or document
was reported as invalid input and pointed at schema repair. Name the
binding, attribute the issue to the cursor, and leave the differing
component unknown.
Fixes#8366
Supersedes #8420
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
When the byte reader for inspect_native_dispatch_metadata refuses a target
(for example a 32-bit Mach-O) and the list_names symbol fallback then fails
or returns an invalid inventory, only the fallback's error reached the
caller. Retain the reader failure under diagnostics.binary_metadata_failure.
Fixes#7651.
Carries forward e7884a704 (by @morluto, on @dreinst's #7701).
Signed-off-by: Zhaowei Gu <83746079+zw-g@users.noreply.github.com>
Supersedes #8036
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
The testing guides stated lane and shard counts in prose. The counts drifted
when the workflow changed: "all eight fast built shards" survived the move to
twelve, "Eight Linux real-system lanes" now covers twelve workflow calls, and
the SQLite guide named a Node 24.15.0 lane that the matrix no longer runs.
Describe each set by its selector and point at the workflow that owns the
exact versions, so later workflow changes cannot make the text wrong.
Fixes#7616Fixes#7617
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process)!: retain observed cleanup intervention
Process capture derived `settlement.cleanup_outcome` from the settlement
state alone in three places, so a quiesced capture reported
`not_required` even after final owned-process cleanup SIGKILLed a live
token-owned descendant. `cleanupOwnedProcessGroup` already knew it had
signaled, but the capture lifecycle discarded that fact.
Carry the observed signal out of ownership cleanup (also on failure
paths), accumulate it across cleanup retries as true/false/unknown, and
derive settlement and the intervention residual unknown once in
`processCaptureCleanupFacts` for full, partial and harness results.
BREAKING CHANGE: a quiesced settlement may now report
`cleanup_outcome: "cleaned"`. Saved captures stay valid; readers that
accepted only `not_required` for quiesced settlements must accept
`cleaned`.
Fixes#8032
Squashed from #8043 and rebased onto main (adapted to the resource-scope
release API and the inspection-failure cleanup path).
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(process): keep a sent signal when cleanup throws an inspection failure
Final ownership verification can rethrow a typed inspection failure (for
example cancellation) after SIGKILL succeeded. The capture owner then
recorded the attempt as unknown and dropped the intervention fact.
cleanupOwnedProcessGroup now marks a failure it throws after signaling,
without changing the failure's identity, and the capture owner keeps
the signal for such failures.
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: wunianze666-netizen <wunianze666@gmail.com>
Co-authored-by: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
decompile_all set its top-level "procedure_info is unavailable" caveat
from a per-call flag that only a newly attempted function could raise.
A resume that skipped every verified file, or selected nothing, rewrote
the manifest and decompile-index.json with an empty limitations list
while every retained record still reported an unavailable body.
The export owner now answers from the records it retains: the summary
counts every non-external record whose body is unavailable, including
records an earlier run wrote, and repeats the reason when all share one.
The per-call flag is removed. A fresh export whose procedure_info works
but leaves some bodies unavailable now reports that caveat too; a later
attempt that records a known body clears it.
Fixes#8351
Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(native): specify Windows ReFS filesystem authority
* docs(native): plan ReFS filesystem support
* feat(native): admit ReFS filesystem identities
* feat(native): support ReFS filesystem authority
* feat(native): advertise ReFS Windows support
* docs(native): format ReFS support documents
* docs(native): record ReFS verification tasks
* docs(native): record ReFS draft pull request
* docs(website): correct remaining ReFS translations
* fix(docs): correct Windows native guide link in ReFS plan
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(native): list ELF initializers of images with COPY relocations
inspect-native-initializers reported every init_array and fini_array slot
of a non-PIE executable as unresolved, and ordinary PIE executables as
incomplete, when the image carried a COPY relocation such as the one for
stdout.
The shared dynamic relocation reader had no write extent for COPY or TLS
descriptor relocations, so one such record made pointer coverage unknown.
It now sizes a COPY from the image's own dynamic symbol and a TLS
descriptor as two words. COPY sizes are accepted up to the file byte count
in total, so repeated records cannot multiply consumer work.
The section relocation fallback also treated a record whose destination
has no file bytes, as COPY into .bss does, as an unread table. A linked
image's record now affects only the slots it overlaps in memory.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YT2WLf5G9AnLKF3bZtNLwf
* test(native): cover a COPY relocation against symbol index 0
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YT2WLf5G9AnLKF3bZtNLwf
* fix(native): size section COPY records and keep write extents opt-in
Address two review findings on the COPY relocation change.
The shared dynamic relocation reader yields COPY and TLS descriptor
records as writes only to a consumer that asks for whole extents. The
initializer walk asks. IL2CPP and the Android JNI overlay do not, so
both see these kinds as not decoded, exactly as before this branch.
IL2CPP finds unknown bytes by looking one pointer back from a read, so
a wider write of unknown value was read as stored zeros.
The section fallback takes a COPY record's span from the symbol its
table links to instead of assuming one word. A table counts as not
fully read when that size is not established, or when a record of
unknown extent writes memory that has no file bytes.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YT2WLf5G9AnLKF3bZtNLwf
* refactor(native): size section COPY records in one helper
Move the symbol lookup, the allowance and the unread-table note out of
the record loop, so the loop only asks for the extent a record is known
to write. Behavior is unchanged.
Cover the allowance across two section records, and keep the new test
code within the lint thresholds the base already meets.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YT2WLf5G9AnLKF3bZtNLwf
---------
Co-authored-by: thunderq10 <195775442+thunderq10@users.noreply.github.com>
Co-authored-by: Claude Fable 5.2 <noreply@anthropic.com>
* fix(elf): keep compressed storage out of decoded metadata facts
* fix(elf): preserve virtual relocation identity
Keep linked initializer backing and relocation values in their owning virtual
or ET_REL section coordinates. Replace the IL2CPP physical-copy materializer
with compact virtual value facts while preserving file-backed capacity.
Reuse initializer repairs and original regressions from ShuaixinHuang PRs
repair retains independent alias values instead of blanket alias refusal.
Co-authored-by: 帅鑫 Huang <1836656514@qq.com>
* fix(elf): admit compressed string tables the profile does not read
SHF_COMPRESSED string tables are rejected only when they name sections
or symbols. An unreferenced string table is not decoded, so it no longer
makes an otherwise analyzable ELF unsupported.
* fix(il2cpp): admit virtual pointer workspace before retention
* fix(elf): reject null relocation target sections
* fix(il2cpp): avoid decoding unrelated Mach-O words
* fix(il2cpp): preserve uncertainty in candidate scans
* fix(il2cpp): bound uncertain array candidates
* fix(il2cpp): preserve unknown registration candidates
* fix(il2cpp): classify type kinds before bound data
* fix(il2cpp): bind candidate counts to matching names
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 帅鑫 Huang <1836656514@qq.com>
Validate the final 64-bit payload before interpreting unwind LEB operands,
and retain valid ten-byte signed padding. Keep invalid records incomplete
without discarding independent valid FDEs.
Adapted from ShuaixinHuang’s closed PR #9872, original head
021ab3ad62. Original fixture, regression
and documentation changes are retained; decoder comments are shortened.
Co-authored-by: 帅鑫 Huang <1836656514@qq.com>
* fix(elf): keep compressed storage out of decoded metadata facts
* fix(elf): admit compressed string tables the profile does not read
SHF_COMPRESSED string tables are rejected only when they name sections
or symbols. An unreferenced string table is not decoded, so it no longer
makes an otherwise analyzable ELF unsupported.
* fix(elf): keep requirement names when verdef declares no entries
A compressed GNU version-definition section with sh_info 0 has no
definitions to decode. Skipping it leaves requirement names in place
instead of clearing them as an unread compressed table.
* fix(elf): skip empty version requirements before storage reads
* fix(elf): skip empty compressed version-requirement tables
A GNU verneed section with sh_info 0 has no requirement records. Reading
its compressed bytes was a version failure and partial coverage; the
declared count now skips that read.
* fix(mips): distinguish compressed metadata storage (#9959)
* fix(elf): note a missing symbol table only when a relocation needs it
A sectionless image with direct DT_INIT and DT_FINI no longer becomes incomplete solely because DT_SYMTAB does not match a decoded table. The same note remains when a dynamic relocation asks for a symbol.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Keep inventory counts inline and preserve explicit 1–32 record detail requests. The real 26-record Windows sample serialized 57,946 metadata bytes before detail selection.
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
* fix(browser-scenario): page captured text on Unicode boundaries
* fix(browser-scenario): retain popup events when open metadata exceeds its budget
* fix(browser-scenario): redact saved secrets across wire encodings
* fix(browser-scenario)!: record parsed request actions in evidence
BREAKING CHANGE: New captures with request actions that save nothing include save: [] in the recorded parameters. Their scenario and Evidence digests can differ from older captures of the same scenario. Read retained captures with their original recorded digests and use the newly recorded digest for new captures.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Since Linux 6.1, kbuild compiles init/version.o with a temporary
UTS_VERSION. Its build number and timestamp stay empty unless
KBUILD_BUILD_VERSION or KBUILD_BUILD_TIMESTAMP is set. That weak
linux_banner stays in the image ahead of the banner from
init/version-timestamp.o, and the first-match scan reported it. The WSL
6.18 kernel showed '# SMP PREEMPT_DYNAMIC ' instead of
'#1 SMP PREEMPT_DYNAMIC Tue Oct 6 19:13:07 UTC 2026'.
Treat a banner with a space right after '#' or at its end as the
placeholder. Keep scanning and report a later banner that repeats its
text up to '#' and is not a placeholder. Report the placeholder when no
such banner follows.
* fix(windows): leave a shortcut icon comparison unknown across code pages
Windows stores the LinkInfo LocalBasePath only as ANSI when the system
code page can represent it, while StringData stays UTF-16. The parser
projects the ANSI bytes as Latin1, so on a code page 936 host a path such
as F:\百度网盘\BaiduNetdisk\BaiduNetdisk.exe never matched the same
Unicode IconLocation, and icon_location_differs_from_target reported true
for a shortcut whose icon is its own target.
Record whether each target path is an ANSI projection. Compare it with
the icon only when both use the same encoding or the ANSI text is ASCII.
A full target that cannot be compared makes the result null, like a
%VAR% target.
* fix(windows): keep each LinkInfo part's encoding when joining paths
A joined LinkInfo target was marked ANSI when any part was ANSI. An ASCII
ANSI share with a UTF-16 suffix such as \\server\share + 工具\app.exe
then could not be compared with a Unicode icon, although no byte needs a
code page. Record which encoding each part's non-ASCII text came from,
and compare two paths when their non-ASCII text shares one encoding.
* fix(cli): publish partial Evidence to --evidence_output on failure
publishCliAnalysisEvidence returned a failed result unchanged before any
--evidence_output handling. When a source reached its deadline, or another
failure carried partial Evidence, the requested file was not written and
--detail summary still printed the complete partial Evidence inline, which
reached more than 64 MB on a large build.
A failure whose details.partial_observation is authenticated Evidence now
publishes it through the same projection and new-file publication as a
successful result. The failure keeps its code, message and remediation.
With --detail summary, details.partial_observation holds the summary
view, and details.diagnostics.evidence_bundle reports the path and bytes.
A refused publication keeps the complete partial Evidence inline and adds
details.diagnostics.evidence_bundle_error with the refusal and a
limitation. Without --evidence_output, for cancellation, and for raw
provider observations the failure output is unchanged.
Fixes#7787
* fix(cli): keep committed partial Evidence receipts on refused publication
When publishing the partial Evidence of a failed analysis, a refusal can
follow a commit. Staging cleanup that stays incomplete after its retry
returns cleanup_incomplete with published_path and bytes, and a
cancellation after commit returns cancelled with
diagnostics.evidence_bundle. The failure path read only the second form,
so a committed file with incomplete cleanup was reported as not
published, without its receipt or the cleanup resources, and the full
partial Evidence went back inline.
Keep the original analysis failure and record the receipt from either
form in details.diagnostics.evidence_bundle. Incomplete publication
cleanup adds published, published_path, bytes, cleanup and resources to
details, the shape a successful run's cleanup_incomplete reports;
resources join any the analysis failure already reports, and its own
cleanup reason is kept. Once the file is committed, the delivered view
(the summary with --detail summary) replaces the inline partial Evidence.
Receipts omit a path that holds an excluded sensitive value, as on
success.
Tests drive the real staged publication through its commit point: cleanup
that stays incomplete, cleanup confirmed by retry, and SIGINT after
commit. A composition test checks receipt redaction on the failure path.
* fix(cli): report incomplete partial publication cleanup
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(native): list ELF and Mach-O initializer and finalizer functions
inspect_native_initializers and inspect-native-initializers list the
functions an ELF or Mach-O image runs before and after main: ELF
DT_INIT, DT_FINI, preinit, init and fini arrays and .ctors/.dtors, and
Mach-O __mod_init_func, __mod_term_func and __init_offsets, with slot
addresses, resolved targets, symbols where available and relocation
facts for relocatable objects. Nothing is executed. Slot, symbol,
relocation and note budgets are shared across tables, sentinels are
matched at the image width, and target-derived names are bounded and
marked untrusted.
* fix(native): keep ELF initializer slots unresolved when relocation coverage is partial
A skipped, unreadable or over-budget section relocation table now keeps
every slot it could reach unresolved instead of reading the stored word as
raw or dropping a .ctors slot as a sentinel. Dynamic writes that only
partly overlap a slot, or write it twice, leave it unresolved. Linked
images no longer reapply retained non-SHF_ALLOC link-time records.
The dynamic relocation walk now pauses at the shared reader's step
boundaries and observes cancellation there, resolved targets need only
their first byte mapped, and unreadable symbol names make the report
incomplete.
* fix(native): stop reporting unchecked Mach-O initializer words as resolved
Object files now apply their own section relocations: an UNSIGNED entry
against a defined symbol gives symbol_addend, one against an undefined
symbol gives unresolved_import, and any other entry leaves the slot
unresolved. Linked images without a fixup decoder, such as 32-bit ones,
keep pointer slots unresolved when an LC_DYLD_INFO bind stream or
LC_DYSYMTAB external relocations could replace the stored word.
LC_DYLD_INFO rebases now report dyld_info_rebase instead of
chained_fixup, and unreadable symbol names make the report incomplete.
Section headers keep their declared reloff and nreloc for this.
* docs(native): move initializer guide under docs/guides/native
The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /native-initializers route is
unchanged.
The guide and spec also describe per-slot relocation coverage, retained
link-time records, Mach-O object relocations, undecoded bind streams,
the dyld_info_rebase resolution and unreadable names.
* fix(native): keep IFUNC and partly relocated ELF initializer slots unresolved
An absolute relocation against an STT_GNU_IFUNC symbol no longer reports
the resolver address as the target. Section relocation records now use
their real write width, so a record that writes only part of a slot,
starts inside it or repeats it leaves the slot unresolved instead of
reading a raw zero or dropping a .ctors slot as a sentinel.
On 32-bit ARM the Thumb bit is cleared when locating a target's section
and file offset, while value_va keeps the stored callable value.
* fix(native): locate Thumb Mach-O initializer targets and reject arm64_32 with a 64-bit header
On CPU_TYPE_ARM the Thumb bit is cleared when locating and naming a
target, since nlist values do not carry it. An arm64_32 image that
declares a 64-bit header is rejected as malformed rather than read with
8-byte slots. The guide and spec describe IFUNC relocations, partly
relocated section slots, Thumb targets and this rejection.
* fix(native): index initializer address lookups and keep ambiguous mappings unknown
ELF and Mach-O initializer lookups now build the shared file mapping
index once per image, so each slot and target lookup is logarithmic in
the number of load segments rather than a scan of every mapping.
An address that load segments map ambiguously no longer falls back to a
section header offset. Its file offset is reported as unknown and the
report is incomplete; only genuinely unmapped spans use the section
fallback.
* fix(native): report Mach-O bind names over the name budget
A bound import name longer than the 1024-byte name budget was dropped
without a trace, although it is the only identity of an unresolved
initializer target. It now counts toward the over-long name limitation
and makes the report incomplete.
* test(native): count mapping lookups instead of timing the load index regression
The load-mapping regression asserted a wall-clock bound, which is
sensitive to machine load. It now spies on the shared mapping module and
requires the same number of mapping scans and index builds for 8 and 64
slots, so a per-slot scan of every load segment fails deterministically
on a small fixture.
* fix(native): yield while decoding legacy rebase runs
* fix(native): preserve initializer mapping and coverage
* fix(native): index legacy fixup spans
* fix(native): preserve relocation uncertainty and bound bind lookup work
* fix(native): validate ELF slot mappings and yield section relocation scans
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* fix(managed): report InternalCall methods as runtime-provided boundaries
inspect_managed_native_boundaries listed P/Invoke, native, runtime and
unmanaged methods, but not methods with MethodImplOptions.InternalCall
(0x1000). The runtime implements those bodies; mscorlib and
System.Private.CoreLib declare hundreds of them as FCalls. They now appear
in native_implementations with boundary_kind runtime-provided.
* fix(managed): keep InternalCall bodies out of CIL decoding
The native-boundary view reports InternalCall methods as runtime-provided.
Body admission still decoded CIL from a nonzero RVA when the row kept IL
and managed flags. CoreCLR rejects such a row (BFA_INTERNAL_METHOD_WITH_RVA).
Body admission now treats InternalCall like the Runtime code type. The
method gets a partial body with no instructions. The InternalCall test
covers both a zero and a nonzero RVA.
* test(javascript): distinguish package scope in route fixtures
* test(apple): separate identity and refusal fixture groups
* fix(managed): honor InternalCall during body admission
---------
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(native): recover ELF function ranges from unwind tables
inspect_elf_unwind_ranges and inspect-elf-unwind-ranges read .eh_frame
and .eh_frame_hdr from one local ELF32 or ELF64 image and list the
function ranges its FDEs name, with CIE facts, LSDA and personality,
the containing section and an exact symbol where one starts at the
address. Nothing is executed and no disassembler is needed. Pointer
encodings follow the DW_EH_PE rules with raw zero as null, discarded
FDEs are counted and skipped, the .eh_frame_hdr search table is
compared with the decoded FDEs, and record, row and symbol budgets are
bounded. verify:elf:unwind-ranges compares the reported starts with
llvm-dwarfdump or readelf on a compiled C++ program.
* fix(elf): keep unresolved unwind facts out of reported ranges
Skip FDEs whose initial location is indirect and do not locate
.eh_frame through an indirect eh_frame_ptr, since pointer slots are
not functions. Stop an unbounded header-located scan at a CIE with an
unrecognized augmentation, report ignored duplicate PT_GNU_EH_FRAME
headers as incomplete coverage, and accept a null personality stored
under an indirect encoding.
Keep only symbols at decoded FDE starts, cache name observations per
string-table offset, and decode names only for the returned page under
a fixed 16 MiB text allowance, so repeated or long names no longer
grow memory with the symbol count.
* fix(scripts): run the ELF unwind verifier under owned process trees
Launch probes, compiler drivers, the stripper, the frame dump and the
inspection through createVerifierCommands, as verify-binary-hardening
does, so a timeout or interrupt stops the whole tree. The temporary
directory is removed only after the owned commands have closed.
* docs(elf): move ELF unwind ranges guide under docs/guides/native
The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /elf-unwind-ranges route is unchanged.
* fix(elf): give unwind text limits their own recovery and skip indirect tables
Throw a dedicated failure when a page's symbol names exceed the 16 MiB
text allowance, and map it to a resource error that tells the caller
to request a smaller limit rather than raise max_ranges.
Read a CIE augmentation with one bounded NUL search and keep it as a
byte view, decoded only for returned CIEs, so a long augmentation is
never built up character by character.
Leave an .eh_frame_hdr search table with an indirect encoding unread:
the header is incomplete, the comparison is unavailable, and the table
no longer bounds a header-located .eh_frame scan.
* fix(elf): resolve header count and table forms and name IFUNC resolvers
Leave a non-zero .eh_frame_hdr FDE count under an indirect encoding
unresolved, since it is the address of a slot that is not followed, and
mark the header incomplete without reading the table.
Treat a DW_EH_PE_omit table encoding as an omitted search table before
testing the indirect bit, so a header that declares a count without a
table stays present with complete coverage, and accept that form in
output validation.
Match STT_GNU_IFUNC symbols at exact FDE starts after function symbols,
with a limitation that the name is the resolver, not the implementation
it selects at run time.
* fix(elf): require allocated unwind pointer bases
* fix(elf): map unwind header relative base
* fix(elf): validate unwind load mappings
* test(elf): cover mapped nonallocated frame agreement
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* feat(elf): report a Linux kernel image's version banner and embedded build config
inspect_kernel_build_config and inspect-kernel-build-config read one
local vmlinux, raw arm64 Image, gzip bzImage or zImage, or configs.ko
and report its Linux version banner and the IKCONFIG .config embedded
between IKCFG_ST and IKCFG_ED, without executing it. A config is present
only when a gzip member ends exactly at IKCFG_ED, passes its CRC-32 and
ISIZE checks and parses as .config text; framing that fails is reported
malformed, never absent. bzImage gzip payloads are inflated within a
budget and other codecs are named as unsupported, using codec detection
now shared with the kernel module parser. The config search, inflate
sizes and option counts are bounded, scans honor cancellation, and
target-derived text is marked untrusted.
* fix(elf): reject a gzip member whose header checksum fails
When FHCRC is set, compare the low 16 bits of the header CRC-32 before
inflating, so a damaged header no longer yields a present config or an
inflated bzImage payload.
* fix(elf): detect the bzImage codec inside the declared payload
Codec detection now reads the same payload_offset/payload_length slice that
is inflated, so bytes past a short payload cannot name its codec.
* fix(elf): report a framed config that does not decode as malformed
A damaged or cut-off deflate stream between IKCFG_ST and IKCFG_ED was
skipped and could end as an absent config with complete coverage. It is
now malformed with config_gzip_invalid, and a later valid config still wins.
* fix(elf): scan config lines in place and accept long string values
Config text is read one line at a time instead of split into an array, and
a quoted value is validated before it is decoded once. The 4096-character
string cap is removed: Kconfig has no such limit and max_config_bytes
already bounds every line, so a long CONFIG_EXTRA_FIRMWARE list is no
longer reported as malformed.
* fix(elf): let a live cancellation reach the kernel config parser
The parser ran synchronously, so an abort raised during parsing could not
change the signal before it returned. Inflation now runs on the zlib thread
pool and each scan yields to the event loop once per MiB, so the existing
cancellation checks observe a real abort.
* refactor(elf): carry the refused kernel config budget as a typed fact
Budget failures are now KernelBuildConfigBudgetFailure with a knob field,
and the provider builds its recovery advice from that field instead of
searching the diagnostic message for an option name.
* docs(elf): move the kernel build config guide under docs/guides/native
The documentation guide assigns analyst workflows to docs/guides/<domain>/.
Move the guide there, place its navigation and directory entries in the
Native binaries group, and update links from the docs index, CLI guide,
spec and authored skill. The public /kernel-build-config route is unchanged.
* fix(elf): yield while checking one long config line
A config made of one long quoted value never reached the per-line yield, so
the control-byte check, value validation and SHA-256 ran in one synchronous
block. Each now works one MiB window per event-loop turn, and the line
patterns match only a bounded name prefix instead of the whole value.
* fix(elf): return paged config entries that do not pin the decoded text
Entry names and values were V8 slices of the whole decoded config, so a
one-entry page kept the full text alive. Entries in the returned page are
now standalone copies, so retained memory follows the page size.
* fix(elf): yield while kernel marker searches find nothing
IKCFG_ST, IKCFG_ED and banner searches used one Buffer.indexOf over the
rest of the image, so a large image with no marker never yielded. They now
search overlapping one MiB windows and yield after each window without a
match.
* fix(elf): preserve long kernel config names
* fix(elf): frame kernel configs by gzip member boundaries
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
* test(javascript): distinguish package scope in route fixtures
* test(apple): separate identity and refusal fixture groups
* fix(electron): preserve uncertainty in indirect listener ownership