diff --git a/tools/tht/internal/safeio/private_windows_test.go b/tools/tht/internal/safeio/private_windows_test.go index 6d45525f..c17595b0 100644 --- a/tools/tht/internal/safeio/private_windows_test.go +++ b/tools/tht/internal/safeio/private_windows_test.go @@ -9,6 +9,7 @@ import ( "runtime" "strings" "testing" + "unsafe" "golang.org/x/sys/windows" ) @@ -68,6 +69,72 @@ func TestOwnerOnlyDACLAcceptsWindowsFullControlMask(t *testing.T) { } } +func TestOwnerOnlyDACLNativeShape(t *testing.T) { + directory := filepath.Join(t.TempDir(), "auth") + if err := os.Mkdir(directory, 0o700); err != nil { + t.Fatal(err) + } + parents, target, err := openCanonicalWindowsParent(directory) + if err != nil { + t.Fatalf("openCanonicalWindowsParent() error = %T %v", err, err) + } + defer parents.Close() + handle, err := openWindowsRelativeComponent( + parents.handles[len(parents.handles)-1], + target, + true, + windows.GENERIC_READ|windows.WRITE_DAC|windows.WRITE_OWNER, + ) + if err != nil { + t.Fatalf("openWindowsRelativeComponent() error = %T %v", err, err) + } + defer windows.CloseHandle(handle) + if err := setOwnerOnlyDACL(handle); err != nil { + t.Fatalf("setOwnerOnlyDACL() error = %T %v", err, err) + } + + descriptor, err := windows.GetSecurityInfo(handle, windows.SE_FILE_OBJECT, + windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION) + if err != nil || descriptor == nil { + t.Fatalf("GetSecurityInfo() error = %T %v descriptor=%p", err, err, descriptor) + } + owner, ownerDefaulted, err := descriptor.Owner() + if err != nil || owner == nil { + t.Fatalf("security descriptor owner error = %T %v owner=%p defaulted=%t", err, err, owner, ownerDefaulted) + } + control, _, err := descriptor.Control() + if err != nil { + t.Fatalf("security descriptor control error = %T %v", err, err) + } + dacl, daclDefaulted, err := descriptor.DACL() + if err != nil || dacl == nil { + t.Fatalf("security descriptor DACL error = %T %v dacl=%p defaulted=%t control=%#x", err, err, dacl, daclDefaulted, uint16(control)) + } + if dacl.AceCount != 1 { + t.Fatalf("security descriptor ACE count = %d, want 1 (control=%#x)", dacl.AceCount, uint16(control)) + } + var ace *windows.ACCESS_ALLOWED_ACE + if err := windows.GetAce(dacl, 0, &ace); err != nil || ace == nil { + t.Fatalf("security descriptor ACE error = %T %v ace=%p", err, err, ace) + } + ownerSID, err := currentOwnerSID() + if err != nil { + t.Fatalf("currentOwnerSID() error = %T %v", err, err) + } + aceSID := (*windows.SID)(unsafe.Pointer(&ace.SidStart)) + if !windows.EqualSid(owner, ownerSID) || !windows.EqualSid(aceSID, ownerSID) || + control&windows.SE_DACL_PROTECTED == 0 || daclDefaulted || + ace.Header.AceType != windows.ACCESS_ALLOWED_ACE_TYPE || ace.Header.AceFlags != 0 || + !isOwnerOnlyFullControlMask(uint32(ace.Mask)) { + t.Fatalf("owner-only DACL shape invalid: ownerMatch=%t aceOwnerMatch=%t control=%#x daclDefaulted=%t aceType=%d aceFlags=%#x mask=%#x", + windows.EqualSid(owner, ownerSID), windows.EqualSid(aceSID, ownerSID), uint16(control), daclDefaulted, + ace.Header.AceType, ace.Header.AceFlags, uint32(ace.Mask)) + } + if err := validateOwnerOnlyDACL(handle); err != nil { + t.Fatalf("validateOwnerOnlyDACL() rejected native shape: %T %v (control=%#x mask=%#x)", err, err, uint16(control), uint32(ace.Mask)) + } +} + func TestWindowsPrivateRegularCleanupClosesAfterDeleteDispositionFailure(t *testing.T) { var calls []string err := finishWindowsPrivateRegularCleanup(