Skip to content

Releases: Strykar/pam_authnft

v1.0.0-rc1

v1.0.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@Strykar Strykar released this 20 Jul 14:00
b4af49e

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 the authnft group, which is exactly the
    monitored-subject population, so one managed user could read
    another's claims tag.
  • NSS resolution (getgrnam and friends) runs in the setup child
    before the seccomp filter applies. sss and ldap backends 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=kernel only 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 cgroupv2 match 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: run make test-packet-match on 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

Choose a tag to compare

@Strykar Strykar released this 25 Apr 22:39
75f2c8b

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_OK walk). NLMSG_NEXT advances by NLMSG_ALIGN(nlmsg_len) (4-byte aligned) but NLMSG_OK only validated nlmsg_len <= remaining without alignment. A crafted nlmsg_len whose 4-byte-aligned size exceeds remaining slipped past NLMSG_OK, then len -= align(nlmsg_len) underflowed size_t, and the next iteration dereferenced past the buffer. Severity: high (kernel-supplied bytes; reachable by any CAP_NET_ADMIN process posting crafted netlink replies). Fixed in #10. CWE-125 / CWE-191.
  • Two heap-buffer-overflows in nft_handler.c:163 and nft_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 approaches 2*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 from sd_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's audit_log_user_message(), with reason tags missing | perms | content | nft-syntax. SOC consumers parsing /var/log/audit/audit.log get 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_session now 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-report and weekly mutation.yml workflow. (#18)
  • Reproducibility check. make reproducibility-check verifies 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

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

v0.1.0-alpha Pre-release
Pre-release

Choose a tag to compare

@Strykar Strykar released this 10 Apr 05:56

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