Releases: Strykar/pam_authnft
Release list
v1.0.0-rc1
First release candidate for 1.0.0, 77 commits since v0.2.0-alpha. The
interfaces the alpha series hedged on are now frozen: the PAM interface
(exactly two exported symbols), the nftables set schema, the fragment
format and ownership model, the claims_env wire format, the session
JSON schema (v=2), the journald audit fields and the element comment
grammar. See docs/ROADMAP.md.
Security hardening
A full adversarial audit (July 2026) found no attacker-reachable
memory-safety, injection or sandbox-escape defect. The caveats it
raised were fixed:
- Session identity files are root-only. An earlier build made them
group-readable to theauthnftgroup, which is exactly the
monitored-subject population, so one managed user could read
another's claims tag. - NSS resolution (
getgrnamand friends) runs in the setup child
before the seccomp filter applies.sssandldapbackends no
longer risk a SIGSYS kill during login. - The seccomp sandbox applies to a short-lived forked child only; the
calling PAM process is never filtered, and orphaned nftables state is
reaped if the child dies. - A login whose PID recycles onto a leaked session's names reclaims the
stale state instead of locking the user out. - The fragment validator is a brace, quote and comment-aware statement
scanner; semicolon-separated and whitespace-padded statements can no
longer bypass the verb and shared-chain guards. rhost_policy=kernelonly trusts an inbound ESTABLISHED socket whose
local port is a host TCP listener, so an outbound LDAP or Kerberos
socket is never mistaken for the client connection.- When the single-transaction teardown aborts because an object is
already gone, cleanup genuinely falls back to per-object deletes.
Compatibility
- Kernel floor: the
socket cgroupv2match must work on INPUT-hooked
chains, which is commit 05ae2fba821c (mainline v5.18; stable trees
carry it, so Ubuntu 22.04's 5.15 qualifies). Kernels between 5.13 and
5.17 without it fail silently: runmake test-packet-matchon the
target host to drive the real match. - musl libc: the sandbox allowlist covers musl's
open/readv/writev
paths and the unit suite runs against Alpine in CI.
Verification behind this release
Every pull request passes 13 required checks, including the unit suite
under ASan, UBSan and LSan, a container integration tier, a 90 percent
fuzz-coverage floor enforced by deterministic corpus replay, mutation
gates on the validator surfaces, a reproducible-build check and a
linked-library inventory gate. Nightly runs fuzz all eight harnesses
with a persistent corpus, and every commit on main is fuzzed
post-merge. CodeQL, Coverity, scan-build and Scorecard run on schedule.
Documentation
The README now leads with what a session looks like; concepts,
the admin guide (quick start and full configuration reference) and the
roadmap live under docs/,
alongside the integration contracts covering the six stable interfaces.
Plan
This candidate bakes for a week under the nightly fuzz, mutation and
integration runs. 1.0.0 final follows if nothing regresses. A CycloneDX
SBOM for the built module is attached to this release.
v0.2.0-alpha — security fixes + audit hardening
Upgrade urgency: recommended
Three memory-safety bugs found by libFuzzer harnesses are fixed in this release. The most severe is a heap-buffer-overflow in the NETLINK_SOCK_DIAG reply walker, which processes kernel-supplied bytes — the classic netlink-parser CVE pattern. A separate GitHub Security Advisory has been filed against this bug; downstream packagers and distros should treat v0.1.0-alpha as withdrawn.
Security fixes
- Heap-buffer-overflow in
peer_lookup.c:134(NLMSG_OKwalk).NLMSG_NEXTadvances byNLMSG_ALIGN(nlmsg_len)(4-byte aligned) butNLMSG_OKonly validatednlmsg_len <= remainingwithout alignment. A craftednlmsg_lenwhose 4-byte-aligned size exceedsremainingslipped pastNLMSG_OK, thenlen -= align(nlmsg_len)underflowedsize_t, and the next iteration dereferenced past the buffer. Severity: high (kernel-supplied bytes; reachable by anyCAP_NET_ADMINprocess posting crafted netlink replies). Fixed in #10. CWE-125 / CWE-191. - Two heap-buffer-overflows in
nft_handler.c:163andnft_handler.c:208(substitute_placeholders). Three write paths in the function, only the matched-placeholder path had a bounds check. Triggered by replacement strings whose total expansion approaches2*src_len. Severity: medium (admin-controlled fragment input; trust model means an attacker would already need root file-write to trigger, but ASan-detectable OOB regardless). Fixed in #8. - Off-by-one in
validate_cgroup_path. Found by inspection during refactor for the differential oracle. Severity: low (trusted input fromsd_pid_get_cgroup). Fixed in #10.
New stable contracts
- Linux audit-syscall channel (§6.2.7). Every fragment-rejection path now emits an
AUDIT_USER_ERR(1109) record via libaudit'saudit_log_user_message(), with reason tagsmissing | perms | content | nft-syntax. SOC consumers parsing/var/log/audit/audit.logget denied-session events without subscribing to the systemd journal. The journald channel (§6.2) stays in place; audit is additive. (#15) - Failed-open rollback (#9). A failed
open_sessionnow leaves no nft state, no transient scope, and no session-identity JSON — clean retry is always safe. Integration test 10.14 guards both rollback paths.
Hardening + test infrastructure
- 8 libFuzzer harnesses, 9 functions ≥ 90% coverage. Property assertions, not just crash-only. Found 4 real bugs (3 heap OOBs + 1 off-by-one). Sustained nightly fuzz cron (
fuzz-nightly.yml, 30 min × 8 harnesses, 03:17 UTC). (#7, #8, #10, #12) - Differential oracle harness (Phase 4.1). 5 small parsers cross-validated against an independent Python re-implementation; 286 inputs. (#11, #13)
- Property-based tests (Phase 4.2). Idempotence + round-trip on the same parsers. (#14)
- Mutation testing (Phase 4.3). mull (LLVM-IR mutator) wired in via
make mutation-reportand weeklymutation.ymlworkflow. (#18) - Reproducibility check.
make reproducibility-checkverifies bit-identical same-machine builds. (#17) - OSTIF best-practices alignment. SECURITY.md, security.txt, third-party inventory, response timelines, incident-response runbook, OpenSSF Best Practices badge. (#16, #17)
Documentation
- New:
docs/SECURITY_PRACTICES.md,docs/REPRODUCIBLE_BUILDS.md,docs/INCIDENT_RESPONSE.md,docs/THIRD_PARTY.md,docs/FUZZ_SURFACE.md. - The unit + integration test stage matrix and CI gate inventory now live in
docs/CONTRIBUTING.txt§ Tests rather than in the README.
Reproducible-build artefact hash
b2591c3afb061d7033297f6beffa1ebea9fc9911f64c0c11a60155b3f3aea46c pam_authnft.so
Verify locally with make reproducibility-check after make — the hash above was recorded on the maintainer's build host (Arch Linux, gcc + glibc; toolchain version dependence documented in docs/REPRODUCIBLE_BUILDS.md).
Upgrading
- No source-level migration required. The PAM interface (two exported symbols), nftables set schema, and fragment ownership model are unchanged.
- The only newly-allowlisted seccomp syscall classes are libaudit's
socket(AF_NETLINK)+sendto/sendmsg— already in the existing allowlist. - Recommended verification path after upgrade:
make test-container && make test-integration-container.
v0.1.0-alpha
Initial pre-release.
- PAM session module binding nftables rules to cgroupv2 session inodes
- Seccomp-BPF sandbox with SCMP_ACT_KILL default
- Transient systemd scopes under authnft.slice via D-Bus
- 24-hour timeout safety net on set elements
- Per-user root-owned nftables fragments
- Unit and integration test suites