// 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.
// +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
}