8.0 KiB
CONTRACT-INIT-ROOTS-401: Init-Section Synthetic Roots
Status: Published Version: 1.0.0 Published: 2025-12-13 Owners: Scanner Guild, Policy Guild, Signals Guild Unblocks: SCANNER-INITROOT-401-036, EDGE-BUNDLE-401-054, and downstream tasks
Overview
This contract defines how ELF/PE/Mach-O initialization sections (.init_array, .ctors, DT_INIT, etc.) are modeled as synthetic roots in reachability graphs. These roots represent code that executes during program load, before main(), and must be included in reachability analysis for complete vulnerability assessment.
1. Init-Section Categories
1.1 ELF Init Sections
| Section/Tag | Phase | Order | Description |
|---|---|---|---|
.preinit_array / DT_PREINIT_ARRAY |
preinit |
0-N | Executed before dynamic linker init |
.init / DT_INIT |
init |
0 | Single init function |
.init_array / DT_INIT_ARRAY |
init |
1-N | Array of init function pointers |
.ctors |
init |
after init_array | Legacy C++ constructors |
.fini / DT_FINI |
fini |
0 | Single cleanup function |
.fini_array / DT_FINI_ARRAY |
fini |
1-N | Array of cleanup function pointers |
.dtors |
fini |
after fini_array | Legacy C++ destructors |
1.2 PE Init Sections
| Mechanism | Phase | Order | Description |
|---|---|---|---|
DllMain (DLL_PROCESS_ATTACH) |
init |
0 | DLL initialization |
| TLS callbacks | init |
1-N | Thread-local storage callbacks |
| C++ global constructors | init |
after TLS | Via CRT init table |
DllMain (DLL_PROCESS_DETACH) |
fini |
0 | DLL cleanup |
1.3 Mach-O Init Sections
| Section | Phase | Order | Description |
|---|---|---|---|
__mod_init_func |
init |
0-N | Module init functions |
__mod_term_func |
fini |
0-N | Module termination functions |
2. Synthetic Root Schema
2.1 Root Object in richgraph-v1
{
"roots": [
{
"id": "root:init:0:sym:binary:abc123...",
"phase": "init",
"source": "init_array",
"order": 0,
"target_id": "sym:binary:abc123...",
"binary_path": "/usr/lib/libfoo.so.1",
"build_id": "gnu-build-id:5f0c7c3c..."
}
]
}
2.2 Root ID Format
root:{phase}:{order}:{target_symbol_id}
Examples:
root:preinit:0:sym:binary:abc...- First preinit functionroot:init:0:sym:binary:def...- DT_INIT functionroot:init:1:sym:binary:ghi...- First init_array entryroot:main:0:sym:binary:jkl...- main() functionroot:fini:0:sym:binary:mno...- DT_FINI function
2.3 Phase Enumeration
| Phase | Numeric Order | Execution Time |
|---|---|---|
load |
0 | Dynamic linker resolution |
preinit |
1 | Before dynamic init |
init |
2 | During initialization |
main |
3 | Program entry (main) |
fini |
4 | During termination |
3. Root Discovery Algorithm
3.1 ELF Root Discovery
1. Parse .dynamic section for DT_PREINIT_ARRAY, DT_INIT, DT_INIT_ARRAY
2. For each array:
a. Read function pointer addresses
b. Resolve to symbol (if available) or emit unknown
c. Create root with phase + order
3. Find _start, main, _init, _fini symbols and add as roots
4. Sort roots by (phase, order, target_id) for determinism
3.2 Handling Unresolved Targets
When init array contains address without symbol:
{
"roots": [
{
"id": "root:init:2:unknown:0x12345678",
"phase": "init",
"source": "init_array",
"order": 2,
"target_id": "unknown:0x12345678",
"resolved": false,
"reason": "No symbol at address 0x12345678"
}
],
"unknowns": [
{
"id": "unknown:0x12345678",
"type": "unresolved_init_target",
"address": "0x12345678",
"source": "init_array[2]"
}
]
}
4. DT_NEEDED Dependency Modeling
4.1 Purpose
DT_NEEDED entries specify shared library dependencies. These execute their init code before the depending binary's init code.
4.2 Schema
{
"dependencies": [
{
"id": "dep:libssl.so.3",
"name": "libssl.so.3",
"source": "DT_NEEDED",
"order": 0,
"resolved_path": "/usr/lib/x86_64-linux-gnu/libssl.so.3",
"resolved_build_id": "gnu-build-id:abc..."
}
]
}
4.3 Init Order with Dependencies
1. libssl.so.3 preinit → init
2. libcrypto.so.3 preinit → init
3. libc.so.6 preinit → init
4. main_binary preinit → init → main
5. Patch Oracle Integration
5.1 Oracle Expected Roots
{
"expected_roots": [
{
"id": "root:init:*:sym:binary:*",
"phase": "init",
"source": "init_array",
"required": true,
"reason": "Init function must be detected for CVE-2023-XXXX"
}
]
}
5.2 Oracle Forbidden Roots
{
"forbidden_roots": [
{
"id": "root:preinit:*:*",
"phase": "preinit",
"reason": "Preinit code should not exist after patch"
}
]
}
6. Policy Integration
6.1 Reachability State with Init Roots
When evaluating reachability:
- If vulnerable function is reachable from
main→REACHABLE - If vulnerable function is reachable from
initroots →REACHABLE_INIT - If vulnerable function is reachable only from
fini→REACHABLE_FINI
6.2 Policy DSL Extensions
# Require init-phase reachability for not_affected
rules:
- name: init-reachability-required
condition: |
vuln.phase_reachable.includes("init") and
reachability.confidence >= 0.8
action: require_evidence
- name: init-only-lower-severity
condition: |
reachability.reachable_phases == ["init"] and
not reachability.reachable_phases.includes("main")
action: reduce_severity
severity_adjustment: -1
7. Evidence Requirements
7.1 Init Root Evidence Bundle
{
"root_evidence": {
"root_id": "root:init:0:sym:binary:...",
"extraction_method": "dynamic_section",
"source_offset": "0x1234",
"target_address": "0x5678",
"target_symbol": "frame_dummy",
"evidence_hash": "sha256:...",
"evidence_uri": "cas://binary/roots/sha256:..."
}
}
7.2 CAS Storage Layout
cas://reachability/roots/{graph_hash}/
init.json # All init-phase roots
fini.json # All fini-phase roots
dependencies.json # DT_NEEDED graph
evidence/
root:{id}.json # Per-root evidence
8. Determinism Rules
8.1 Root Ordering
Roots are sorted by:
- Phase (numeric: load=0, preinit=1, init=2, main=3, fini=4)
- Order within phase (numeric)
- Target ID (string, ordinal)
8.2 Root ID Canonicalization
root_id = "root:" + phase + ":" + order + ":" + target_id
All components lowercase, no whitespace.
9. Implementation Status
| Component | Location | Status |
|---|---|---|
| ELF init parser | NativeCallgraphBuilder.cs |
Implemented |
| Root model | NativeSyntheticRoot |
Implemented |
| richgraph-v1 roots | RichGraph.cs |
Implemented |
| Patch oracle roots | PatchOracleComparer.cs |
Implemented |
| Policy integration | - | Pending |
| DT_NEEDED graph | - | Pending |
10. Test Fixtures
Location: tests/Binary/fixtures/init-roots/
| Fixture | Description |
|---|---|
elf-simple-init/ |
Binary with single init function |
elf-init-array/ |
Binary with multiple init_array entries |
elf-preinit/ |
Binary with preinit_array |
elf-ctors/ |
Binary with .ctors section |
elf-stripped-init/ |
Stripped binary with init |
pe-dllmain/ |
PE DLL with DllMain |
pe-tls-callbacks/ |
PE with TLS callbacks |
11. Related Contracts
- richgraph-v1 - Root schema in graphs
- Build-ID Propagation - Binary identification
- Patch Oracles - Oracle validation
Changelog
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-12-13 | Scanner Guild | Initial contract for init-section roots |