# 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 ```json { "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 function - `root:init:0:sym:binary:def...` - DT_INIT function - `root:init:1:sym:binary:ghi...` - First init_array entry - `root:main:0:sym:binary:jkl...` - main() function - `root: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: ```json { "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 ```json { "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 ```json { "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 ```json { "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: 1. If vulnerable function is reachable from `main` → `REACHABLE` 2. If vulnerable function is reachable from `init` roots → `REACHABLE_INIT` 3. If vulnerable function is reachable only from `fini` → `REACHABLE_FINI` ### 6.2 Policy DSL Extensions ```yaml # 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 ```json { "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: 1. Phase (numeric: load=0, preinit=1, init=2, main=3, fini=4) 2. Order within phase (numeric) 3. 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](./richgraph-v1.md) - Root schema in graphs - [Build-ID Propagation](./buildid-propagation.md) - Binary identification - [Patch Oracles](../reachability/patch-oracles.md) - Oracle validation --- ## Changelog | Version | Date | Author | Changes | |---------|------|--------|---------| | 1.0.0 | 2025-12-13 | Scanner Guild | Initial contract for init-section roots |