// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build windows package windows_test import ( "fmt" "internal/syscall/windows" "os" "os/exec" "syscall" "testing" "unsafe" ) func TestRunAtLowIntegrity(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { wil, err := getProcessIntegrityLevel() if err != nil { fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) os.Exit(9) return } fmt.Printf("%s", wil) os.Exit(0) return } cmd := exec.Command(os.Args[0], "-test.run=^TestRunAtLowIntegrity$", "--") cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} token, err := getIntegrityLevelToken(sidWilLow) if err != nil { t.Fatal(err) } defer token.Close() cmd.SysProcAttr = &syscall.SysProcAttr{ Token: token, } out, err := cmd.CombinedOutput() if err != nil { t.Fatal(err) } if string(out) != sidWilLow { t.Fatalf("Child process did not run as low integrity level: %s", string(out)) } } const ( sidWilLow = `S-1-16-4096` ) func getProcessIntegrityLevel() (string, error) { procToken, err := syscall.OpenCurrentProcessToken() if err != nil { return "", err } defer procToken.Close() p, err := tokenGetInfo(procToken, syscall.TokenIntegrityLevel, 64) if err != nil { return "", err } tml := (*windows.TOKEN_MANDATORY_LABEL)(p) sid := (*syscall.SID)(unsafe.Pointer(tml.Label.Sid)) return sid.String() } func tokenGetInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) { n := uint32(initSize) for { b := make([]byte, n) e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) if e == nil { return unsafe.Pointer(&b[0]), nil } if e != syscall.ERROR_INSUFFICIENT_BUFFER { return nil, e } if n <= uint32(len(b)) { return nil, e } } } func getIntegrityLevelToken(wns string) (syscall.Token, error) { var procToken, token syscall.Token proc, err := syscall.GetCurrentProcess() if err != nil { return 0, err } defer syscall.CloseHandle(proc) err = syscall.OpenProcessToken(proc, syscall.TOKEN_DUPLICATE| syscall.TOKEN_ADJUST_DEFAULT| syscall.TOKEN_QUERY| syscall.TOKEN_ASSIGN_PRIMARY, &procToken) if err != nil { return 0, err } defer procToken.Close() sid, err := syscall.StringToSid(wns) if err != nil { return 0, err } tml := &windows.TOKEN_MANDATORY_LABEL{} tml.Label.Attributes = windows.SE_GROUP_INTEGRITY tml.Label.Sid = sid err = windows.DuplicateTokenEx(procToken, 0, nil, windows.SecurityImpersonation, windows.TokenPrimary, &token) if err != nil { return 0, err } err = windows.SetTokenInformation(token, syscall.TokenIntegrityLevel, uintptr(unsafe.Pointer(tml)), tml.Size()) if err != nil { token.Close() return 0, err } return token, nil }