2026-09-14 10:58:35 +00:00
|
|
|
# Security Policy
|
|
|
|
|
|
|
|
|
|
## Supported versions
|
|
|
|
|
|
|
|
|
|
No version has been tagged yet (see `CHANGELOG.md`); this project is
|
|
|
|
|
pre-1.0 (`README.md`'s "Status"). Only the latest commit on the default
|
|
|
|
|
branch is supported — there is no LTS branch and no backport policy while
|
|
|
|
|
the project is at `0.x`.
|
|
|
|
|
|
|
|
|
|
## What PackFS actually claims as a security boundary
|
|
|
|
|
|
|
|
|
|
Stated precisely, per this project's documentation standard (`CLAUDE.md`),
|
|
|
|
|
rather than a generic "we take security seriously":
|
|
|
|
|
|
|
|
|
|
- **Path containment for `dir` mounts is a hard requirement** (`concept.md`
|
|
|
|
|
Section 6, `CLAUDE.md`'s "Load-bearing constraints"). On Linux 5.6+,
|
|
|
|
|
every lookup beneath a `dir` mount uses `openat2(RESOLVE_BENEATH |
|
|
|
|
|
RESOLVE_NO_SYMLINKS)` to atomically block `..` escapes, symlink escapes,
|
|
|
|
|
and the canonicalize-then-open TOCTOU window in one kernel call.
|
|
|
|
|
`vfs_harden_process_with_landlock` (Section 6.2) is an additional,
|
|
|
|
|
**opt-in** kernel-level layer — not applied automatically, since
|
|
|
|
|
Landlock restrictions are cumulative, irreversible, and process-wide,
|
|
|
|
|
which would be a surprising side effect for an embeddable library to
|
|
|
|
|
trigger on its own.
|
|
|
|
|
- **On platforms or kernels without `openat2`, containment falls back to
|
|
|
|
|
per-component `O_NOFOLLOW` plus canonicalize-and-verify** (Section 6.3)
|
|
|
|
|
— an accepted, **explicitly weaker** residual-risk posture, not a claim
|
|
|
|
|
of equal strength. Code and documentation that describe this fallback as
|
|
|
|
|
equivalent to the `openat2` path would themselves be a bug worth
|
|
|
|
|
reporting.
|
|
|
|
|
- **The VFS core canonicalizes `.`/`..` in the virtual namespace itself**,
|
|
|
|
|
before any backend is reached, so a crafted path cannot escape a mount's
|
|
|
|
|
prefix even when no host directory is involved.
|
|
|
|
|
- **A pack file is treated as untrusted input unless it came from this
|
|
|
|
|
run's own compaction** (Section 7). Every index entry's offsets and
|
|
|
|
|
sizes are bounds-checked against the actual file/strings-region length
|
|
|
|
|
before being trusted; a failed check invalidates the whole pack load. An
|
|
|
|
|
externally-sourced pack additionally needs a checksum verified at load.
|
|
|
|
|
Loading an attacker-supplied `.img` file that PackFS accepts without
|
|
|
|
|
detecting corruption, or that causes an out-of-bounds read/write, is a
|
|
|
|
|
security bug.
|
|
|
|
|
- **Journal records are length/checksum self-describing** (Section 4.4),
|
|
|
|
|
so replay stops cleanly at the first torn or corrupted record rather
|
|
|
|
|
than reading past it.
|
|
|
|
|
|
|
|
|
|
## What PackFS explicitly does *not* claim
|
|
|
|
|
|
|
|
|
|
Reporting these as vulnerabilities is not necessary — they are documented,
|
|
|
|
|
known limitations, not silent gaps:
|
|
|
|
|
|
|
|
|
|
- **`mode` (permission bits, symlinks, hard links) is stored and restored
|
|
|
|
|
but not enforced.** Nothing in the VFS core interprets it as an access
|
|
|
|
|
control boundary in v0 (`concept.md` Section 10).
|
|
|
|
|
- **Cross-process concurrency is specified (an LMDB-style reader-table
|
|
|
|
|
design, Section 5.6) but not implemented.** Two uncoordinated processes
|
|
|
|
|
writing the same host directory through a `dir` mount are not
|
|
|
|
|
synchronized against each other.
|
|
|
|
|
- **`zip`/`tar` are permanently out of scope** (`CLAUDE.md`, "Project
|
|
|
|
|
decisions that supersede concept.md") — there is no archive-format
|
|
|
|
|
parsing code in this project to have a vulnerability in.
|
|
|
|
|
|
|
|
|
|
## Reporting a vulnerability
|
|
|
|
|
|
2026-09-14 11:03:20 +00:00
|
|
|
This project is hosted on Gitea, not GitHub (see `CONTRIBUTING.md`).
|
|
|
|
|
Please do not open a public issue on the issue tracker for a suspected
|
|
|
|
|
security vulnerability — report it privately, by email, to the
|
|
|
|
|
maintainer:
|
2026-09-14 10:58:35 +00:00
|
|
|
|
|
|
|
|
**retoor** — `retoor@molodetz.nl`
|
|
|
|
|
|
|
|
|
|
When reporting, include: the affected function(s) or file(s), a minimal
|
|
|
|
|
reproduction (ideally as a `tests/test_*.c`-style program using only the
|
|
|
|
|
public API in `include/packfs.h`), and which of the guarantees above (or
|
|
|
|
|
which `concept.md` section) you believe is violated — this project's own
|
|
|
|
|
verification discipline (`make test`, ASan/UBSan/TSan per `CONTRIBUTING.md`)
|
|
|
|
|
depends on being able to turn a report into a permanent regression test.
|
|
|
|
|
|
|
|
|
|
## Verification this project already does
|
|
|
|
|
|
|
|
|
|
Every change to `src/upper.c`, `src/overlay.c`, or `src/vfs.c` is required
|
|
|
|
|
to pass under `-fsanitize=address,undefined` and `-fsanitize=thread`
|
|
|
|
|
before being considered done (`CLAUDE.md`) — this process has already
|
|
|
|
|
caught and fixed a real heap-use-after-free in the snapshot-reclamation
|
|
|
|
|
logic during development (see the `reclaim_gate` note in `src/internal.h`).
|
2026-09-14 11:03:20 +00:00
|
|
|
`.gitea/workflows/ci.yml` (Gitea Actions) runs the full test suite plus
|
|
|
|
|
both sanitizer passes on every push.
|