Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Security Assurance Case

This document provides a structured argument that mmap-guard meets its security requirements.

Frameworks Referenced

This assurance case draws on three complementary frameworks:

  • NIST IR 7608 – structured assurance case model. Provides the overall argument structure (security requirements, threat model, trust boundaries, countermeasures).
  • NIST SSDF (SP 800-218) – Secure Software Development Framework. Maps our development practices to the four SSDF practice groups (PO, PS, PW, RV). See Section 10.
  • SLSA v1.0 – Supply-chain Levels for Software Artifacts. Defines progressive build integrity levels. See Section 11.

1. Security Requirements

mmap-guard is a safe wrapper around memmap2::Mmap::map() that isolates the single unsafe call behind a hardened boundary. Its security requirements are:

  1. SR-1: Must not exhibit undefined behavior when mapping any file
  2. SR-2: Must not allow use-after-unmap of memory-mapped regions
  3. SR-3: Must not create mutable aliasing of mapped memory
  4. SR-4: Must not allow path traversal via file path arguments
  5. SR-5: Must validate all pre-flight conditions (non-empty, permissions) before the unsafe mmap call
  6. SR-6: Must hold advisory locks for the full lifetime of the mapping
  7. SR-7: Must not leak file descriptors or mappings across FileData instances

2. Threat Model

2.1 Assets

  • Host system: The machine running mmap-guard
  • Mapped file contents: Data being mapped (may be sensitive)
  • File descriptors: OS resources held by FileData::Mapped

2.2 Threat Actors

ActorMotivationCapability
Malicious file authorExploit the mmap call to cause undefined behavior or DoSCan craft arbitrary file contents
Concurrent processTruncate or modify a mapped file to trigger SIGBUSCan write to or truncate files on the same filesystem
Supply chain attackerCompromise a dependency to inject unsafe codeCan publish malicious crate versions

2.3 Attack Vectors

IDVectorTarget SR
AV-1Crafted file triggers undefined behavior in the unsafe mmap callSR-1
AV-2Concurrent truncation causes SIGBUS (Unix) or access violation (Windows)SR-1
AV-3Empty file causes panic in mappingSR-1, SR-5
AV-4TOCTOU race between stat check and mmap callSR-5
AV-5Compromised dependency introduces unsafe codeSR-1, SR-2, SR-3

3. Trust Boundaries

flowchart TD
    subgraph Untrusted["Untrusted Zone"]
        direction LR
        FP["File Paths<br/>(user input)"]
        FC["File Contents<br/>(any data)"]
        CP["Concurrent Processes<br/>(may truncate files)"]
    end

    subgraph mmap-guard["mmap-guard (Trusted Zone)"]
        PF["Pre-flight Checks<br/>exists, non-empty, permissions"]
        AL["Advisory Locking<br/>fs4 try_lock_shared"]
        UB["Unsafe Boundary<br/>single Mmap::map() call"]
        FD["FileData<br/>Mmap + File lifetime coupling"]
    end

    FP -- "path" --> PF
    FC -- "file bytes" --> UB
    CP -- "filesystem ops" --> AL
    PF -- "validated file" --> AL
    AL -- "locked file" --> UB
    UB -- "mapped region" --> FD

    style Untrusted fill:#4a1a1a,stroke:#ef5350,color:#e0e0e0,stroke-width:2px
    style mmap-guard fill:#1b3d1b,stroke:#66bb6a,color:#e0e0e0,stroke-width:2px

All data crossing the trust boundary (file paths, file contents) is treated as untrusted and validated before use. Concurrent processes are mitigated through cooperative advisory locking.

4. Secure Design Principles (Saltzer and Schroeder)

PrincipleHow Applied
Economy of mechanismThin wrapper with 4 source files and 2 runtime dependencies (memmap2, fs4). No plugin system, no network I/O, no configuration files.
Fail-safe defaultsPre-flight checks reject empty files and permission errors before reaching unsafe code. Advisory lock uses try_lock_shared (non-blocking), returning WouldBlock rather than deadlocking.
Complete mediationEvery file path goes through the full open -> stat -> lock -> map pipeline. No shortcut paths bypass validation.
Open designFully open source (Apache-2.0). Security does not depend on obscurity. All safety mechanisms are publicly documented.
Separation of privilegemap.rs (unsafe boundary) and load.rs (convenience layer) are separate modules with distinct responsibilities.
Least privilegeRead-only mappings only. No mutable or writable mappings are created. No write, execute, or network capabilities.
Least common mechanismNo shared mutable state. Each FileData instance is independent with its own file descriptor and advisory lock.
Psychological acceptabilityStandard io::Result error handling. Familiar Deref<Target=[u8]> API. Consumers treat FileData as &[u8] without caring about the backing storage.

5. The Unsafe Boundary

Unlike most Rust crates which use #![forbid(unsafe_code)], mmap-guard is the unsafe boundary. It exists specifically to contain the one unsafe call that downstream #![forbid(unsafe_code)] crates cannot make themselves.

The crate enforces:

  • Exactly one unsafe block in the entire crate (in src/map.rs). Adding new ones requires an issue discussion.
  • #![deny(clippy::undocumented_unsafe_blocks)] – every unsafe block must have a // SAFETY: comment explaining why the invariants are upheld.
  • Strict clippy lints: unwrap_used = "deny", panic = "deny", full pedantic/nursery/cargo groups enabled.

Safety Invariants

The safety of memmap2::Mmap::map() relies on these conditions, all of which mmap-guard upholds:

InvariantHow It’s Upheld
File opened read-onlyFile::open() opens in read-only mode
File descriptor stays aliveFile is kept alive inside FileData::Mapped for the full mapping lifetime
No use-after-unmap&[u8] lifetime is tied to FileData via Deref
No mutable aliasingOnly read-only mappings are created
Advisory lock heldfs4::FileExt::try_lock_shared is called before mapping; the lock-owning File lives inside FileData::Mapped

6. Common Weakness Countermeasures

6.1 CWE/SANS Top 25

CWEWeaknessCountermeasureStatus
CWE-416Use after freeRust ownership system prevents use-after-free at compile time. Mmap and File are co-located in FileData::Mapped, ensuring the mapping and file descriptor are dropped together.Mitigated
CWE-476NULL pointer dereferenceRust’s Option type eliminates null pointer dereferences at compile time.Mitigated
CWE-125Out-of-bounds readMemory-mapped regions have a known size derived from File::metadata(). Deref returns a slice with correct bounds.Mitigated
CWE-22Path traversalRead-only access only. Paths are resolved by std::fs::File::open() with no path construction from file contents.Mitigated
CWE-20Improper input validationPre-flight checks validate file existence, non-empty size, and permissions before the unsafe call.Mitigated
CWE-400Resource exhaustionEmpty file pre-check prevents zero-length mapping. try_lock_shared returns WouldBlock instead of blocking indefinitely.Mitigated
CWE-190Integer overflowFile size comes from OS metadata via std::fs::Metadata::len(), which returns u64. No manual arithmetic on sizes.Mitigated
CWE-362Race condition (TOCTOU)Advisory lock acquired between stat check and mmap call reduces the window. Fully preventing TOCTOU requires OS-level guarantees beyond advisory locking.Partially mitigated
CWE-787Out-of-bounds writeNot applicable – only read-only mappings are created. No writes to mapped memory.N/A
CWE-78OS command injectionNot applicable – no shell invocation or command execution.N/A
CWE-89SQL injectionNot applicable – no database.N/A
CWE-79XSSNot applicable – no web output.N/A

6.2 OWASP Top 10 (where applicable)

Most OWASP Top 10 categories target web applications and are not applicable to a memory-mapping library. The applicable items are:

CategoryApplicabilityCountermeasure
A04: Insecure DesignApplicableSecure design principles applied throughout (see Section 4)
A06: Vulnerable ComponentsApplicablecargo audit daily, cargo deny, Dependabot, OSSF Scorecard
A09: Security LoggingPartialErrors returned via io::Result; security events reported via GitHub Advisories

7. Known Limitation: SIGBUS / Access Violation

If the underlying file is truncated or modified by another process while mapped, the operating system may deliver:

  • Unix: SIGBUS signal
  • Windows: Access violation (structured exception)

This is inherent to memory-mapped I/O and cannot be fully prevented. It is explicitly out of scope for security reports (see SECURITY.md).

Mitigation

mmap-guard acquires a cooperative shared advisory lock via fs4::FileExt::try_lock_shared before creating the mapping. This is advisory only – it relies on other processes cooperating. The lock and mapping lifetimes are coupled through FileData::Mapped(Mmap, File).

For applications needing stronger guarantees:

  1. Advisory locking – rely on mmap-guard’s built-in shared lock (cooperative)
  2. Signal handling – install a SIGBUS handler that can recover gracefully (complex and platform-specific)
  3. Copy-on-read – for small files, prefer std::fs::read() via the FileData::Loaded path

8. Supply Chain Security

MeasureImplementation
Dependency auditingcargo audit and cargo deny run daily in CI
Dependency updatesDependabot configured for weekly automated PRs (cargo, github-actions, devcontainers)
Pinned toolchainRust stable via mise
Reproducible buildsCargo.lock and mise.lock committed
SBOM generationcargo-cyclonedx produces CycloneDX SBOM attached to GitHub Releases
Build provenanceSigstore attestation of the crate tarball (cargo package output)
CI integrityAll GitHub Actions pinned to SHA hashes
Code reviewRequired on all PRs
OSSF ScorecardWeekly supply-chain assessment with SARIF upload to GitHub code-scanning
Banned dependenciescargo deny blocks openssl, git2, cmake, libssh2-sys, unknown registries

