fix: complete P2 host workspace contract

This commit is contained in:
2026-08-11 00:39:44 +02:00
parent ccaf8c1be0
commit 9df7c38069
13 changed files with 849 additions and 252 deletions
@@ -54,7 +54,29 @@ func ReadCanonicalRegular(path string, maximum int64) ([]byte, error) {
return nil, ErrUnsafeFile
}
defer file.Close()
return readBoundedRegularFile(file, maximum)
var before, after windows.ByHandleFileInformation
if windows.GetFileInformationByHandle(handle, &before) != nil || before.NumberOfLinks > 1 {
return nil, ErrUnsafeFile
}
contents, err := readBoundedRegularFile(file, maximum)
if err != nil {
return nil, ErrUnsafeFile
}
if windows.GetFileInformationByHandle(handle, &after) != nil || after.NumberOfLinks > 1 || !sameWindowsFile(before, after) {
return nil, ErrUnsafeFile
}
// Re-opened pathname identity is checked as well as the retained handle. This
// catches replacement by an ordinary local actor where share/delete policy permits it.
check, err := openWindowsComponent(current, false)
if err != nil {
return nil, ErrUnsafeFile
}
defer windows.CloseHandle(check)
var named windows.ByHandleFileInformation
if windows.GetFileInformationByHandle(check, &named) != nil || named.NumberOfLinks > 1 || !sameWindowsFile(before, named) {
return nil, ErrUnsafeFile
}
return contents, nil
}
func openWindowsComponent(path string, directory bool) (windows.Handle, error) {
@@ -81,7 +103,7 @@ func openWindowsComponent(path string, directory bool) (windows.Handle, error) {
windows.CloseHandle(handle)
return 0, err
}
if information.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 ||
if information.NumberOfLinks > 1 || information.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 ||
(directory && information.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0) ||
(!directory && information.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY != 0) {
windows.CloseHandle(handle)
@@ -113,7 +135,22 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
if _, err := f.Write(contents); err != nil {
return ErrUnsafeFile
}
return f.Sync()
if err := f.Sync(); err != nil {
return ErrUnsafeFile
}
var opened, named windows.ByHandleFileInformation
if windows.GetFileInformationByHandle(h, &opened) != nil || opened.NumberOfLinks != 1 {
return ErrUnsafeFile
}
check, err := openWindowsComponent(path, false)
if err != nil {
return ErrUnsafeFile
}
defer windows.CloseHandle(check)
if windows.GetFileInformationByHandle(check, &named) != nil || named.NumberOfLinks != 1 || !sameWindowsFile(opened, named) {
return ErrUnsafeFile
}
return nil
}
func validateCanonicalOutputPath(path string) error {
@@ -140,3 +177,7 @@ func validateCanonicalOutputPath(path string) error {
}
return nil
}
func sameWindowsFile(a, b windows.ByHandleFileInformation) bool {
return a.VolumeSerialNumber == b.VolumeSerialNumber && a.FileIndexHigh == b.FileIndexHigh && a.FileIndexLow == b.FileIndexLow
}