Development record
probe.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
probe.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
Evidence
internal/core/lifeboat/probe.go:406--dirRoot.OpenRoot(name)guarded only by the parent ReadDir's IsDir;os.Root.OpenRootopens with O_NOFOLLOW|O_CLOEXEC, no O_DIRECTORY/O_NONBLOCK, so a directory swapped for a FIFO in that window blocks.
Verifier verdict -- CONFIRMED, recorded not fixed
Real TOCTOU, same shape as iss-341, but race-only (needs an active writer in the probed tree) and unfixable with the nonBlock const because os.Root.OpenRoot takes no flags -- a fix means a raw openat(O_DIRECTORY|O_NOFOLLOW|O_NONBLOCK) or an OpenInRoot-style restructure. Filed separately from the iss-342/iss-341 same-sweep fixes by the verifier's own recommendation; larger than this round should bundle.
Grounds
- pursued: a walk over a tree whose listed directory becomes a FIFO returns promptly instead of hanging disembark; shown wrong if a toolchain stops opening os.Root intermediate components with O_DIRECTORY, which the descent test would then catch by timing out
Frontmatter
| id | iss-337 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-337-probe-go-s-inner-directory-descent.md
open on GitHub ↗ · commit history ↗
mentions3
- 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-341readLifeboatFile 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
- iss-342SourceContext.ListDir opens directory entries with root.Open (no O_NONBLOCK), so a statically-planted FIFO named at a path a probe adapter lists (e.g. docs) hangs abcd disembark probe/plan/pack forever over an untrusted target repo — no race required, breaking the package's stated no-hang-on-FIFO invariant