mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-10 05:01:28 -10:00
* fix(sandbox): keep Windows restricted-token SIDs narrow and fail closed on DenyRead * fix(sandbox): address CodeRabbit review feedback on PR 640 * refactor(sandbox): Address CodeRabbit nitpicks on PR 640. Co-Authored-By: cairn-code <[email protected]> * fix(sandbox): skip inherited ACEs and reject DenyRead upfront during setup Skip inherited ACEs when preserving read deny entries, correct syntax in the command runner error message, and evaluate unsupported DenyRead profiles before the elevation check in Windows sandbox setup. Refs #640 * Reject unsupported DenyRead profiles upfront during sandbox setup Refs #640 * Migrate legacy Windows DenyWrite ACEs, randomize smoke probes, and clean dead descendant machinery. Refs #640 * Use /d /c for denied-write probe command and verify ownership on cleanup. Refs #640 * Honor NoInherit in legacy ACL migration and verify probe ownership. Refs #639 * Preserve DenyRead bits when migrating combined legacy deny ACEs. Refs #639 --------- Co-authored-by: euxaristia <[email protected]> Co-authored-by: cairn-code <[email protected]>
64 lines
2.1 KiB
Go
64 lines
2.1 KiB
Go
package sandbox
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestWindowsDenyReadRestrictedTokenUnsupported(t *testing.T) {
|
|
// Both restricted-token runner levels reject DenyRead before launch/setup.
|
|
for _, level := range []WindowsSandboxLevel{
|
|
WindowsSandboxLevelRestrictedToken,
|
|
WindowsSandboxLevelUnelevated,
|
|
} {
|
|
err := windowsDenyReadRestrictedTokenUnsupported(WindowsSandboxCommandConfig{
|
|
SandboxLevel: level,
|
|
PermissionProfile: PermissionProfile{
|
|
FileSystem: FileSystemPolicy{
|
|
Kind: FileSystemRestricted,
|
|
DenyRead: []string{`C:\secret`, `D:\private`},
|
|
},
|
|
},
|
|
})
|
|
if err == nil {
|
|
t.Fatalf("expected unsupported error for %s DenyRead profile", level)
|
|
}
|
|
msg := err.Error()
|
|
for _, want := range []string{"DenyRead", "not supported", "restricted-token", "unelevated", "path count: 2"} {
|
|
if !strings.Contains(msg, want) {
|
|
t.Fatalf("%s error %q missing %q", level, msg, want)
|
|
}
|
|
}
|
|
// DenyRead often names credential or private-file paths; keep them out of stderr.
|
|
for _, secret := range []string{`C:\secret`, `D:\private`} {
|
|
if strings.Contains(msg, secret) {
|
|
t.Fatalf("%s error leaked DenyRead path %q: %q", level, secret, msg)
|
|
}
|
|
}
|
|
if strings.Contains(msg, "--sandbox forbid") {
|
|
t.Fatalf("%s error advertises unsupported --sandbox forbid recovery: %q", level, msg)
|
|
}
|
|
if strings.Contains(msg, "sandbox_permissions") || strings.Contains(msg, "require_escalated") {
|
|
t.Fatalf("%s error advertises unusable escalation recovery: %q", level, msg)
|
|
}
|
|
if !strings.Contains(msg, "Remove DenyRead") {
|
|
t.Fatalf("%s error should advise removing DenyRead: %q", level, msg)
|
|
}
|
|
}
|
|
|
|
// No DenyRead: allowed (WRITE_RESTRICTED path can launch system tools).
|
|
for _, level := range []WindowsSandboxLevel{
|
|
WindowsSandboxLevelRestrictedToken,
|
|
WindowsSandboxLevelUnelevated,
|
|
} {
|
|
if err := windowsDenyReadRestrictedTokenUnsupported(WindowsSandboxCommandConfig{
|
|
SandboxLevel: level,
|
|
PermissionProfile: PermissionProfile{
|
|
FileSystem: FileSystemPolicy{Kind: FileSystemRestricted},
|
|
},
|
|
}); err != nil {
|
|
t.Fatalf("unexpected error without DenyRead at %s: %v", level, err)
|
|
}
|
|
}
|
|
}
|