Development record
readLifeboatFile keeps an Lstat then root.Open window over an untrusted lifeboat (embark), bypassing fsutil.ReadGuardedInRoot — a vetted regular file swapped for a FIFO blocks the open forever, or an in-root symlink is read/hashed in place of the vetted file
readLifeboatFile keeps an Lstat then root.Open window over an untrusted lifeboat (embark), bypassing fsutil.ReadGuardedInRoot — a vetted regular file swapped for a FIFO blocks the open forever, or an in-root symlink is read/hashed in place of the vetted file
Evidence
internal/core/lifeboat/embark.go:563-589--root.Lstat(rel)then a separateroot.Open(rel), noO_NONBLOCK, noos.SameFilefd re-check. Callers:VerifyManifest(embark.go:146), the planner (embark.go:246),synthesis_review.go:105.internal/fsutil/fsutil.go:92-133ReadGuardedInRoot-- canonical primitive naming both dropped guarantees;probe.go:226-247SourceContext.ReadFileis the hardened sibling.
Refuter verdict -- CONFIRMED (substantive)
On the pinned go1.25.6, root.Open follows in-root symlinks and blocks on a FIFO. The lifeboat dir is documented untrusted (embark.go:4-8). Incremental hazard is the FIFO hang; a content swap inside VerifyManifest fails closed on hash mismatch. Same shape as the burst-2 readGraveyardFile fix, invisible to a Lstat->ReadFile grep. Fix: route through fsutil.ReadGuardedInRoot, drop the unused abs param, keep the Lstat symlink check for its distinct message.
Frontmatter
| id | iss-341 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-341-readlifeboatfile-keeps-an-lstat-then.md
open on GitHub ↗ · commit history ↗
mentions2
- dcn-26082000000000012026-08-20 — bughunt round 2 (branch bughunt-a/round-2): captured iss-331..iss-343 and fixed (ids 339-343 re-minted from an initial 326-330 after main concurrently took those numbers in the v0.6.1 cut)
- iss-337probe.go's inner directory descent (dirRoot.OpenRoot(name)) is guarded only by the parent ReadDir's IsDir, so a directory swapped for a FIFO in that window blocks — same TOCTOU shape as readLifeboatFile but race-only and unfixable via the nonBlock const (os.Root.OpenRoot takes no flags); needs a raw openat restructure, recorded not fixed