Note: cargo-auditable is not applicable – it embeds dependency metadata in ELF/PE binaries, which do not exist for a library crate. SBOM and provenance attestation cover the equivalent supply chain visibility.

9. Ongoing Assurance

This assurance case is maintained as a living document. It is updated when:

  • New features introduce new attack surfaces
  • New threat vectors are identified
  • Dependencies change significantly
  • Security incidents occur

The project maintains continuous assurance through automated CI checks (clippy, cargo audit, cargo deny, OSSF Scorecard) that run on every commit and on daily schedules.

10. SSDF Practice Mapping

This section maps mmap-guard’s development practices to the NIST Secure Software Development Framework (SP 800-218) practice groups.

PO: Prepare the Organization

TaskImplementationStatus
PO.1: Define security requirementsSecurity requirements SR-1 through SR-7 defined in this documentDone
PO.3: Implement supporting toolchainsmise manages all dev tools; pre-commit hooks enforce checks locallyDone
PO.5: Implement and maintain secure environmentsCI runs on ephemeral GitHub Actions runners; minimal permissions per workflowDone

PS: Protect the Software

TaskImplementationStatus
PS.1: Protect all forms of code from unauthorized access and tamperingGitHub branch protection on main; Mergify merge protections; required PR reviewsDone
PS.2: Provide a mechanism for verifying software release integrityCycloneDX SBOM attached to GitHub Releases; Sigstore attestation of crate tarballPlanned
PS.3: Archive and protect each software releaseGitHub Releases with tagged versions; crates.io immutable publishing via release-plzDone

PW: Produce Well-Secured Software

TaskImplementationStatus
PW.1: Design software to meet security requirementsSaltzer and Schroeder principles applied (Section 4); single unsafe block policyDone
PW.4: Reuse existing, well-secured softwareDelegates to memmap2 (vetted mmap wrapper) and fs4 (advisory locking)Done
PW.5: Create source code by adhering to secure coding practicesclippy::undocumented_unsafe_blocks = "deny", unwrap_used = "deny", panic = "deny", pedantic/nursery/cargo lint groupsDone
PW.6: Configure the compilation and build processes to improve executable securityRelease builds via cargo build --release; all clippy lints promoted to errors in CIDone
PW.7: Review and/or analyze human-readable code to identify vulnerabilitiesRequired PR reviews; OSSF Scorecard; cargo clippy with strict configurationDone
PW.8: Test executable code to identify vulnerabilitiesnextest on 4-platform matrix; 85% coverage threshold enforced; cargo audit and cargo denyDone

RV: Respond to Vulnerabilities

TaskImplementationStatus
RV.1: Identify and confirm vulnerabilities on an ongoing basisDaily cargo audit and cargo deny in CI; weekly OSSF Scorecard; Dependabot PRsDone
RV.2: Assess, prioritize, and remediate vulnerabilitiesSECURITY.md defines scope, reporting channels, and 90-day fix targetDone
RV.3: Analyze vulnerabilities to identify their root causesSecurity advisories coordinated via GitHub Private Vulnerability ReportingDone

11. SLSA Build Level Assessment

This section assesses mmap-guard’s current SLSA v1.0 build level and identifies gaps for advancement.

Current Level: Build L1

RequirementStatusEvidence
Build L1: Provenance exists showing how the package was builtMetCI workflow on GitHub Actions; build logs publicly visible; release-plz automates crate publishing from CI

Build L2 Requirements (target)

RequirementStatusGap
Builds run on a hosted build serviceMetGitHub Actions (ephemeral runners)
Build service generates provenancePartialGitHub Actions provides workflow run metadata, but no signed SLSA provenance document is generated
Provenance is signed by the build serviceNot yetNeed to add slsa-framework/slsa-github-generator or Sigstore attestation to the release workflow
Provenance is complete (source, builder, build config)Not yetRequires SLSA provenance generator integration

Build L3 Requirements (aspirational)

RequirementStatusGap
Hardened build platformPartialGitHub Actions provides isolation between jobs, but not the full L3 hermetic build guarantee
Builds are isolated from one anotherMetEach CI run uses a fresh ephemeral runner
Provenance is unforgeableNot yetRequires L2 first

Roadmap to Build L2

  1. Add slsa-framework/slsa-github-generator to the release workflow to produce signed SLSA provenance
  2. Attach the provenance attestation to the GitHub Release alongside the SBOM
  3. Document verification steps for consumers (slsa-verifier)