Skip to content

feat(cpp): opt-in debug hardening — freed-block poisoning, canaries, free-list safe-linking #109

Description

@danielPoloWork

Summary

Add an opt-in, debug-only hardening mode for the free list, behind a compile-time knob,
that provides: (1) freed-block poisoning, (2) optional block canaries for
overflow/underflow detection, and (3) free-list next-pointer safe-linking (glibc-style
XOR obfuscation). Release builds stay byte-for-byte and cycle-for-cycle unchanged; the
hardening is a separate configuration.

An intrusive free list stores the next-pointer inside freed blocks, which is a classic
use-after-free / pointer-corruption exploitation primitive. The spec review (#105) flags
that the project has "no mention of pointer obfuscation, freed-block poisoning, or debug
canaries" despite the rest of the repo holding an enterprise/security posture
(SECURITY.md).

Motivation

  • Bug-finding. Poisoning turns silent use-after-free into a loud, deterministic crash
    (reads of poisoned memory are obviously wrong; a poisoned next-pointer faults on the next
    alloc). Canaries catch the fixed-block internal-overflow case that ASan's redzones don't
    see inside a pool-owned region.
  • Didactic value. Safe-linking is a real, shipping allocator hardening technique
    (glibc ≥ 2.32). Demonstrating it — with an ADR explaining the threat model and the
    PROTECT_PTR/REVEAL_PTR transform — is squarely in this project's "exercise
    production-grade techniques and justify them" mandate (ADR-0003).
  • Complements, not replaces, ASan: ASan is unavailable on MSVC and cannot instrument the
    pool's own sub-block boundaries; a self-contained debug mode works everywhere the
    library builds.

Design sketch (needs a new ADR — this touches the free-list layout, ADR-0009)

  • Compile-time knob, e.g. PBR_MEMORY_POOL_HARDENING (OFF by default), not a runtime
    branch on the hot path — preserves the ADR-0014 benchmark numbers and the ADR-0015
    overhead budget in release.
  • Poisoning: on free, fill the block with a recognizable pattern (e.g. 0xDEADBEEF)
    after threading the next-pointer; on alloc, optionally verify the pattern is intact
    (detects writes to freed blocks) before handing the block out.
  • Safe-linking: store next XOR (addr >> PAGE_SHIFT) instead of the raw next-pointer,
    so a leaked/overwritten free-list pointer is not directly usable and corruption is
    detected via an alignment check on reveal. Access stays strict-aliasing-safe (ADR-0009).
  • Canaries: optional guard word(s) at block boundaries, validated on free; requires a
    documented interaction with the block-size/alignment math (canaries cost usable bytes, so
    this is a distinct sub-mode, possibly its own knob).
  • Must work across dynamic-growth chunks (ADR-0022/0023) and remain compatible with the
    thread-safe configuration (ADR-0020) and the InstrumentedPool decorator (ADR-0025).
  • On detection: behaviour per a documented policy (abort with a diagnostic in debug),
    reusing the foreign/double-free stance already set in
    ADR-0012 — and note
    that safe-linking makes double-free detection cheaper.

Scope & compatibility

  • Additive & opt-in. Zero change to the frozen v1.0.0 ABI or to the default build.
    SemVer MINOR (next MINOR, e.g. v1.2.0) per ADR-0004.
  • Because it changes the on-disk free-list encoding only when enabled, a hardened build is
    not memory-layout-compatible with a non-hardened one — that is fine (never mix
    configurations) and must be stated explicitly.

Acceptance criteria

  • New ADR records the threat model, the three sub-features, the on/off knob(s), and the
    detection/abort policy; cross-links ADR-0009/0012/0015.
  • With hardening ON, a use-after-free, a buffer overflow past block_size, and a
    double-free are each detected deterministically (covered by tests).
  • With hardening OFF, the benchmark (ADR-0014) and the metadata-overhead budget
    (ADR-0015) are unchanged — verified.
  • Works with fixed and dynamic pools, single-thread and thread-safe configs.
  • README security section, SECURITY.md, spec §4, and Doxygen updated; patterns
    catalogue updated if a pattern is introduced.
  • Clean under the full quality bar in both configurations.

References

Metadata

Metadata

Labels

enhancementNew feature or requestfeatNew feature (Conventional Commit: feat)

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions