Skip to content

Commit 5071535

Browse files
committed
Fix race in dowloader.Cached()
Checking if an image is cached races with parallel downloads. Take the lock when validating the digest or the data file to ensure that we validate the cached when it is in consistent state. If an image is being downloaded, the check will block until the download completes. Signed-off-by: Nir Soffer <[email protected]>
1 parent c1b4d72 commit 5071535

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

pkg/downloader/downloader.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -361,18 +361,33 @@ func Cached(remote string, opts ...Opt) (*Result, error) {
361361
if err != nil {
362362
return nil, err
363363
}
364+
365+
// Checking if data file exists is safe without locking.
364366
if _, err := os.Stat(shadData); err != nil {
365367
return nil, err
366368
}
367-
if _, err := os.Stat(shadDigest); err != nil {
368-
if err := validateCachedDigest(shadDigest, o.expectedDigest); err != nil {
369-
return nil, err
370-
}
371-
} else {
372-
if err := validateLocalFileDigest(shadData, o.expectedDigest); err != nil {
373-
return nil, err
369+
370+
// But validating the digest or the data file must take the lock to avoid races
371+
// with parallel downloads.
372+
if err := os.MkdirAll(shad, 0o700); err != nil {
373+
return nil, err
374+
}
375+
err = lockutil.WithDirLock(shad, func() error {
376+
if _, err := os.Stat(shadDigest); err != nil {
377+
if err := validateCachedDigest(shadDigest, o.expectedDigest); err != nil {
378+
return err
379+
}
380+
} else {
381+
if err := validateLocalFileDigest(shadData, o.expectedDigest); err != nil {
382+
return err
383+
}
374384
}
385+
return nil
386+
})
387+
if err != nil {
388+
return nil, err
375389
}
390+
376391
res := &Result{
377392
Status: StatusUsedCache,
378393
CachePath: shadData,

0 commit comments

Comments
 (0)