mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
- Fix TOCTOU race condition in Cache.maybeReload by re-stating the file
under the write lock. The previous implementation stat'd the file before
acquiring the lock, then used the stale FileInfo after the lock, which
could lead to storing an outdated mtime that doesn't match the loaded
content. This could cause subsequent Lookups to miss updates in
high-concurrency scenarios.
- Clarify Windows lock semantics: the mandatory LockFileEx lock is on the
separate .lock file (not the data file), so both Unix and Windows achieve
the same advisory-lock effect for the cache operations.
- Document mtimeOf zero-value semantics: the zero time.Time{} is a sentinel
for 'file not found' and is safe to compare with time.Time.Equal.
- Add comment explaining Store's update-after-persist ordering: the in-memory
map is updated after the disk write so that persistence failures still keep
the entry in memory for the current process.
- Document resolveCachePath's lexical-only path traversal check: symlinks are
not resolved, which is acceptable for the threat model (cache paths come
from agent configs, not untrusted user input).
All tests pass with -race. No functional changes to the cache behavior.
Assisted-By: docker-agent
45 lines
1.1 KiB
Go
45 lines
1.1 KiB
Go
//go:build windows
|
|
|
|
package cache
|
|
|
|
import (
|
|
"os"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// maxRange asks LockFileEx / UnlockFileEx to cover the whole file by
|
|
// passing 0xFFFFFFFF for both the low and high 32 bits of the range.
|
|
const maxRange = ^uint32(0)
|
|
|
|
// lockExclusive blocks until an exclusive lock is held on the file.
|
|
// Windows has no flock, so we use LockFileEx with LOCKFILE_EXCLUSIVE_LOCK.
|
|
//
|
|
// The lock is mandatory (kernel-enforced) on Windows, unlike the advisory
|
|
// flock used on Unix. However, since we lock a separate .lock file (not
|
|
// the data file itself), both platforms achieve the same effect: serializing
|
|
// the read-modify-write window without preventing direct reads of cache.json.
|
|
func lockExclusive(f *os.File) error {
|
|
var ol windows.Overlapped
|
|
return windows.LockFileEx(
|
|
windows.Handle(f.Fd()),
|
|
windows.LOCKFILE_EXCLUSIVE_LOCK,
|
|
0,
|
|
maxRange,
|
|
maxRange,
|
|
&ol,
|
|
)
|
|
}
|
|
|
|
// unlockFile releases the lock previously acquired with lockExclusive.
|
|
func unlockFile(f *os.File) error {
|
|
var ol windows.Overlapped
|
|
return windows.UnlockFileEx(
|
|
windows.Handle(f.Fd()),
|
|
0,
|
|
maxRange,
|
|
maxRange,
|
|
&ol,
|
|
)
|
|
}
|