CI / build-and-test (push) Failing after 23s
Per explicit direction: this repository is not going on GitHub. Moved .github/workflows/ci.yml to .gitea/workflows/ci.yml (Gitea Actions' convention) and updated every doc that referenced the old path or assumed GitHub-specific features: - .gitea/workflows/ci.yml: added a header comment on the two things that are genuinely Gitea-specific and instance-dependent, not just a renamed file -- `runs-on: ubuntu-latest` must match a label the actual registered Gitea runner advertises (there is no GitHub-hosted-runner equivalent, this is self-hosted), and `actions/checkout@v4` resolves against whatever action source that runner is configured with. - CONTRIBUTING.md: corrected a claim that no longer holds -- it previously said CI "runs on a normal, unrestricted GitHub Actions VM where TSan is expected to work"; since this is actually a self-hosted Gitea runner whose environment isn't controlled by this repo, that assumption isn't something this repo can vouch for, so the text now says so rather than carrying the old (GitHub-shaped) assumption forward silently. - SECURITY.md: removed a claim this project can't back up (that "private security advisories" are available once hosted -- that's a GitHub feature this repo never had access to); reporting is by direct email to the maintainer only. - README.md: fixed a real gap while in here -- the "Security" section never actually linked to SECURITY.md despite it existing since the previous commit. - CLAUDE.md, CHANGELOG.md: updated path references; CLAUDE.md's self-evaluation section (a historical record of an audit finding) keeps the old .github path where it describes what was literally true at that time, with a note explaining the rename, rather than rewriting history. Verified: clean make all + make test, all 6 binaries pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqJpkdJ6Njnt1pw3CbghzB
87 lines
4.3 KiB
Markdown
87 lines
4.3 KiB
Markdown
# 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
|
|
|
|
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:
|
|
|
|
**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`).
|
|
`.gitea/workflows/ci.yml` (Gitea Actions) runs the full test suite plus
|
|
both sanitizer passes on every push.
|