From 8097e1b27ff5e40620836729a9584e91b094b062 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 21 May 2019 17:16:17 +0200 Subject: [PATCH] windows: do not query library for inline functions The GetCurrent*Token variety of functions are actually implemented as inline functions in the header files of the SDK. Attempting to call out to these as library functions is an error. This commit also adds a test to ensure that these work as expected. Change-Id: I105f1ca1a8936114fe61bc22188200c31f240a23 Reviewed-on: https://go-review.googlesource.com/c/sys/+/177840 Run-TryBot: Jason Donenfeld TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- windows/security_windows.go | 27 ++++++++++++-- windows/syscall_windows_test.go | 65 +++++++++++++++++++++++++++++++++ windows/zsyscall_windows.go | 14 ------- 3 files changed, 89 insertions(+), 17 deletions(-) diff --git a/windows/security_windows.go b/windows/security_windows.go index f119a4ad..e9d26bee 100644 --- a/windows/security_windows.go +++ b/windows/security_windows.go @@ -583,9 +583,7 @@ func (tml *Tokenmandatorylabel) Size() uint32 { // Authorization Functions //sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership //sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken -//sys GetCurrentThreadToken() (token Token) = advapi32.GetCurrentThreadToken //sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken -//sys GetCurrentProcessToken() (token Token) = advapi32.GetCurrentProcessToken //sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf //sys RevertToSelf() (err error) = advapi32.RevertToSelf //sys SetThreadToken(thread *Handle, token Token) (err error) = advapi32.SetThreadToken @@ -608,7 +606,9 @@ func (tml *Tokenmandatorylabel) Size() uint32 { type Token Handle // OpenCurrentProcessToken opens the access token -// associated with current process. +// associated with current process. It is a real +// token that needs to be closed, unlike +// GetCurrentProcessToken. func OpenCurrentProcessToken() (Token, error) { p, e := GetCurrentProcess() if e != nil { @@ -622,6 +622,27 @@ func OpenCurrentProcessToken() (Token, error) { return t, nil } +// GetCurrentProcessToken returns the access token associated with +// the current process. It is a pseudo token that does not need +// to be closed. +func GetCurrentProcessToken() Token { + return Token(^uintptr(4 - 1)) +} + +// GetCurrentThreadToken return the access token associated with +// the current thread. It is a pseudo token that does not need +// to be closed. +func GetCurrentThreadToken() Token { + return Token(^uintptr(5 - 1)) +} + +// GetCurrentThreadEffectiveToken returns the effective access token +// associated with the current thread. It is a pseudo token that does +// not need to be closed. +func GetCurrentThreadEffectiveToken() Token { + return Token(^uintptr(6 - 1)) +} + // Close releases access to access token. func (t Token) Close() error { return CloseHandle(Handle(t)) diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index f2f449cd..423fa9ec 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "syscall" "testing" @@ -104,3 +105,67 @@ func TestCreateWellKnownSid(t *testing.T) { t.Fatalf("Expecting administrators to be S-1-5-32-544, but found %s instead", sidStr) } } + +func TestPseudoTokens(t *testing.T) { + version, err := windows.GetVersion() + if err != nil { + t.Fatal(err) + } + if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 { + return + } + + realProcessToken, err := windows.OpenCurrentProcessToken() + if err != nil { + t.Fatal(err) + } + defer realProcessToken.Close() + realProcessUser, err := realProcessToken.GetTokenUser() + if err != nil { + t.Fatal(err) + } + + pseudoProcessToken := windows.GetCurrentProcessToken() + pseudoProcessUser, err := pseudoProcessToken.GetTokenUser() + if err != nil { + t.Fatal(err) + } + if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) { + t.Fatal("The real process token does not have the same as the pseudo process token") + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + err = windows.RevertToSelf() + if err != nil { + t.Fatal(err) + } + + pseudoThreadToken := windows.GetCurrentThreadToken() + _, err = pseudoThreadToken.GetTokenUser() + if err != windows.ERROR_NO_TOKEN { + t.Fatal("Expected an empty thread token") + } + pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken() + pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser() + if err != nil { + t.Fatal(nil) + } + if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) { + t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating") + } + + err = windows.ImpersonateSelf(windows.SecurityImpersonation) + if err != nil { + t.Fatal(err) + } + defer windows.RevertToSelf() + pseudoThreadUser, err := pseudoThreadToken.GetTokenUser() + if err != nil { + t.Fatal(err) + } + if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) { + t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self") + } +} diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index 624d02fa..2a0f3969 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -259,9 +259,7 @@ var ( procEqualSid = modadvapi32.NewProc("EqualSid") procCheckTokenMembership = modadvapi32.NewProc("CheckTokenMembership") procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") - procGetCurrentThreadToken = modadvapi32.NewProc("GetCurrentThreadToken") procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") - procGetCurrentProcessToken = modadvapi32.NewProc("GetCurrentProcessToken") procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") procRevertToSelf = modadvapi32.NewProc("RevertToSelf") procSetThreadToken = modadvapi32.NewProc("SetThreadToken") @@ -2824,12 +2822,6 @@ func OpenProcessToken(process Handle, access uint32, token *Token) (err error) { return } -func GetCurrentThreadToken() (token Token) { - r0, _, _ := syscall.Syscall(procGetCurrentThreadToken.Addr(), 0, 0, 0, 0) - token = Token(r0) - return -} - func OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) { var _p0 uint32 if openAsSelf { @@ -2848,12 +2840,6 @@ func OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token return } -func GetCurrentProcessToken() (token Token) { - r0, _, _ := syscall.Syscall(procGetCurrentProcessToken.Addr(), 0, 0, 0, 0) - token = Token(r0) - return -} - func ImpersonateSelf(impersonationlevel uint32) (err error) { r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) if r1 == 0 {