mirror of
https://github.com/garrytan/gstack.git
synced 2026-07-06 16:17:56 +02:00
harden(sync): close staging-guard TOCTOU + fail hard on marker write (#1802 C5)
checkOwnedStagingDir() now returns the realpath-resolved canonicalPath on a pass, and cleanupStagingDir() rmSync's that instead of the raw input — closing the gap where the input is a symlink swapped between the ownership check and the delete. makeStagingDir() tears down the partial dir and rethrows if the marker write fails, so a marker-less dir (which the guard would refuse forever) can never leak. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1211,7 +1211,15 @@ function makeStagingDir(): string {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
// Mint the ownership marker (#1802) so cleanupStagingDir() and decideResume()
|
||||
// can prove this dir was created by us before any recursive delete or resume.
|
||||
writeFileSync(join(dir, STAGING_MARKER), `${process.pid}\n${Date.now()}\n`, "utf-8");
|
||||
// #1802 C5: fail hard if the marker can't be written — a marker-less dir would
|
||||
// be refused by the guard forever (leaked, never cleaned). Tear down the
|
||||
// partial dir and rethrow so the caller fails loudly instead of leaking.
|
||||
try {
|
||||
writeFileSync(join(dir, STAGING_MARKER), `${process.pid}\n${Date.now()}\n`, "utf-8");
|
||||
} catch (err) {
|
||||
try { rmSync(dir, { recursive: true, force: true }); } catch { /* best-effort */ }
|
||||
throw err;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -1284,7 +1292,10 @@ function cleanupStagingDir(dir: string): void {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
// #1802 C5: delete the realpath-resolved dir the guard validated, not the
|
||||
// raw input — closes the TOCTOU gap where `dir` is a symlink swapped between
|
||||
// the check above and this rmSync. canonicalPath is always set when ok.
|
||||
rmSync(verdict.canonicalPath ?? dir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user