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

Part of the Stella Ops Contracts index. Audience: Scanner, Policy, and Signals implementers who produce or consume reachability roots, and reviewers verifying that init-phase code is accounted for in vulnerability assessment.

Overview

This contract defines how ELF/PE/Mach-O initialization sections (.init_array, .ctors, DT_INIT, etc.) are modeled as synthetic roots in Stella Ops reachability graphs. These roots represent code that executes during program load, before main() — code that a naive main-only traversal would miss but that must be included in reachability analysis for complete vulnerability assessment.


1. Init-Section Categories

1.1 ELF Init Sections

Section/TagPhaseOrderDescription
.preinit_array / DT_PREINIT_ARRAYpreinit0-NExecuted before dynamic linker init
.init / DT_INITinit0Single init function
.init_array / DT_INIT_ARRAYinit1-NArray of init function pointers
.ctorsinitafter init_arrayLegacy C++ constructors
.fini / DT_FINIfini0Single cleanup function
.fini_array / DT_FINI_ARRAYfini1-NArray of cleanup function pointers
.dtorsfiniafter fini_arrayLegacy C++ destructors

1.2 PE Init Sections

MechanismPhaseOrderDescription
DllMain (DLL_PROCESS_ATTACH)init0DLL initialization
TLS callbacksinit1-NThread-local storage callbacks
C++ global constructorsinitafter TLSVia CRT init table
DllMain (DLL_PROCESS_DETACH)fini0DLL cleanup

1.3 Mach-O Init Sections

SectionPhaseOrderDescription
__mod_init_funcinit0-NModule init functions
__mod_term_funcfini0-NModule 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:

2.3 Phase Enumeration

PhaseNumeric OrderExecution Time
load0Dynamic linker resolution
preinit1Before dynamic init
init2During initialization
main3Program entry (main)
fini4During 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:

  1. If vulnerable function is reachable from mainREACHABLE
  2. If vulnerable function is reachable from init roots → REACHABLE_INIT
  3. If vulnerable function is reachable only from finiREACHABLE_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:

  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

ComponentLocationStatus
ELF init parserNativeCallgraphBuilder.csImplemented
Root modelNativeSyntheticRootImplemented
richgraph-v1 rootsRichGraph.csImplemented
Patch oracle rootsPatchOracleComparer.csImplemented
Policy integration-Pending
DT_NEEDED graph-Pending

10. Test Fixtures

Location: tests/Binary/fixtures/init-roots/

FixtureDescription
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


Changelog

VersionDateAuthorChanges
1.0.02025-12-13Scanner GuildInitial contract for init-section roots