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