github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/syscall/windows/exec_windows_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build windows 6 7 package windows_test 8 9 import ( 10 "fmt" 11 "os" 12 "os/exec" 13 "syscall" 14 "testing" 15 "unsafe" 16 17 "github.com/go-asm/go/syscall/windows" 18 ) 19 20 func TestRunAtLowIntegrity(t *testing.T) { 21 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 22 wil, err := getProcessIntegrityLevel() 23 if err != nil { 24 fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) 25 os.Exit(9) 26 return 27 } 28 fmt.Printf("%s", wil) 29 os.Exit(0) 30 return 31 } 32 33 cmd := exec.Command(os.Args[0], "-test.run=^TestRunAtLowIntegrity$", "--") 34 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 35 36 token, err := getIntegrityLevelToken(sidWilLow) 37 if err != nil { 38 t.Fatal(err) 39 } 40 defer token.Close() 41 42 cmd.SysProcAttr = &syscall.SysProcAttr{ 43 Token: token, 44 } 45 46 out, err := cmd.CombinedOutput() 47 if err != nil { 48 t.Fatal(err) 49 } 50 51 if string(out) != sidWilLow { 52 t.Fatalf("Child process did not run as low integrity level: %s", string(out)) 53 } 54 } 55 56 const ( 57 sidWilLow = `S-1-16-4096` 58 ) 59 60 func getProcessIntegrityLevel() (string, error) { 61 procToken, err := syscall.OpenCurrentProcessToken() 62 if err != nil { 63 return "", err 64 } 65 defer procToken.Close() 66 67 p, err := tokenGetInfo(procToken, syscall.TokenIntegrityLevel, 64) 68 if err != nil { 69 return "", err 70 } 71 72 tml := (*windows.TOKEN_MANDATORY_LABEL)(p) 73 74 sid := (*syscall.SID)(unsafe.Pointer(tml.Label.Sid)) 75 76 return sid.String() 77 } 78 79 func tokenGetInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) { 80 n := uint32(initSize) 81 for { 82 b := make([]byte, n) 83 e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) 84 if e == nil { 85 return unsafe.Pointer(&b[0]), nil 86 } 87 if e != syscall.ERROR_INSUFFICIENT_BUFFER { 88 return nil, e 89 } 90 if n <= uint32(len(b)) { 91 return nil, e 92 } 93 } 94 } 95 96 func getIntegrityLevelToken(wns string) (syscall.Token, error) { 97 var procToken, token syscall.Token 98 99 proc, err := syscall.GetCurrentProcess() 100 if err != nil { 101 return 0, err 102 } 103 defer syscall.CloseHandle(proc) 104 105 err = syscall.OpenProcessToken(proc, 106 syscall.TOKEN_DUPLICATE| 107 syscall.TOKEN_ADJUST_DEFAULT| 108 syscall.TOKEN_QUERY| 109 syscall.TOKEN_ASSIGN_PRIMARY, 110 &procToken) 111 if err != nil { 112 return 0, err 113 } 114 defer procToken.Close() 115 116 sid, err := syscall.StringToSid(wns) 117 if err != nil { 118 return 0, err 119 } 120 121 tml := &windows.TOKEN_MANDATORY_LABEL{} 122 tml.Label.Attributes = windows.SE_GROUP_INTEGRITY 123 tml.Label.Sid = sid 124 125 err = windows.DuplicateTokenEx(procToken, 0, nil, windows.SecurityImpersonation, 126 windows.TokenPrimary, &token) 127 if err != nil { 128 return 0, err 129 } 130 131 err = windows.SetTokenInformation(token, 132 syscall.TokenIntegrityLevel, 133 uintptr(unsafe.Pointer(tml)), 134 tml.Size()) 135 if err != nil { 136 token.Close() 137 return 0, err 138 } 139 return token, nil 140 }