audit: state that the log is volatile, and trim CLAUDE.md - #124
Merged
Conversation
The Check Point BTR Reforged write-up (root-level attacker blinds the EDR) raised the obvious follow-up: would our audit log show it afterwards? It would not -- `reboot` erases it -- which makes persistence look like the fix. It is not, and the reasons are specific enough to be worth writing down before someone (me) proposes it again. Two blockers, both verified rather than assumed: 1. audit_init() (audit.c:81) regenerates the HMAC key from the CSPRNG on every boot and stores it nowhere. Records persisted across a reboot therefore cannot be authenticated afterwards. Persistence would ship a tamper-evident log whose tamper-evidence is void exactly across the boundary persistence exists to cross -- and `[OK] integrity verified` would print either way, which is the status-surface lie class. 2. The only persistence precedent here has never persisted anything. entropy.c:442 targets "/boot/entropy.seed" via ramfs_open; nothing creates /boot and ramfs is RAM. Confirmed from three live boot logs that every boot prints "Cannot create seed file" / "Entropy will reset on next reboot". Copying that model reproduces the bug more quietly. Neither is fixable by a small change (1 needs a key root cannot read, i.e. sealed storage, which is a hardware question), so the honest interim fix is to stop the volatility being a surprise: - `auditlog -s` printed "Total events logged", which reads as an all-time figure the counter structurally cannot report. Now "Events logged (this boot)", with the remaining labels re-aligned to the wider column, plus an explicit "Log is VOLATILE: held in RAM, cleared on reboot." - `auditlog --help` says the log is not written to disk. Verified live under QEMU, both surfaces (stats block and --help), rather than by reading the diff. Build clean under -Werror. doc/AUDIT_LOG_PERSISTENCE.md records the decision and what would have to be true to revisit it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CEkhAhgTxbE5TgifyYf8v4
426 -> 378 lines. The split rule is "constraints stay inline, history moves out", so this cuts supporting narrative that doc/ already carries and leaves the rules themselves alone. Mechanically verified that nothing was lost -- no rule heading, doc/ pointer, harness name or build flag present before is absent after (comm against HEAD:CLAUDE.md on all four). Rule count went 21 -> 23 because `su` and `edit` became their own bullets. Also: - Added table rows for NETWORK_ISOLATION.md and NETDAEMON_DESIGN.md, which the rules already cited without the index listing them, plus the new AUDIT_LOG_PERSISTENCE.md. - The EDR-tear entry no longer inlines grep/sed incantations. Those are superseded by the shared splice in verify/edr-rejoin.sh, and reproducing them here invites a sixth hand-copy -- all five earlier ones had defects that FAILed a correct kernel. - Noted verify/run-all.sh, which CLAUDE.md never mentioned. - Confirmed every harness filename it names actually exists (one was wrong: verify-edr-rejoin-test.sh -> verify/edr-rejoin-test.sh). Still above the ~150 target. Getting there means deleting rules rather than prose, and each is the residue of a real bug, so I stopped here rather than buy the line count with content. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CEkhAhgTxbE5TgifyYf8v4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Finishes the two items left open from the EDR/kprintf work: the audit-log persistence question, and the CLAUDE.md trim.
1. Audit log: decided to stay volatile, and now says so
The Check Point BTR Reforged write-up (root-level attacker blinds the EDR) raised the follow-up: would our audit log show it afterwards? It would not —
rebooterases it — which makes persistence look like the fix. It isn't, for two reasons I verified rather than assumed:The HMAC key is regenerated every boot.
audit_init()(src/audit.c:81) draws it from the CSPRNG and stores it nowhere, so records persisted across a reboot cannot be authenticated afterwards. Persistence would ship a tamper-evident log whose tamper-evidence is void exactly across the boundary persistence exists to cross — and[OK] integrity verifiedwould print either way, which is the status-surface lie class. Fixing it needs a key root cannot read, i.e. sealed storage. No TPM here.The one persistence precedent has never persisted anything.
entropy.c:442targets/boot/entropy.seedviaramfs_open; nothing creates/boot, and ramfs is RAM. Confirmed from three live boot logs that every boot printsCannot create seed file/Entropy will reset on next reboot. Copying that model reproduces the bug more quietly.Neither is a small change, so the interim fix is to stop the volatility being a surprise:
auditlog -sprintedTotal events logged, which reads as an all-time figure this counter structurally cannot report →Events logged (this boot), remaining labels re-aligned, plus an explicitLog is VOLATILE: held in RAM, cleared on reboot.auditlog --helpnow states the log is not written to disk.doc/AUDIT_LOG_PERSISTENCE.mdrecords the decision and the three things that would have to be true to revisit it.Verification
Both surfaces driven live under QEMU rather than read off the diff:
and the
--helpnote renders. Full rebuildrc=0, zero diagnostics under-Werror.2. CLAUDE.md: 426 → 378
The split rule is "constraints stay inline, history moves out", so this cuts narrative that
doc/already carries and leaves the rules alone. Mechanically verified nothing was lost — no rule heading,doc/pointer, harness name or build flag present before is absent after (commagainst the base on all four axes). Rule count went 21 → 23 becausesuandeditbecame their own bullets.Also: added index rows for
NETWORK_ISOLATION.mdandNETDAEMON_DESIGN.md(cited by the rules but never listed); dropped the inline EDR grep/sed incantations, which are superseded byverify/edr-rejoin.shand whose reproduction here invites a sixth hand-copy (all five earlier ones had defects that FAILed a correct kernel); notedverify/run-all.sh; and checked every harness filename it names exists — one was wrong.Still above the ~150 target. Getting there means deleting rules rather than prose, and each is the residue of a real bug, so I stopped rather than buy the line count with content.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CEkhAhgTxbE5TgifyYf8v4