fix(safeio): retain writable Windows parent handles
This commit is contained in:
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func createPrivateDirectory(path string) error {
|
||||
parents, target, err := openCanonicalWindowsParent(path)
|
||||
parents, target, err := openCanonicalWindowsParentWithFinalAccess(path, windows.FILE_APPEND_DATA)
|
||||
if err != nil || parents == nil || len(parents.handles) == 0 {
|
||||
if parents != nil {
|
||||
parents.Close()
|
||||
@@ -112,7 +112,10 @@ func createCanonicalNewPrivateParentReadWriteFile(path string, mode os.FileMode)
|
||||
}
|
||||
|
||||
func createCanonicalNewFile(path string, mode os.FileMode, requirePrivateParent bool, access uint32) (*os.File, error) {
|
||||
parents, target, err := openCanonicalWindowsParent(path)
|
||||
// FILE_WRITE_DATA is FILE_ADD_FILE when the retained handle names a directory. Request it
|
||||
// while that final parent is opened, rather than reopening its lexical path later to gain
|
||||
// create permission.
|
||||
parents, target, err := openCanonicalWindowsParentWithFinalAccess(path, windows.FILE_WRITE_DATA)
|
||||
if err != nil || parents == nil || len(parents.handles) == 0 || (requirePrivateParent && validateOwnerOnlyDACL(parents.handles[len(parents.handles)-1]) != nil) {
|
||||
if parents != nil {
|
||||
parents.Close()
|
||||
@@ -172,6 +175,13 @@ func (parents *windowsParentHandles) Close() {
|
||||
// target parent without FILE_SHARE_DELETE. Every component after the volume root is resolved
|
||||
// through the prior retained handle's NT RootDirectory, never by re-opening an absolute prefix.
|
||||
func openCanonicalWindowsParent(path string) (*windowsParentHandles, string, error) {
|
||||
return openCanonicalWindowsParentWithFinalAccess(path, 0)
|
||||
}
|
||||
|
||||
// openCanonicalWindowsParentWithFinalAccess gives only the final retained parent the requested
|
||||
// child-operation capability. It is the Windows openat traversal for a later relative create;
|
||||
// reopening that parent by its reconstructed path would recreate the ancestor-swap race.
|
||||
func openCanonicalWindowsParentWithFinalAccess(path string, finalParentAccess uint32) (*windowsParentHandles, string, error) {
|
||||
if err := ValidateCanonicalPath(path); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -182,13 +192,21 @@ func openCanonicalWindowsParent(path string) (*windowsParentHandles, string, err
|
||||
return nil, "", ErrUnsafeFile
|
||||
}
|
||||
parents := &windowsParentHandles{directory: root}
|
||||
rootHandle, err := openWindowsComponent(root, true)
|
||||
rootAccess := uint32(windows.GENERIC_READ)
|
||||
if len(components) == 1 {
|
||||
rootAccess |= finalParentAccess
|
||||
}
|
||||
rootHandle, err := openWindowsComponentWithAccess(root, true, rootAccess)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
parents.handles = append(parents.handles, rootHandle)
|
||||
for _, component := range components[:len(components)-1] {
|
||||
handle, err := openWindowsRelativeComponent(parents.handles[len(parents.handles)-1], component, true, windows.GENERIC_READ)
|
||||
for index, component := range components[:len(components)-1] {
|
||||
componentAccess := uint32(windows.GENERIC_READ)
|
||||
if index == len(components)-2 {
|
||||
componentAccess |= finalParentAccess
|
||||
}
|
||||
handle, err := openWindowsRelativeComponent(parents.handles[len(parents.handles)-1], component, true, componentAccess)
|
||||
if err != nil {
|
||||
parents.Close()
|
||||
return nil, "", err
|
||||
|
||||
Reference in New Issue
Block a user