Commit 1a55b59
authored
## Summary
**Post-open `IsRegular` re-check in `readRootFile`** — a security
hardening claude flagged during the PR #831 review that merged without
the fix.
`readRootFile` (the Redis blob `*.bin` reader) is reached via
`walkBlobDir` → `handleBlobEntry`, which pre-filters entries by the
**ReadDir** entry type (`ent.Type().IsRegular()`). That type is
**stale**: a FIFO/device swapped in for a `*.bin` between `ReadDir` and
`root.Open` passes the stale check and reaches `io.ReadAll` — blocking
on a writer-attached FIFO, or ingesting attacker-controlled bytes. This
adds the authoritative **post-open fstat** `IsRegular` check (the
read-side analogue of the post-open guard the JSON-collection walk paths
already use), ordered before `refuseHardLink` so a non-regular target is
classified as not-regular rather than hard-linked.
## Risk
Hardening only; tightens an untrusted-dump-input boundary in the offline
encode tool. No change to the happy path (regular `.bin` files read
identically).
## Self-review (5 lenses)
- **Data loss**: none — read-only offline tool; rejects bad input rather
than dropping good data.
- **Concurrency/distributed**: closes a TOCTOU window (stale ReadDir
type vs. authoritative post-open fstat) in a single-goroutine offline
encoder.
- **Performance**: one extra `Mode()` comparison on an already-`Stat`'d
fd; no new syscall.
- **Consistency**: matches the post-open `IsRegular` pattern already
used by the JSON-collection walk and the DDB schema reader.
- **Test coverage**: new co-located regression test calls `readRootFile`
on a directory (cross-platform non-regular stand-in) and asserts
`ErrRedisEncodeNotRegular`; confirmed failing without the guard
(returned the hard-link error) and passing with it.
## Test plan
- [x] `go test ./internal/backup/` (full package)
- [x] `golangci-lint run internal/backup/` (0 issues)
- [x] Regression test fails without the guard, passes with it (verified
by temporarily reverting the guard)
2 files changed
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
363 | 363 | | |
364 | 364 | | |
365 | 365 | | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
366 | 374 | | |
367 | 375 | | |
368 | 376 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
289 | 289 | | |
290 | 290 | | |
291 | 291 | | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
292 | 316 | | |
293 | 317 | | |
294 | 318 | | |
| |||
0 commit comments