//go:build windows package safeio import ( "errors" "io" "os" "runtime" "sort" "time" "unsafe" "golang.org/x/sys/windows" ) // windowsPrivateDirectory keeps the root's canonical component handles alive, then uses NT // RootDirectory-relative opens for every descendant. Unlike a lexical child path, an NT relative // object name is resolved by the already-open directory handle and cannot be redirected by a // rename, replacement, or reparse point at the original root path. type windowsPrivateDirectory struct { anchors *windowsParentHandles parent windows.Handle handle windows.Handle info windows.ByHandleFileInformation } type windowsPrivateRegularAt struct { handle windows.Handle info windows.ByHandleFileInformation } func openPrivateDirectory(path string, ensure bool) (PrivateDirectoryHandle, bool, error) { anchors, target, err := openCanonicalWindowsParent(path) if err != nil || anchors == nil || len(anchors.handles) == 0 { if anchors != nil { anchors.Close() } return nil, false, ErrUnsafeFile } parent := anchors.handles[len(anchors.handles)-1] handle, found, err := openWindowsPrivateDirectoryAt(parent, target, false) if err != nil { anchors.Close() return nil, false, ErrUnsafeFile } if !found { // The final root is absent. The retained canonical parent must prove that the same // ensure operation could create it; validation itself must remain side-effect free. // FILE_APPEND_DATA is the Win32 spelling of directory FILE_ADD_SUBDIRECTORY. anchors.Close() writableAnchors, writableTarget, probeErr := openCanonicalWindowsParentWithFinalAccess(path, windows.FILE_APPEND_DATA) if probeErr != nil || writableAnchors == nil || len(writableAnchors.handles) == 0 { if writableAnchors != nil { writableAnchors.Close() } return nil, false, ErrUnsafeFile } if !ensure { writableAnchors.Close() return nil, false, nil } anchors = writableAnchors target = writableTarget parent = anchors.handles[len(anchors.handles)-1] handle, found, err = openWindowsPrivateDirectoryAt(parent, target, true) if err != nil || !found { anchors.Close() return nil, false, ErrUnsafeFile } } value := &windowsPrivateDirectory{anchors: anchors, handle: handle} if value.captureAndValidate() != nil { _ = value.Close() return nil, false, ErrUnsafeFile } return value, true, nil } func openWindowsPrivateDirectoryAt(parent windows.Handle, name string, ensure bool) (windows.Handle, bool, error) { if parent == 0 || !validPrivateLeafName(name) { return 0, false, ErrUnsafeFile } for attempt := 0; attempt < 2; attempt++ { handle, err := openWindowsRelativePrivateDirectoryWithRetry(parent, name) if err == nil { return handle, true, nil } if !isWindowsRelativeNotFound(err) { return 0, false, ErrUnsafeFile } if !ensure { return 0, false, nil } handle, err = createWindowsRelativePrivateDirectory(parent, name) if err == nil { return handle, true, nil } } return 0, false, ErrUnsafeFile } func openWindowsRelativePrivateDirectoryWithRetry(parent windows.Handle, name string) (windows.Handle, error) { for attempt := 0; ; attempt++ { handle, err := openWindowsRelativeDirectory(parent, name) if !isWindowsRelativeSharingViolation(err) { return handle, err } if attempt == windowsPrivateSharingRetries { return 0, err } time.Sleep(time.Millisecond) } } func openWindowsRelativeDirectory(parent windows.Handle, name string) (windows.Handle, error) { handle, err := openWindowsRelativeObject( parent, name, // The retained directory handle is also the RootDirectory for create, rename, // hard-link, and delete operations below, so it needs the owner's full private // directory capability rather than a read-only probe handle. windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, windows.FILE_OPEN, windows.FILE_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, nil, ) if err != nil { return 0, err } if _, err := privateWindowsDirectoryInfo(handle); err != nil { _ = windows.CloseHandle(handle) return 0, ErrUnsafeFile } return handle, nil } func createWindowsRelativePrivateDirectory(parent windows.Handle, name string) (windows.Handle, error) { security, err := newOwnerOnlySecurityDescriptor() if err != nil { return 0, ErrUnsafeFile } defer security.Close() handle, err := openWindowsRelativeObject( parent, name, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, windows.FILE_CREATE, windows.FILE_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, security, ) if err != nil { return 0, err } if _, err := privateWindowsDirectoryInfo(handle); err != nil { _ = markWindowsHandleForDelete(handle) _ = windows.CloseHandle(handle) return 0, ErrUnsafeFile } return handle, nil } func openWindowsRelativeObject( parent windows.Handle, name string, access uint32, disposition uint32, options uint32, security *ownerOnlySecurityDescriptor, ) (windows.Handle, error) { return openWindowsRelativeObjectWithShareMode( parent, name, access, disposition, options, security, windowsRetainedHandleShareMode, ) } func openWindowsRelativeObjectWithShareMode( parent windows.Handle, name string, access uint32, disposition uint32, options uint32, security *ownerOnlySecurityDescriptor, shareMode uint32, ) (windows.Handle, error) { if parent == 0 || !validPrivateLeafName(name) { return 0, ErrUnsafeFile } access = normalizeWindowsNTDesiredAccess(access) objectName, err := windows.NewNTUnicodeString(name) if err != nil { return 0, ErrUnsafeFile } attributes := &windows.OBJECT_ATTRIBUTES{ Length: uint32(unsafe.Sizeof(windows.OBJECT_ATTRIBUTES{})), RootDirectory: parent, ObjectName: objectName, Attributes: windows.OBJ_CASE_INSENSITIVE, SecurityDescriptor: nil, } if security != nil { attributes.SecurityDescriptor = security.descriptor } var ( handle windows.Handle status windows.IO_STATUS_BLOCK allocationSize int64 ) err = windows.NtCreateFile( &handle, access, attributes, &status, &allocationSize, // NtCreateFile supplies the normal attribute default when this is zero; no // explicit creation attribute is needed for these retained open/create calls. 0, shareMode, disposition, options, 0, 0, ) runtime.KeepAlive(objectName) runtime.KeepAlive(security) if err != nil { return 0, err } return handle, nil } func normalizeWindowsNTDesiredAccess(access uint32) uint32 { if access&uint32(windows.GENERIC_ALL) != 0 { const fileSpecificAll = uint32(0x1ff) access = access&^uint32(windows.GENERIC_ALL) | uint32(windows.STANDARD_RIGHTS_REQUIRED|windows.SYNCHRONIZE) | fileSpecificAll } if access&uint32(windows.GENERIC_READ) != 0 { access = access&^uint32(windows.GENERIC_READ) | uint32(windows.FILE_GENERIC_READ) } if access&uint32(windows.GENERIC_WRITE) != 0 { access = access&^uint32(windows.GENERIC_WRITE) | uint32(windows.FILE_GENERIC_WRITE) } if access&uint32(windows.GENERIC_EXECUTE) != 0 { access = access&^uint32(windows.GENERIC_EXECUTE) | uint32(windows.FILE_GENERIC_EXECUTE) } return access } func privateWindowsDirectoryInfo(handle windows.Handle) (windows.ByHandleFileInformation, error) { var info windows.ByHandleFileInformation if handle == 0 || windows.GetFileInformationByHandle(handle, &info) != nil || info.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 || info.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 || validateOwnerOnlyDACL(handle) != nil { return windows.ByHandleFileInformation{}, ErrUnsafeFile } return info, nil } func privateWindowsRegularInfo(handle windows.Handle, allowedLinks ...uint32) (windows.ByHandleFileInformation, error) { var info windows.ByHandleFileInformation if handle == 0 || windows.GetFileInformationByHandle(handle, &info) != nil || info.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 || info.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY != 0 || validateOwnerOnlyDACL(handle) != nil { return windows.ByHandleFileInformation{}, ErrUnsafeFile } for _, links := range allowedLinks { if info.NumberOfLinks == links { return info, nil } } return windows.ByHandleFileInformation{}, ErrUnsafeFile } func isWindowsRelativeNotFound(err error) bool { return errors.Is(err, windows.ERROR_FILE_NOT_FOUND) || errors.Is(err, windows.ERROR_PATH_NOT_FOUND) || errors.Is(err, windows.STATUS_NO_SUCH_FILE) || errors.Is(err, windows.STATUS_OBJECT_NAME_NOT_FOUND) || errors.Is(err, windows.STATUS_OBJECT_PATH_NOT_FOUND) } func isWindowsRelativeCollision(err error) bool { return errors.Is(err, windows.ERROR_FILE_EXISTS) || errors.Is(err, windows.ERROR_ALREADY_EXISTS) || errors.Is(err, windows.STATUS_OBJECT_NAME_COLLISION) } func isWindowsRelativeSharingViolation(err error) bool { return errors.Is(err, windows.ERROR_SHARING_VIOLATION) || errors.Is(err, windows.STATUS_SHARING_VIOLATION) } func (directory *windowsPrivateDirectory) captureAndValidate() error { if directory == nil || directory.handle == 0 { return ErrUnsafeFile } info, err := privateWindowsDirectoryInfo(directory.handle) if err != nil { return ErrUnsafeFile } directory.info = info return nil } func (directory *windowsPrivateDirectory) Close() error { if directory == nil { return nil } var result error if directory.handle != 0 { if err := windows.CloseHandle(directory.handle); err != nil { result = ErrUnsafeFile } directory.handle = 0 } if directory.parent != 0 { if err := windows.CloseHandle(directory.parent); err != nil { result = ErrUnsafeFile } directory.parent = 0 } if directory.anchors != nil { directory.anchors.Close() directory.anchors = nil } return result } func sameWindowsPrivateDirectoryIdentity(left, right windows.ByHandleFileInformation) bool { return left.VolumeSerialNumber == right.VolumeSerialNumber && left.FileIndexHigh == right.FileIndexHigh && left.FileIndexLow == right.FileIndexLow && left.FileAttributes == right.FileAttributes } func sameWindowsPrivateDirectorySnapshot(left, right windows.ByHandleFileInformation) bool { return sameWindowsPrivateDirectoryIdentity(left, right) && left.LastWriteTime == right.LastWriteTime } func (directory *windowsPrivateDirectory) Validate() error { if directory == nil || directory.handle == 0 || (directory.anchors == nil && directory.parent == 0) { return ErrUnsafeFile } if directory.anchors != nil && len(directory.anchors.handles) == 0 { return ErrUnsafeFile } if directory.parent != 0 { if _, err := privateWindowsDirectoryInfo(directory.parent); err != nil { return ErrUnsafeFile } } current, err := privateWindowsDirectoryInfo(directory.handle) if err != nil || !sameWindowsPrivateDirectoryIdentity(directory.info, current) { return ErrUnsafeFile } return nil } func duplicateWindowsRetainedHandle(handle windows.Handle) (windows.Handle, error) { if handle == 0 { return 0, ErrUnsafeFile } var duplicate windows.Handle process := windows.CurrentProcess() if err := windows.DuplicateHandle(process, handle, process, &duplicate, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { return 0, ErrUnsafeFile } return duplicate, nil } func (directory *windowsPrivateDirectory) OpenChild(name string, ensure bool) (PrivateDirectoryHandle, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) { return nil, false, ErrUnsafeFile } parent, err := duplicateWindowsRetainedHandle(directory.handle) if err != nil { return nil, false, ErrUnsafeFile } handle, found, err := openWindowsPrivateDirectoryAt(parent, name, ensure) if err != nil || !found { _ = windows.CloseHandle(parent) if err != nil { return nil, false, ErrUnsafeFile } return nil, false, nil } child := &windowsPrivateDirectory{parent: parent, handle: handle} if child.captureAndValidate() != nil || directory.Validate() != nil { _ = child.Close() return nil, false, ErrUnsafeFile } return child, true, nil } func openWindowsPrivateRegularAt( parent windows.Handle, name string, access uint32, allowedLinks ...uint32, ) (*windowsPrivateRegularAt, error) { return openWindowsPrivateRegularAtWithShareMode( parent, name, access, windowsRetainedHandleShareMode, allowedLinks..., ) } func openWindowsPrivateRegularAtWithShareMode( parent windows.Handle, name string, access uint32, shareMode uint32, allowedLinks ...uint32, ) (*windowsPrivateRegularAt, error) { handle, err := openWindowsRelativeObjectWithShareMode( parent, name, access, windows.FILE_OPEN, windows.FILE_NON_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, nil, shareMode, ) if err != nil { return nil, err } info, err := privateWindowsRegularInfo(handle, allowedLinks...) if err != nil { _ = windows.CloseHandle(handle) return nil, ErrUnsafeFile } return &windowsPrivateRegularAt{handle: handle, info: info}, nil } func openWindowsPrivateRegularAtAllowedLinks( parent windows.Handle, name string, access uint32, allowedLinks ...uint32, ) (*windowsPrivateRegularAt, error) { var ( lastError error unsafeFound bool ) for _, links := range allowedLinks { value, err := openWindowsPrivateRegularAt(parent, name, access, links) if err == nil { return value, nil } lastError = err if !isWindowsRelativeNotFound(err) { unsafeFound = true } } if unsafeFound { return nil, ErrUnsafeFile } return nil, lastError } func createWindowsPrivateRegularAt(parent windows.Handle, name string) (*windowsPrivateRegularAt, error) { return createWindowsPrivateRegularAtWithAccess(parent, name, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE) } // createWindowsPrivateRegularAtWithAccess creates the final leaf beneath an already-retained // parent with an owner-only DACL in the same NtCreateFile operation. The caller never re-resolves // an absolute pathname after the parent is pinned. func createWindowsPrivateRegularAtWithAccess(parent windows.Handle, name string, access uint32) (*windowsPrivateRegularAt, error) { security, err := newOwnerOnlySecurityDescriptor() if err != nil { return nil, ErrUnsafeFile } defer security.Close() // The caller's data authority is intentionally preserved (GENERIC_WRITE is used for // streaming creates), but privateWindowsRegularInfo must inspect attributes and links // before returning the handle. FILE_READ_ATTRIBUTES grants that inspection without // adding read-data authority to a write-only create. access |= windows.FILE_READ_ATTRIBUTES handle, err := openWindowsRelativeObject( parent, name, access|windows.DELETE, windows.FILE_CREATE, windows.FILE_NON_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, security, ) if err != nil { return nil, err } info, err := privateWindowsRegularInfo(handle, 1) if err != nil { _ = markWindowsHandleForDelete(handle) _ = windows.CloseHandle(handle) return nil, ErrUnsafeFile } return &windowsPrivateRegularAt{handle: handle, info: info}, nil } func (value *windowsPrivateRegularAt) Close() error { if value == nil || value.handle == 0 { return nil } handle := value.handle value.handle = 0 if err := windows.CloseHandle(handle); err != nil { return ErrUnsafeFile } return nil } func writeWindowsPrivateRegular(value *windowsPrivateRegularAt, contents []byte) error { if value == nil || value.handle == 0 || len(contents) == 0 { return ErrUnsafeFile } for remaining := contents; len(remaining) > 0; { var written uint32 if err := windows.WriteFile(value.handle, remaining, &written, nil); err != nil || written == 0 || int(written) > len(remaining) { return ErrUnsafeFile } remaining = remaining[written:] } if err := windows.FlushFileBuffers(value.handle); err != nil { return ErrUnsafeFile } info, err := privateWindowsRegularInfo(value.handle, 1) if err != nil { return ErrUnsafeFile } value.info = info return nil } func readWindowsPrivateRegular(value *windowsPrivateRegularAt, maximum int64, links uint32) ([]byte, error) { if value == nil || value.handle == 0 || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, ErrUnsafeFile } contents := make([]byte, 0, 4096) buffer := make([]byte, 4096) for { var read uint32 err := windows.ReadFile(value.handle, buffer, &read, nil) if read > 0 { if int64(len(contents))+int64(read) > maximum { return nil, ErrUnsafeFile } contents = append(contents, buffer[:read]...) } if err != nil { if errors.Is(err, windows.ERROR_HANDLE_EOF) { break } return nil, ErrUnsafeFile } if read == 0 { break } } after, err := privateWindowsRegularInfo(value.handle, links) if err != nil || !sameWindowsPrivateFile(value.info, after) { return nil, ErrUnsafeFile } value.info = after return contents, nil } func markWindowsHandleForDelete(handle windows.Handle) error { if handle == 0 { return ErrUnsafeFile } buffer := [1]byte{1} var status windows.IO_STATUS_BLOCK if err := windows.NtSetInformationFile(handle, &status, &buffer[0], uint32(len(buffer)), windows.FileDispositionInformation); err != nil { return ErrUnsafeFile } return nil } func finishWindowsPrivateRegularCleanup(mark func() error, close func() error) error { failed := false if mark == nil || mark() != nil { failed = true } if close == nil || close() != nil { failed = true } if failed { return ErrUnsafeFile } return nil } func closeAndDeleteWindowsPrivateRegular(value *windowsPrivateRegularAt) error { if value == nil || value.handle == 0 { return ErrUnsafeFile } return finishWindowsPrivateRegularCleanup( func() error { return markWindowsHandleForDelete(value.handle) }, value.Close, ) } func (directory *windowsPrivateDirectory) CreateRegular(name string, contents []byte) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) || len(contents) == 0 { return false, ErrUnsafeFile } value, err := createWindowsPrivateRegularAt(directory.handle, name) if err != nil { existing, existingErr := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if existingErr == nil { closeErr := existing.Close() validateErr := directory.Validate() if closeErr != nil || validateErr != nil { return false, ErrUnsafeFile } return false, nil } return false, ErrUnsafeFile } published := false defer func() { if !published { _ = closeAndDeleteWindowsPrivateRegular(value) } }() if writeWindowsPrivateRegular(value, contents) != nil || directory.Validate() != nil { return false, ErrUnsafeFile } if value.Close() != nil { return false, ErrUnsafeFile } published = true return true, nil } func (directory *windowsPrivateDirectory) CreateRegularFile(name string) (*os.File, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) { return nil, false, ErrUnsafeFile } value, err := createWindowsPrivateRegularAt(directory.handle, name) if err != nil { existing, existingErr := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if existingErr == nil { if existing.Close() != nil || directory.Validate() != nil { return nil, false, ErrUnsafeFile } return nil, false, nil } return nil, false, ErrUnsafeFile } failed := true defer func() { if failed { _ = closeAndDeleteWindowsPrivateRegular(value) } }() info, err := privateWindowsRegularInfo(value.handle, 1) if err != nil || directory.Validate() != nil { return nil, false, ErrUnsafeFile } value.info = info file := os.NewFile(uintptr(value.handle), "tht-safeio-private-root-stream") if file == nil { return nil, false, ErrUnsafeFile } value.handle = 0 failed = false return file, true, nil } func (directory *windowsPrivateDirectory) ReadRegular(name string, maximum int64) ([]byte, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if isWindowsRelativeNotFound(err) { return nil, false, nil } if err != nil { return nil, false, ErrUnsafeFile } defer value.Close() contents, err := readWindowsPrivateRegular(value, maximum, 1) if err != nil || directory.Validate() != nil { return nil, false, ErrUnsafeFile } return contents, true, nil } type windowsRelativeNameInformation struct { Flags uint32 RootDirectory windows.Handle FileNameLength uint32 FileName [1]uint16 } func setWindowsRelativeNameInformation( handle windows.Handle, parent windows.Handle, name string, class uint32, flags uint32, ) error { if handle == 0 || parent == 0 || !validPrivateLeafName(name) { return ErrUnsafeFile } encoded, err := windows.UTF16FromString(name) if err != nil || len(encoded) < 2 { return ErrUnsafeFile } nameBytes := (len(encoded) - 1) * 2 var header windowsRelativeNameInformation size := int(unsafe.Offsetof(header.FileName)) + nameBytes buffer := make([]byte, size) value := (*windowsRelativeNameInformation)(unsafe.Pointer(&buffer[0])) value.Flags = flags value.RootDirectory = parent value.FileNameLength = uint32(nameBytes) copy(unsafe.Slice(&value.FileName[0], len(encoded)-1), encoded[:len(encoded)-1]) var status windows.IO_STATUS_BLOCK if err := windows.NtSetInformationFile(handle, &status, &buffer[0], uint32(len(buffer)), class); err != nil { return ErrUnsafeFile } runtime.KeepAlive(encoded) runtime.KeepAlive(buffer) return nil } func renameWindowsPrivateRegularAt(handle windows.Handle, parent windows.Handle, name string) error { return setWindowsRelativeNameInformation(handle, parent, name, windows.FileRenameInformation, windows.FILE_RENAME_REPLACE_IF_EXISTS) } func linkWindowsPrivateRegularAt(handle windows.Handle, parent windows.Handle, name string) error { return setWindowsRelativeNameInformation(handle, parent, name, windows.FileLinkInformation, 0) } func createWindowsPrivateTemporaryAt(parent windows.Handle, contents []byte) (*windowsPrivateRegularAt, error) { for attempt := 0; attempt < 16; attempt++ { name, err := randomTemporaryName() if err != nil { return nil, ErrUnsafeFile } value, err := createWindowsPrivateRegularAt(parent, name) if err != nil { if isWindowsRelativeCollision(err) { continue } return nil, ErrUnsafeFile } if writeWindowsPrivateRegular(value, contents) == nil { return value, nil } _ = closeAndDeleteWindowsPrivateRegular(value) return nil, ErrUnsafeFile } return nil, ErrUnsafeFile } func (directory *windowsPrivateDirectory) ReplaceRegular(name string, contents []byte) error { if directory.Validate() != nil || !validPrivateLeafName(name) || len(contents) == 0 { return ErrUnsafeFile } existing, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil { return ErrUnsafeFile } if existing.Close() != nil { return ErrUnsafeFile } temporary, err := createWindowsPrivateTemporaryAt(directory.handle, contents) if err != nil { return ErrUnsafeFile } renamed := false defer func() { if !renamed { _ = closeAndDeleteWindowsPrivateRegular(temporary) } }() current, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil { return ErrUnsafeFile } currentCloseErr := current.Close() currentValidateErr := directory.Validate() if currentCloseErr != nil || currentValidateErr != nil { return ErrUnsafeFile } renameErr := renameWindowsPrivateRegularAt(temporary.handle, directory.handle, name) temporaryCloseErr := temporary.Close() if renameErr != nil || temporaryCloseErr != nil { return ErrUnsafeFile } renamed = true replaced, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil { return ErrUnsafeFile } replacedCloseErr := replaced.Close() replacedValidateErr := directory.Validate() if replacedCloseErr != nil || replacedValidateErr != nil { return ErrUnsafeFile } return nil } func (directory *windowsPrivateDirectory) RemoveRegular(name string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) { return false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ|windows.DELETE, 1) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } cleanupErr := closeAndDeleteWindowsPrivateRegular(value) validateErr := directory.Validate() if cleanupErr != nil || validateErr != nil { return false, ErrUnsafeFile } return true, nil } func (directory *windowsPrivateDirectory) ListPage( maximumEntries int, afterName string, validName func(string) bool, validLinks func(string, uint64) bool, ) (PrivateDirectoryPage, error) { if directory.Validate() != nil || maximumEntries < 1 || maximumEntries > 4096 || validName == nil || validLinks == nil || (afterName != "" && !validName(afterName)) { return PrivateDirectoryPage{}, ErrUnsafeFile } var before windows.ByHandleFileInformation if err := windows.GetFileInformationByHandle(directory.handle, &before); err != nil || !sameWindowsPrivateDirectoryIdentity(directory.info, before) { return PrivateDirectoryPage{}, ErrUnsafeFile } duplicate, err := duplicateWindowsRetainedHandle(directory.handle) if err != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } file := os.NewFile(uintptr(duplicate), "tht-safeio-private-root-list") if file == nil { _ = windows.CloseHandle(duplicate) return PrivateDirectoryPage{}, ErrUnsafeFile } defer file.Close() seen := make(map[string]struct{}, maximumEntries+1) selected := make([]PrivateDirectoryEntry, 0, maximumEntries+1) scanned := 0 for { entries, readErr := file.ReadDir(1) if readErr != nil && !errors.Is(readErr, io.EOF) { return PrivateDirectoryPage{}, ErrUnsafeFile } if len(entries) == 0 { break } if len(entries) != 1 { return PrivateDirectoryPage{}, ErrUnsafeFile } scanned++ if scanned > maximumPrivateDirectoryPageScanEntries { return PrivateDirectoryPage{}, ErrUnsafeFile } name := entries[0].Name() if !validPrivateLeafName(name) || !validName(name) { return PrivateDirectoryPage{}, ErrUnsafeFile } if _, duplicate := seen[name]; duplicate { return PrivateDirectoryPage{}, ErrUnsafeFile } seen[name] = struct{}{} value, valueErr := openWindowsPrivateRegularAtAllowedLinks(directory.handle, name, windows.FILE_GENERIC_READ, 1, 2) if valueErr != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } info := value.info if value.Close() != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } if !validLinks(name, uint64(info.NumberOfLinks)) { return PrivateDirectoryPage{}, ErrUnsafeFile } if name > afterName { selected = appendBoundedPrivateDirectoryEntry(selected, PrivateDirectoryEntry{ Name: name, ModifiedUnixMs: time.Unix(0, info.LastWriteTime.Nanoseconds()).UnixMilli(), }, maximumEntries+1) } if errors.Is(readErr, io.EOF) { break } } var after windows.ByHandleFileInformation if windows.GetFileInformationByHandle(directory.handle, &after) != nil || directory.Validate() != nil || !sameWindowsPrivateDirectorySnapshot(before, after) { return PrivateDirectoryPage{}, ErrUnsafeFile } sort.Slice(selected, func(left, right int) bool { return selected[left].Name < selected[right].Name }) more := len(selected) > maximumEntries if more { selected = selected[:maximumEntries] } return PrivateDirectoryPage{Entries: selected, More: more}, nil } func sameWindowsRelativeClaim(source, claim *windowsPrivateRegularAt) bool { return source != nil && claim != nil && sameWindowsPrivateFile(source.info, claim.info) } func finishWindowsClaimCleanup(closeClaim, deleteSource, deleteClaim, validate func() error) error { failed := false for _, operation := range []func() error{closeClaim, deleteSource, deleteClaim, validate} { if operation == nil || operation() != nil { failed = true } } if failed { return ErrUnsafeFile } return nil } func windowsRelativeClaimPairExists(directory *windowsPrivateDirectory, source, claim string) (bool, error) { left, err := openWindowsPrivateRegularAt(directory.handle, source, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } defer left.Close() right, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } defer right.Close() return sameWindowsRelativeClaim(left, right), nil } func windowsRelativeClaimAbsentOrOrphan(directory *windowsPrivateDirectory, source, claim string) (bool, error) { current, err := openWindowsPrivateRegularAtAllowedLinks(directory.handle, source, windows.FILE_GENERIC_READ, 1, 2) if err == nil { _ = current.Close() return false, nil } if !isWindowsRelativeNotFound(err) { return false, ErrUnsafeFile } orphan, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 1) if err == nil { _ = orphan.Close() return true, nil } if isWindowsRelativeNotFound(err) { return true, nil } return false, ErrUnsafeFile } const windowsPrivateSharingRetries = 100 func waitForWindowsRelativeClaimLoss(directory *windowsPrivateDirectory, source, claim string) (bool, error) { for attempt := 0; ; attempt++ { pair, pairErr := windowsRelativeClaimPairExists(directory, source, claim) if pairErr == nil && pair { return true, nil } absent, absentErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if absentErr == nil && absent { return true, nil } if attempt == windowsPrivateSharingRetries { return false, ErrUnsafeFile } time.Sleep(time.Millisecond) } } func openWindowsPrivateClaimRegular( directory windows.Handle, name string, access uint32, allowedLinks uint32, ) (*windowsPrivateRegularAt, error) { for attempt := 0; ; attempt++ { value, err := openWindowsPrivateRegularAt(directory, name, access, allowedLinks) if !isWindowsRelativeSharingViolation(err) { return value, err } if attempt == windowsPrivateSharingRetries { return nil, err } time.Sleep(time.Millisecond) } } func (directory *windowsPrivateDirectory) ClaimRegular(source, claim string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) { return false, ErrUnsafeFile } // A concurrent winner temporarily holds the source with DELETE access and deliberately // without FILE_SHARE_DELETE. Wait only for that specific, bounded contention before // observing the resulting pair or absence below. Persistent sharing remains unsafe. value, err := openWindowsPrivateClaimRegular( directory.handle, source, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, 1, ) if err != nil { lost, observationErr := waitForWindowsRelativeClaimLoss(directory, source, claim) if observationErr == nil && lost { return false, nil } return false, ErrUnsafeFile } defer value.Close() if linkWindowsPrivateRegularAt(value.handle, directory.handle, claim) != nil { existing, existingErr := openWindowsPrivateRegularAtAllowedLinks(directory.handle, claim, windows.FILE_GENERIC_READ, 1, 2) if existingErr == nil { _ = existing.Close() return false, nil } return false, ErrUnsafeFile } after, err := privateWindowsRegularInfo(value.handle, 2) if err != nil { return false, ErrUnsafeFile } value.info = after claimed, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if err != nil { return false, ErrUnsafeFile } defer claimed.Close() if !sameWindowsRelativeClaim(value, claimed) || directory.Validate() != nil { return false, ErrUnsafeFile } return true, nil } func (directory *windowsPrivateDirectory) ReadClaim(source, claim string, maximum int64) ([]byte, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, source, windows.FILE_GENERIC_READ, 2) if err != nil { orphan, orphanErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if orphanErr == nil && orphan { return nil, false, nil } return nil, false, ErrUnsafeFile } defer value.Close() claimed, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return nil, false, nil } if err != nil { return nil, false, ErrUnsafeFile } defer claimed.Close() if !sameWindowsRelativeClaim(value, claimed) { return nil, false, ErrUnsafeFile } contents, err := readWindowsPrivateRegular(value, maximum, 2) if err != nil { return nil, false, ErrUnsafeFile } afterClaim, err := privateWindowsRegularInfo(claimed.handle, 2) if err != nil || !sameWindowsPrivateFile(value.info, afterClaim) || directory.Validate() != nil { return nil, false, ErrUnsafeFile } return contents, true, nil } func (directory *windowsPrivateDirectory) RemoveClaim(source, claim string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) { return false, ErrUnsafeFile } // A losing claimer can still be closing its no-delete source handle after observing the // existing hard-link pair. Treat only that bounded sharing window as contention. value, err := openWindowsPrivateClaimRegular( directory.handle, source, windows.FILE_GENERIC_READ|windows.DELETE, 2, ) if err != nil { orphan, orphanErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if orphanErr == nil && orphan { return false, nil } return false, ErrUnsafeFile } claimed, err := openWindowsPrivateRegularAtWithShareMode( directory.handle, claim, windows.FILE_GENERIC_READ, windowsRetainedHandleShareMode|windows.FILE_SHARE_DELETE, 2, ) if isWindowsRelativeNotFound(err) { closeErr := value.Close() validateErr := directory.Validate() if closeErr != nil || validateErr != nil { return false, ErrUnsafeFile } return false, nil } if err != nil || !sameWindowsRelativeClaim(value, claimed) { valueCloseErr := value.Close() claimedCloseErr := error(nil) if claimed != nil { claimedCloseErr = claimed.Close() } if valueCloseErr != nil || claimedCloseErr != nil || directory.Validate() != nil { return false, ErrUnsafeFile } return false, ErrUnsafeFile } cleanupErr := finishWindowsClaimCleanup( claimed.Close, func() error { return closeAndDeleteWindowsPrivateRegular(value) }, func() error { // A concurrent loser can briefly hold the orphan observation read-only after // source deletion. Preserve no-delete sharing and wait only for that close. remaining, remainingErr := openWindowsPrivateClaimRegular( directory.handle, claim, windows.FILE_GENERIC_READ|windows.DELETE, 1, ) if remainingErr != nil { return ErrUnsafeFile } return closeAndDeleteWindowsPrivateRegular(remaining) }, directory.Validate, ) if cleanupErr != nil { return false, ErrUnsafeFile } return true, nil }