fix(auth): pin native auth storage operations
This commit is contained in:
@@ -71,6 +71,96 @@ func TestProtocolValidatesAndCreatesTheCompleteWindowsSessionLayout(t *testing.T
|
||||
runRejected(t, request{Version: 1, Operation: "validate-root", Root: root})
|
||||
}
|
||||
|
||||
func TestProtocolReadsWindowsLocalUsersWithOwnerOnlyDACLAndNoReparseFallback(t *testing.T) {
|
||||
root := filepath.Join(t.TempDir(), "auth")
|
||||
if err := safeio.EnsurePrivateDirectory(root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(root, "users.yaml")
|
||||
contents := []byte("version: 1\nusers: []\n")
|
||||
if err := safeio.WriteCanonicalNewPrivateFile(path, contents, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
read := runRequest(t, request{Version: 1, Operation: "read-local-users", Root: root, Filename: "users.yaml"})
|
||||
if !read.Found || decodeContent(t, read) != string(contents) {
|
||||
t.Fatalf("read-local-users = %#v", read)
|
||||
}
|
||||
if err := setPermissiveDACL(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runRejected(t, request{Version: 1, Operation: "read-local-users", Root: root, Filename: "users.yaml"})
|
||||
|
||||
if err := os.Remove(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(filepath.Join(root, "missing-target.yaml"), path); err != nil {
|
||||
t.Skipf("Windows host does not permit test symlink creation: %v", err)
|
||||
}
|
||||
runRejected(t, request{Version: 1, Operation: "read-local-users", Root: root, Filename: "users.yaml"})
|
||||
}
|
||||
|
||||
func TestProtocolValidateLayoutPinsWindowsRootAcrossMissingAndUnsafeChildren(t *testing.T) {
|
||||
for _, scenario := range []struct {
|
||||
name string
|
||||
originalUnsafe bool
|
||||
replacementUnsafe bool
|
||||
wantAccepted bool
|
||||
}{
|
||||
{name: "rejects unsafe retained child", originalUnsafe: true, wantAccepted: false},
|
||||
{name: "accepts missing retained child while replacement is unsafe", replacementUnsafe: true, wantAccepted: true},
|
||||
} {
|
||||
t.Run(scenario.name, func(t *testing.T) {
|
||||
parent := t.TempDir()
|
||||
root := filepath.Join(parent, "auth")
|
||||
replacement := filepath.Join(parent, "replacement")
|
||||
moved := filepath.Join(parent, "auth-original")
|
||||
for _, directory := range []string{root, replacement} {
|
||||
if err := safeio.EnsurePrivateDirectory(directory); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if scenario.originalUnsafe {
|
||||
path := filepath.Join(root, "sessions")
|
||||
if err := safeio.EnsurePrivateDirectory(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setPermissiveDACL(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if scenario.replacementUnsafe {
|
||||
path := filepath.Join(replacement, "sessions")
|
||||
if err := safeio.EnsurePrivateDirectory(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := setPermissiveDACL(path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
blocked := false
|
||||
restore := safeio.SetPrivateDirectoryTestHookForTest(func(stage string) {
|
||||
if stage != "after-auth-root-open" || blocked {
|
||||
return
|
||||
}
|
||||
if err := os.Rename(root, moved); err == nil {
|
||||
t.Fatal("retained Windows root handle permitted rename")
|
||||
}
|
||||
blocked = true
|
||||
})
|
||||
t.Cleanup(restore)
|
||||
input := request{Version: 1, Operation: "validate-root", Root: root}
|
||||
if scenario.wantAccepted {
|
||||
runRequest(t, input)
|
||||
} else {
|
||||
runRejected(t, input)
|
||||
}
|
||||
if !blocked {
|
||||
t.Fatal("layout validation did not retain the Windows root handle")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setPermissiveDACL(path string) error {
|
||||
world, err := windows.StringToSid("S-1-1-0")
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user