Remaining findings from the adversarial review of #30 that were not fixed in that PR, because they
sit in pre-existing src/ and session_linux.c code the PR did not touch. Each is tagged with how far
it was actually checked — several review claims turned out to be stale or wrong elsewhere in this
review, so please treat the tags as load-bearing.
1. monotonic_now reports success while never assigning the clock — VERIFIED (read)
native/session_linux.c:68
if (clock_gettime(CLOCK_MONOTONIC, &value) != 0 || value.tv_sec < 0) return -errno;
On the tv_sec < 0 branch clock_gettime SUCCEEDED, so errno is unset or stale and the function
returns -0 == 0 — success — with *now never assigned. remaining_milliseconds (:76) and the
zero-stability loop (:918, :924) then compare an indeterminate value against a deadline.
This is the same defect class as the seccomp fail-open fixed in #30 (trampoline_linux.c:70):
return -errno on a branch where errno was never set. I swept all 25 return -errno sites in
native/ for the pattern; these two are the only instances, and every other site follows a call that
genuinely sets errno. So the class is bounded, and this is the one that remains.
2. Receipt HMAC key not zeroed on four early returns — VERIFIED (read)
native/session_linux.c:906,908,910,913. In vinci_broker_session_finalize_terminal the key is read
into key at :886; attach_key/capture_key/policy_key/ingress_key are zeroed at :903-904,
but the four cgroup.freeze / cgroup.kill failure returns leave key un-zeroed, unlike every other exit
(:899, :941, :955, :956). A failing openat("cgroup.kill") — routine on a host without the kill
controller — leaves the 32-byte signing key in the stack frame.
3. The mutation-definition tests execute no product code — VERIFIED (read)
test/mutation-definitions.test.mjs asserts against test/harnesses.mjs, which contains five
export const frozen arrays and imports nothing from src/ or native/. Three of its four tests
therefore compare literals to literals and cannot fail for any change to the broker, while
package.json exposes them as npm run test:mutations and #30 wired them into CI as coverage. The
fourth test — the source_digests enumeration — IS load-bearing and mutation-tested. Either give the
matrices a real consumer or stop presenting them as a mutation suite.
4. linkat(AT_EMPTY_PATH) may make receipt persistence impossible unprivileged — REPORTED, probe pending
native/session_linux.c:281. persist_atomic publishes the O_TMPFILE receipt with
linkat(fd, "", dirfd, name, AT_EMPTY_PATH), which required CAP_DAC_READ_SEARCH before kernel 6.10.
An unprivileged broker would get EPERM, which is not EEXIST, so -EPERM propagates and every
receipt persist fails: commit_prelaunch drops to RECONCILE_ONLY (:618), begin_closing to stage 2
(:825), finalize_terminal to stage 3 (:947), and no session can ever reach SEALED. The portable
form is linkat(AT_FDCWD, "/proc/self/fd/<fd>", dirfd, name, AT_SYMLINK_FOLLOW). I have a probe
queued on a real unprivileged host and will post the result here.
5. Recovery tombstone is written before fsync — REPORTED, not independently verified
src/journal.mjs:186. recoverToUncontained writes UNCONTAINED.json with {flag:"wx"} and fsyncs
only afterwards (:194-200); a crash between the two leaves a torn file, and every later recovery
attempt hits JSON.parse at :186 and throws a raw SyntaxError instead of the intended
JournalError("...", "RECOVERY_TOMBSTONE_INVALID"). Same line also reads without O_NOFOLLOW,
inconsistent with the openSync(..., O_NOFOLLOW) two lines below.
6. recordDomainZero has no duplicate-call guard — REPORTED, not independently verified
src/capture.mjs:72, unlike closeIngress (:61, CAPTURE_CLOSE_DUPLICATE) and seal (:98,
CAPTURE_SEAL_DUPLICATE). A second call with a different proof passes every check and silently
overwrites this.zeroProof — the evidence the terminal receipt is built from — with no record that a
first proof existed.
Two other findings from the same review are filed separately as #34 (canonicalization collision) and
#35 (bare TypeError from a refusal path), both reproduced. One further claim — that the prctl
varargs UB was harmless at current call sites — was WRONG in the other direction: there was a short
call site, and it is fixed in #30.
Remaining findings from the adversarial review of #30 that were not fixed in that PR, because they
sit in pre-existing
src/andsession_linux.ccode the PR did not touch. Each is tagged with how farit was actually checked — several review claims turned out to be stale or wrong elsewhere in this
review, so please treat the tags as load-bearing.
1.
monotonic_nowreports success while never assigning the clock — VERIFIED (read)native/session_linux.c:68On the
tv_sec < 0branchclock_gettimeSUCCEEDED, soerrnois unset or stale and the functionreturns
-0 == 0— success — with*nownever assigned.remaining_milliseconds(:76) and thezero-stability loop (
:918,:924) then compare an indeterminate value against a deadline.This is the same defect class as the seccomp fail-open fixed in #30 (
trampoline_linux.c:70):return -errnoon a branch whereerrnowas never set. I swept all 25return -errnosites innative/for the pattern; these two are the only instances, and every other site follows a call thatgenuinely sets
errno. So the class is bounded, and this is the one that remains.2. Receipt HMAC key not zeroed on four early returns — VERIFIED (read)
native/session_linux.c:906,908,910,913. Invinci_broker_session_finalize_terminalthe key is readinto
keyat:886;attach_key/capture_key/policy_key/ingress_keyare zeroed at:903-904,but the four cgroup.freeze / cgroup.kill failure returns leave
keyun-zeroed, unlike every other exit(
:899,:941,:955,:956). A failingopenat("cgroup.kill")— routine on a host without the killcontroller — leaves the 32-byte signing key in the stack frame.
3. The mutation-definition tests execute no product code — VERIFIED (read)
test/mutation-definitions.test.mjsasserts againsttest/harnesses.mjs, which contains fiveexport constfrozen arrays and imports nothing fromsrc/ornative/. Three of its four teststherefore compare literals to literals and cannot fail for any change to the broker, while
package.jsonexposes them asnpm run test:mutationsand #30 wired them into CI as coverage. Thefourth test — the
source_digestsenumeration — IS load-bearing and mutation-tested. Either give thematrices a real consumer or stop presenting them as a mutation suite.
4.
linkat(AT_EMPTY_PATH)may make receipt persistence impossible unprivileged — REPORTED, probe pendingnative/session_linux.c:281.persist_atomicpublishes theO_TMPFILEreceipt withlinkat(fd, "", dirfd, name, AT_EMPTY_PATH), which requiredCAP_DAC_READ_SEARCHbefore kernel 6.10.An unprivileged broker would get
EPERM, which is notEEXIST, so-EPERMpropagates and everyreceipt persist fails:
commit_prelaunchdrops toRECONCILE_ONLY(:618),begin_closingto stage 2(
:825),finalize_terminalto stage 3 (:947), and no session can ever reachSEALED. The portableform is
linkat(AT_FDCWD, "/proc/self/fd/<fd>", dirfd, name, AT_SYMLINK_FOLLOW). I have a probequeued on a real unprivileged host and will post the result here.
5. Recovery tombstone is written before fsync — REPORTED, not independently verified
src/journal.mjs:186.recoverToUncontainedwritesUNCONTAINED.jsonwith{flag:"wx"}and fsyncsonly afterwards (
:194-200); a crash between the two leaves a torn file, and every later recoveryattempt hits
JSON.parseat:186and throws a rawSyntaxErrorinstead of the intendedJournalError("...", "RECOVERY_TOMBSTONE_INVALID"). Same line also reads withoutO_NOFOLLOW,inconsistent with the
openSync(..., O_NOFOLLOW)two lines below.6.
recordDomainZerohas no duplicate-call guard — REPORTED, not independently verifiedsrc/capture.mjs:72, unlikecloseIngress(:61,CAPTURE_CLOSE_DUPLICATE) andseal(:98,CAPTURE_SEAL_DUPLICATE). A second call with a different proof passes every check and silentlyoverwrites
this.zeroProof— the evidence the terminal receipt is built from — with no record that afirst proof existed.
Two other findings from the same review are filed separately as #34 (canonicalization collision) and
#35 (bare
TypeErrorfrom a refusal path), both reproduced. One further claim — that theprctlvarargs UB was harmless at current call sites — was WRONG in the other direction: there was a short
call site, and it is fixed in #30.