diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-25 22:29:13 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-27 12:50:53 +0100 |
commit | ea8a6b076ef2359426687467d7465e4c092f6447 (patch) | |
tree | a474c3dd789e62a97fee033c9d9899b6beef4069 /conf/filewriter_windows.go | |
parent | docs: fix /0 -> /1 in netquirk (diff) | |
download | wireguard-windows-ea8a6b076ef2359426687467d7465e4c092f6447.tar.xz wireguard-windows-ea8a6b076ef2359426687467d7465e4c092f6447.zip |
conf: do exponential back off for sharing violation in hotfolder
Windows gives us notifications about writes to files in a directory, but
it does not give us notifications on when file handles are closed and
when we can expect to be able to grab a handle to it; this would be
racey at best. So, there always exists a race between the writer's last
call to WriteFile() and its eventual CloseHandle(). Work around this by
implementing a basic exponential back off of retrying the open call.
While we're at it, clean up the "file already exists" logic to remove a
basic toctou situation, and switch to using random temp file names in
order to handle better the case of saving a new file from two different
administrators at once.
Reported-by: Jim Salter <jim@jrs-s.net>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'conf/filewriter_windows.go')
-rw-r--r-- | conf/filewriter_windows.go | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/conf/filewriter_windows.go b/conf/filewriter_windows.go index 6f7c40ad..ca45bf42 100644 --- a/conf/filewriter_windows.go +++ b/conf/filewriter_windows.go @@ -6,6 +6,8 @@ package conf import ( + "crypto/rand" + "encoding/hex" "sync/atomic" "unsafe" @@ -14,7 +16,16 @@ import ( var encryptedFileSd unsafe.Pointer -func writeEncryptedFile(destination string, contents []byte) error { +func randomFileName() string { + var randBytes [32]byte + _, err := rand.Read(randBytes[:]) + if err != nil { + panic(err) + } + return hex.EncodeToString(randBytes[:]) + ".tmp" +} + +func writeEncryptedFile(destination string, overwrite bool, contents []byte) error { var err error sa := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{}))} sa.SecurityDescriptor = (*windows.SECURITY_DESCRIPTOR)(atomic.LoadPointer(&encryptedFileSd)) @@ -29,7 +40,7 @@ func writeEncryptedFile(destination string, contents []byte) error { if err != nil { return err } - tmpDestination := destination + ".tmp" + tmpDestination := randomFileName() tmpDestination16, err := windows.UTF16PtrFromString(tmpDestination) if err != nil { return err @@ -57,7 +68,13 @@ func writeEncryptedFile(destination string, contents []byte) error { rootDirectory windows.Handle fileNameLength uint32 fileName [windows.MAX_PATH]uint16 - }{replaceIfExists: 1, fileNameLength: uint32(len(destination16) - 1)} + }{replaceIfExists: func() byte { + if overwrite { + return 1 + } else { + return 0 + } + }(), fileNameLength: uint32(len(destination16) - 1)} if len(destination16) > len(fileRenameInfo.fileName) { deleteIt() return windows.ERROR_BUFFER_OVERFLOW |