feat: add native Windows hierarchy test harness
This commit is contained in:
@@ -43,7 +43,13 @@ type NativeOptions struct {
|
||||
MaxWrapperBytes uint64
|
||||
MaxOutputChunk uint64
|
||||
WindowsTermGrace time.Duration
|
||||
Now func() time.Time
|
||||
// TestContextFailures is populated only by the separately tagged native
|
||||
// fixture binary. It is deliberately not protocol or TOML policy: it lets
|
||||
// the fixture fail token preparation before launch so the real daemon can
|
||||
// prove its fallback order without creating a second broker or weakening a
|
||||
// release binary.
|
||||
TestContextFailures map[ExecutionContext]bool
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
// JobProfile is the validated administrator policy for one protocol profile.
|
||||
|
||||
@@ -388,6 +388,10 @@ func (manager *execSupervisor) selectToken(elevated bool) (winapi.Token, supervi
|
||||
}
|
||||
for _, attempt := range selection.Attempts {
|
||||
token, identity, err := openTokenForAttempt(attempt.Context, selected)
|
||||
if err == nil && manager.options.TestContextFailures[attempt.Context] {
|
||||
_ = token.Close()
|
||||
err = errors.New("native test fixture forced pre-launch context failure")
|
||||
}
|
||||
if err == nil {
|
||||
return token, withEvidence(identity), nil
|
||||
}
|
||||
@@ -396,6 +400,33 @@ func (manager *execSupervisor) selectToken(elevated bool) (winapi.Token, supervi
|
||||
return 0, supervisor.EffectiveIdentity{}, rejection(err)
|
||||
}
|
||||
}
|
||||
// Select stops at the first policy-available elevated context. Native
|
||||
// preparation can still fail after that point (a linked token can vanish or
|
||||
// SeTcbPrivilege can be unavailable), so preserve the documented order by
|
||||
// trying ACTIVE_SYSTEM before the final LOCAL_SYSTEM fallback. This is a
|
||||
// preparation fallback only: no child has been created yet.
|
||||
if elevated && selected != nil {
|
||||
seenActiveSystem := false
|
||||
for _, contextName := range attempted {
|
||||
if contextName == string(ContextActiveSystem) {
|
||||
seenActiveSystem = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !seenActiveSystem {
|
||||
addAttempt(ContextActiveSystem, "fallback after active-user-elevated preparation failure")
|
||||
if token, identity, err := openTokenForAttempt(ContextActiveSystem, selected); err == nil {
|
||||
if manager.options.TestContextFailures[ContextActiveSystem] {
|
||||
_ = token.Close()
|
||||
addAttempt(ContextActiveSystem, "native test fixture forced pre-launch context failure")
|
||||
} else {
|
||||
return token, withEvidence(identity), nil
|
||||
}
|
||||
} else {
|
||||
addAttempt(ContextActiveSystem, "native preparation failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
// The pure selector stops as soon as ACTIVE_SYSTEM is available. A native
|
||||
// privilege/session operation can still fail (for example, SeTcb was
|
||||
// removed), so the final LOCAL_SYSTEM fallback is attempted here before
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build !rvbox_native_test
|
||||
|
||||
package windows
|
||||
|
||||
import "fmt"
|
||||
|
||||
// NativeTestContextFailures is intentionally unavailable in shipped binaries.
|
||||
// The native fixture compiles a separately tagged test executable when it
|
||||
// needs to prove a pre-launch fallback row.
|
||||
func NativeTestContextFailures(raw string) (map[ExecutionContext]bool, error) {
|
||||
if raw != "" {
|
||||
return nil, fmt.Errorf("--test-fail-contexts requires the rvbox_native_test fixture build")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build rvbox_native_test
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NativeTestContextFailures accepts only the two active elevated preparation
|
||||
// stages. It is compiled into the disposable native-fixture binary, never a
|
||||
// release binary, and is applied before a process is launched.
|
||||
func NativeTestContextFailures(raw string) (map[ExecutionContext]bool, error) {
|
||||
if raw == "" {
|
||||
return nil, nil
|
||||
}
|
||||
result := make(map[ExecutionContext]bool)
|
||||
for _, item := range strings.Split(raw, ",") {
|
||||
contextName := ExecutionContext(strings.TrimSpace(item))
|
||||
switch contextName {
|
||||
case ContextActiveUserElevated, ContextActiveSystem:
|
||||
result[contextName] = true
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported native test context %q", item)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user