diff options
| author | Paul Querna <paul@querna.org> | 2017-11-01 15:11:52 -0700 |
|---|---|---|
| committer | Alex Brainman <alex.brainman@gmail.com> | 2017-11-06 01:35:58 +0000 |
| commit | bb98331555a177f0e1256cebcfbc8a7b454bccd2 (patch) | |
| tree | 0d62f21310ba5e1a400307bf3446c68a5e1f049b /src/internal/syscall | |
| parent | 989cc80167e0ec4e8c220f1aec308dbdf4b9b0e9 (diff) | |
| download | go-bb98331555a177f0e1256cebcfbc8a7b454bccd2.tar.xz | |
syscall: add Token to Windows SysProcAttr
Fixes #21105
Change-Id: Ia2dea9b82a356795f581ce75616198b46e97abb6
Reviewed-on: https://go-review.googlesource.com/75253
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Diffstat (limited to 'src/internal/syscall')
| -rw-r--r-- | src/internal/syscall/windows/exec_windows_test.go | 153 | ||||
| -rw-r--r-- | src/internal/syscall/windows/security_windows.go | 26 | ||||
| -rw-r--r-- | src/internal/syscall/windows/zsyscall_windows.go | 26 |
3 files changed, 205 insertions, 0 deletions
diff --git a/src/internal/syscall/windows/exec_windows_test.go b/src/internal/syscall/windows/exec_windows_test.go new file mode 100644 index 0000000000..b1edb4d6af --- /dev/null +++ b/src/internal/syscall/windows/exec_windows_test.go @@ -0,0 +1,153 @@ +// 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 isWindowsXP(t) { + t.Skip("Windows XP does not support windows integrity levels") + } + + 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 syscall.CloseHandle(token) + + 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)) + } +} + +func isWindowsXP(t *testing.T) bool { + v, err := syscall.GetVersion() + if err != nil { + t.Fatalf("GetVersion failed: %v", err) + } + major := byte(v) + return major < 6 +} + +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.Handle, error) { + var token syscall.Handle + var procToken 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(syscall.Handle(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 { + syscall.CloseHandle(token) + return 0, err + } + return token, nil +} diff --git a/src/internal/syscall/windows/security_windows.go b/src/internal/syscall/windows/security_windows.go index 2c145e160f..2e34ea72e1 100644 --- a/src/internal/syscall/windows/security_windows.go +++ b/src/internal/syscall/windows/security_windows.go @@ -6,6 +6,7 @@ package windows import ( "syscall" + "unsafe" ) const ( @@ -55,3 +56,28 @@ func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newst } return err } + +//sys DuplicateTokenEx(hExistingToken syscall.Handle, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Handle) (err error) = advapi32.DuplicateTokenEx +//sys SetTokenInformation(tokenHandle syscall.Handle, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation + +type SID_AND_ATTRIBUTES struct { + Sid *syscall.SID + Attributes uint32 +} + +type TOKEN_MANDATORY_LABEL struct { + Label SID_AND_ATTRIBUTES +} + +func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 { + return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid) +} + +const SE_GROUP_INTEGRITY = 0x00000020 + +type TokenType uint32 + +const ( + TokenPrimary TokenType = 1 + TokenImpersonation TokenType = 2 +) diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go index 2af42c314f..ba16456b67 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -58,6 +58,8 @@ var ( procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") ) @@ -246,6 +248,30 @@ func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newst return } +func DuplicateTokenEx(hExistingToken syscall.Handle, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func SetTokenInformation(tokenHandle syscall.Handle, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) if r1 == 0 { |
