Detect file modifications during checksum calculation (TOCTOU fix)
- Check file mtime before and after hashing; error if they differ - Store file's mtime as sumtime instead of wall-clock time - Use fresh stat for BytesProcessed to get accurate count This fixes a TOCTOU race where a file could be modified between hashing and writing the xattr, resulting in a stale checksum. It also makes sum update comparisons semantically correct by comparing file mtime against stored mtime rather than wall-clock time.
This commit is contained in:
parent
2e44e5bb78
commit
9f86bf1dc1
19
attrsum.go
19
attrsum.go
@ -238,10 +238,23 @@ func ProcessSumUpdate(dir string, stats *Stats, bar *progressbar.ProgressBar) er
|
||||
}
|
||||
|
||||
func writeChecksumAndTime(path string, info os.FileInfo, stats *Stats) error {
|
||||
// Record mtime before hashing to detect modifications during hash
|
||||
mtimeBefore := info.ModTime()
|
||||
|
||||
hash, err := fileMultihash(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if file was modified during hashing
|
||||
infoAfter, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stat after hash: %w", err)
|
||||
}
|
||||
if !infoAfter.ModTime().Equal(mtimeBefore) {
|
||||
return fmt.Errorf("%s: file modified during checksum calculation", path)
|
||||
}
|
||||
|
||||
if err := xattr.Set(path, checksumKey, hash); err != nil {
|
||||
return fmt.Errorf("set checksum attr: %w", err)
|
||||
}
|
||||
@ -249,7 +262,9 @@ func writeChecksumAndTime(path string, info os.FileInfo, stats *Stats) error {
|
||||
fmt.Printf("%s %s written\n", path, hash)
|
||||
}
|
||||
|
||||
ts := time.Now().UTC().Format(time.RFC3339Nano)
|
||||
// Store the file's mtime as sumtime (not wall-clock time)
|
||||
// This makes update comparisons semantically correct
|
||||
ts := mtimeBefore.UTC().Format(time.RFC3339Nano)
|
||||
if err := xattr.Set(path, sumTimeKey, []byte(ts)); err != nil {
|
||||
return fmt.Errorf("set sumtime attr: %w", err)
|
||||
}
|
||||
@ -258,7 +273,7 @@ func writeChecksumAndTime(path string, info os.FileInfo, stats *Stats) error {
|
||||
}
|
||||
|
||||
atomic.AddInt64(&stats.FilesProcessed, 1)
|
||||
atomic.AddInt64(&stats.BytesProcessed, info.Size())
|
||||
atomic.AddInt64(&stats.BytesProcessed, infoAfter.Size())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user