src/runtime/os_windows.go | 64 ++++++++++++++++++++++++++++++++++++++++++++--------- src/runtime/syscall_windows.go | 14 ++++++-------- src/syscall/dll_windows.go | 28 ++++++++++++++++++++++++++-- src/syscall/security_windows.go | 1 + src/syscall/zsyscall_windows.go | 14 ++++++++++++++ diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 5607bf95c1d59f093765126ef3dbeecc74c34c53..a3d0bcc596cecd0a603b58c6c075af49e066439d 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -29,6 +29,7 @@ //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll" //go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll" //go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll" //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll" +//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll" //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll" //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" @@ -46,12 +47,9 @@ //go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll" //go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll" //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" //go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll" -//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll" //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll" //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" -//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll" -//go:cgo_import_dynamic runtime._timeEndPeriod timeEndPeriod%1 "winmm.dll" type stdFunction unsafe.Pointer @@ -74,6 +72,7 @@ _GetProcAddress, _GetProcessAffinityMask, _GetQueuedCompletionStatus, _GetStdHandle, + _GetSystemDirectoryA, _GetSystemInfo, _GetSystemTimeAsFileTime, _GetThreadContext, @@ -94,12 +93,9 @@ _SwitchToThread, _VirtualAlloc, _VirtualFree, _VirtualQuery, - _WSAGetOverlappedResult, _WaitForSingleObject, _WriteConsoleW, _WriteFile, - _timeBeginPeriod, - _timeEndPeriod, _ stdFunction // Following syscalls are only available on some Windows PCs. @@ -107,6 +103,7 @@ // We will load syscalls, if available, before using them. _AddDllDirectory, _AddVectoredContinueHandler, _GetQueuedCompletionStatusEx, + _LoadLibraryExA, _LoadLibraryExW, _ stdFunction @@ -124,6 +121,12 @@ // Load ntdll.dll manually during startup, otherwise Mingw // links wrong printf function to cgo executable (see issue // 12030 for details). _NtWaitForSingleObject stdFunction + + // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. + _timeBeginPeriod, + _timeEndPeriod, + _WSAGetOverlappedResult, + _ stdFunction ) // Function to be called by windows CreateThread @@ -171,6 +174,26 @@ f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0]))) return stdFunction(unsafe.Pointer(f)) } +var sysDirectory [521]byte +var sysDirectoryLen uintptr + +func windowsLoadSystemLib(name []byte) uintptr { + if useLoadLibraryEx { + return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) + } else { + if sysDirectoryLen == 0 { + l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1)) + if l == 0 || l > uintptr(len(sysDirectory)-1) { + throw("Unable to determine system directory") + } + sysDirectory[l] = '\\' + sysDirectoryLen = l + 1 + } + absName := append(sysDirectory[:sysDirectoryLen], name...) + return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0]))) + } +} + func loadOptionalSyscalls() { var kernel32dll = []byte("kernel32.dll\000") k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) @@ -180,21 +203,44 @@ } _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) _GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000")) + _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000")) _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) + useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil) var advapi32dll = []byte("advapi32.dll\000") - a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0]))) + a32 := windowsLoadSystemLib(advapi32dll) if a32 == 0 { throw("advapi32.dll not found") } _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) var ntdll = []byte("ntdll.dll\000") - n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0]))) + n32 := windowsLoadSystemLib(ntdll) if n32 == 0 { throw("ntdll.dll not found") } _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000")) + + var winmmdll = []byte("winmm.dll\000") + m32 := windowsLoadSystemLib(winmmdll) + if m32 == 0 { + throw("winmm.dll not found") + } + _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) + _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) + if _timeBeginPeriod == nil || _timeEndPeriod == nil { + throw("timeBegin/EndPeriod not found") + } + + var ws232dll = []byte("ws2_32.dll\000") + ws232 := windowsLoadSystemLib(ws232dll) + if ws232 == 0 { + throw("ws2_32.dll not found") + } + _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000")) + if _WSAGetOverlappedResult == nil { + throw("WSAGetOverlappedResult not found") + } if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil { // running on Wine @@ -301,8 +347,6 @@ setBadSignalMsg() loadOptionalSyscalls() - - useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil) disableWER() diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 8264070569ff360ea1beeccb82e43da40b21fa2d..ee931ceb0a57d163e081290d02908800de37e5e9 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -90,9 +90,13 @@ } const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 +// When available, this function will use LoadLibraryEx with the filename +// parameter and the important SEARCH_SYSTEM32 argument. But on systems that +// do not have that option, absoluteFilepath should contain a fallback +// to the full path inside of system32 for use with vanilla LoadLibrary. //go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary //go:nosplit -func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { +func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) { lockOSThread() defer unlockOSThread() c := &getg().m.syscall @@ -107,15 +111,9 @@ flags uint32 }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32} c.args = uintptr(noescape(unsafe.Pointer(&args))) } else { - // User doesn't have KB2533623 installed. The caller - // wanted to only load the filename DLL from the - // System32 directory but that facility doesn't exist, - // so just load it the normal way. This is a potential - // security risk, but so is not installing security - // updates. c.fn = getLoadLibrary() c.n = 1 - c.args = uintptr(noescape(unsafe.Pointer(&filename))) + c.args = uintptr(noescape(unsafe.Pointer(&absoluteFilepath))) } cgocall(asmstdcallAddr, unsafe.Pointer(c)) diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go index 2ee85a0d77da1adb651cac78f1908a0d6289ec67..577ca96b1c80cf4a57fcec3620c281f17aa14e2b 100644 --- a/src/syscall/dll_windows.go +++ b/src/syscall/dll_windows.go @@ -27,7 +27,7 @@ func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) func loadlibrary(filename *uint16) (handle uintptr, err Errno) -func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno) +func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno) func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) // A DLL implements access to a single DLL. @@ -36,6 +36,26 @@ Name string Handle Handle } +// We use this for computing the absolute path for system DLLs on systems +// where SEARCH_SYSTEM32 is not available. +var systemDirectoryPrefix string + +func init() { + n := uint32(MAX_PATH) + for { + b := make([]uint16, n) + l, e := getSystemDirectory(&b[0], n) + if e != nil { + panic("Unable to determine system directory: " + e.Error()) + } + if l <= n { + systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\" + break + } + n = l + } +} + // LoadDLL loads the named DLL file into memory. // // If name is not an absolute path and is not a known system DLL used by @@ -52,7 +72,11 @@ } var h uintptr var e Errno if sysdll.IsSystemDLL[name] { - h, e = loadsystemlibrary(namep) + absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name) + if err != nil { + return nil, err + } + h, e = loadsystemlibrary(namep, absoluteFilepathp) } else { h, e = loadlibrary(namep) } diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go index ae8b3a17bfb0f77a000726687994b3ab065e6156..db80d98a084d019832c52cce5a77126663951ecc 100644 --- a/src/syscall/security_windows.go +++ b/src/syscall/security_windows.go @@ -290,6 +290,7 @@ //sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken //sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation //sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW +//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW // An access token contains the security information for a logon session. // The system creates an access token when a user logs on, and every diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index de2d4f3adb5d0f7835476aa7212a95a7601d0b3c..2348f6534f7af7c675250bb8091af1963ffa1c87 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -190,6 +190,7 @@ procCopySid = modadvapi32.NewProc("CopySid") procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") + procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW") ) func GetLastError() (lasterr error) { @@ -1916,3 +1917,16 @@ } } return } + +func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { + r0, _, e1 := Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + len = uint32(r0) + if len == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = EINVAL + } + } + return +}