]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: always use LoadLibraryEx to load system libraries
authorqmuntal <quimmuntal@gmail.com>
Mon, 30 Jan 2023 13:42:17 +0000 (14:42 +0100)
committerDamien Neil <dneil@google.com>
Tue, 31 Jan 2023 22:06:41 +0000 (22:06 +0000)
This CL removes a fallback that used LoadLibraryA when the runtime
was loading system DLLs on Windows 7, Windows Server 2008 R2,
or earlier.

We can safely remove that fallback now, as go1.21 will require at least
Windows 8 or Server 2012.

This CL also saves some syscall initialization time and bytes:

new:
    init syscall @2.3 ms, 0 ms clock, 1000 bytes, 18 allocs
old:
    init syscall @3.6 ms, 0.52 ms clock, 1744 bytes, 24 allocs

Updates #57003

Change-Id: I7dcc1173537785b6b580e9f78632c0c74da658d4
Reviewed-on: https://go-review.googlesource.com/c/go/+/463842
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Damien Neil <dneil@google.com>
src/runtime/export_windows_test.go
src/runtime/os_windows.go
src/runtime/syscall_windows.go
src/runtime/syscall_windows_test.go
src/syscall/dll_windows.go
src/syscall/security_windows.go
src/syscall/zsyscall_windows.go

index d9cf753463940c2f6c2bfc0c8dd3a9de56179411..d4b1e1fad32e4ea8de626bb60a5f076773111cff 100644 (file)
@@ -21,7 +21,3 @@ func NumberOfProcessors() int32 {
        stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
        return int32(info.dwnumberofprocessors)
 }
-
-func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) {
-       return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
-}
index 60741f321ffb65730509c64921b4e5a8c3a1dc25..62be6350bddf52489d4b195a1d29dfc0da4c5a93 100644 (file)
@@ -37,8 +37,8 @@ const (
 //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._SetThreadContext SetThreadContext%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll"
 //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
-//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
 //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
 //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
 //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
@@ -88,8 +88,8 @@ var (
        _GetSystemTimeAsFileTime,
        _GetThreadContext,
        _SetThreadContext,
+       _LoadLibraryExW,
        _LoadLibraryW,
-       _LoadLibraryA,
        _PostQueuedCompletionStatus,
        _QueryPerformanceCounter,
        _QueryPerformanceFrequency,
@@ -116,10 +116,7 @@ var (
 
        // Following syscalls are only available on some Windows PCs.
        // We will load syscalls, if available, before using them.
-       _AddDllDirectory,
        _AddVectoredContinueHandler,
-       _LoadLibraryExA,
-       _LoadLibraryExW,
        _ stdFunction
 
        // Use RtlGenRandom to generate cryptographically random data.
@@ -146,6 +143,15 @@ var (
        _ stdFunction
 )
 
+var (
+       advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0}
+       kernel32dll = [...]uint16{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0}
+       ntdlldll    = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
+       powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
+       winmmdll    = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
+       ws2_32dll   = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0}
+)
+
 // Function to be called by windows CreateThread
 // to start new os thread.
 func tstart_stdcall(newm *m)
@@ -225,46 +231,35 @@ const _MAX_PATH = 260 // https://docs.microsoft.com/en-us/windows/win32/fileio/m
 var sysDirectory [_MAX_PATH + 1]byte
 var sysDirectoryLen uintptr
 
-func windowsLoadSystemLib(name []byte) uintptr {
-       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
-       }
-       if useLoadLibraryEx {
-               return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
-       } else {
-               absName := append(sysDirectory[:sysDirectoryLen], name...)
-               return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
+func initSysDirectory() {
+       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
+}
+
+func windowsLoadSystemLib(name []uint16) uintptr {
+       return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
 }
 
 const haveCputicksAsm = GOARCH == "386" || GOARCH == "amd64"
 
 func loadOptionalSyscalls() {
-       var kernel32dll = []byte("kernel32.dll\000")
-       k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
+       k32 := windowsLoadSystemLib(kernel32dll[:])
        if k32 == 0 {
                throw("kernel32.dll not found")
        }
-       _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
        _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\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 := windowsLoadSystemLib(advapi32dll)
+       a32 := windowsLoadSystemLib(advapi32dll[:])
        if a32 == 0 {
                throw("advapi32.dll not found")
        }
        _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
 
-       var ntdll = []byte("ntdll.dll\000")
-       n32 := windowsLoadSystemLib(ntdll)
+       n32 := windowsLoadSystemLib(ntdlldll[:])
        if n32 == 0 {
                throw("ntdll.dll not found")
        }
@@ -279,8 +274,7 @@ func loadOptionalSyscalls() {
                }
        }
 
-       var winmmdll = []byte("winmm.dll\000")
-       m32 := windowsLoadSystemLib(winmmdll)
+       m32 := windowsLoadSystemLib(winmmdll[:])
        if m32 == 0 {
                throw("winmm.dll not found")
        }
@@ -290,8 +284,7 @@ func loadOptionalSyscalls() {
                throw("timeBegin/EndPeriod not found")
        }
 
-       var ws232dll = []byte("ws2_32.dll\000")
-       ws232 := windowsLoadSystemLib(ws232dll)
+       ws232 := windowsLoadSystemLib(ws2_32dll[:])
        if ws232 == 0 {
                throw("ws2_32.dll not found")
        }
@@ -315,7 +308,7 @@ func monitorSuspendResume() {
                context  uintptr
        }
 
-       powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
+       powrprof := windowsLoadSystemLib(powrprofdll[:])
        if powrprof == 0 {
                return // Running on Windows 7, where we don't need it anyway.
        }
@@ -389,22 +382,6 @@ const (
 // in sys_windows_386.s and sys_windows_amd64.s:
 func getlasterror() uint32
 
-// When loading DLLs, we prefer to use LoadLibraryEx with
-// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
-// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
-// flags are not available on some versions of Windows without a
-// security patch.
-//
-// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
-// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
-// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
-// systems that have KB2533623 installed. To determine whether the
-// flags are available, use GetProcAddress to get the address of the
-// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
-// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
-// flags can be used with LoadLibraryEx."
-var useLoadLibraryEx bool
-
 var timeBeginPeriodRetValue uint32
 
 // osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
@@ -555,6 +532,7 @@ func osinit() {
        initHighResTimer()
        timeBeginPeriodRetValue = osRelax(false)
 
+       initSysDirectory()
        initLongPathSupport()
 
        ncpu = getproccount()
index 76036ad098e372af3cdd660cdee6fdbc6427730f..947f68510c1afb65726d573ade7af54ef6f9ae0f 100644 (file)
@@ -413,36 +413,23 @@ func callbackWrap(a *callbackArgs) {
 
 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
 //go:cgo_unsafe_args
-func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
+func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
        lockOSThread()
        c := &getg().m.syscall
-
-       if useLoadLibraryEx {
-               c.fn = getLoadLibraryEx()
-               c.n = 3
-               args := struct {
-                       lpFileName *uint16
-                       hFile      uintptr // always 0
-                       flags      uint32
-               }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
-               c.args = uintptr(noescape(unsafe.Pointer(&args)))
-       } else {
-               c.fn = getLoadLibrary()
-               c.n = 1
-               c.args = uintptr(noescape(unsafe.Pointer(&absoluteFilepath)))
-       }
+       c.fn = getLoadLibraryEx()
+       c.n = 3
+       args := struct {
+               lpFileName *uint16
+               hFile      uintptr // always 0
+               flags      uint32
+       }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
+       c.args = uintptr(noescape(unsafe.Pointer(&args)))
 
        cgocall(asmstdcallAddr, unsafe.Pointer(c))
        KeepAlive(filename)
-       KeepAlive(absoluteFilepath)
        handle = c.r1
        if handle == 0 {
                err = c.err
index abc28387e605e678d2eed6b8a148079880dc9820..b49da323841453f89d95591fa092e67b5836f5d6 100644 (file)
@@ -1164,10 +1164,7 @@ uintptr_t cfunc(void) {
        dll, err = syscall.LoadDLL(name)
        if err == nil {
                dll.Release()
-               if wantLoadLibraryEx() {
-                       t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
-               }
-               t.Skip("insecure load of DLL, but expected")
+               t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
        }
 }
 
@@ -1213,24 +1210,6 @@ func TestBigStackCallbackSyscall(t *testing.T) {
        }
 }
 
-// wantLoadLibraryEx reports whether we expect LoadLibraryEx to work for tests.
-func wantLoadLibraryEx() bool {
-       return testenv.Builder() != "" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "386")
-}
-
-func TestLoadLibraryEx(t *testing.T) {
-       use, have, flags := runtime.LoadLibraryExStatus()
-       if use {
-               return // success.
-       }
-       if wantLoadLibraryEx() {
-               t.Fatalf("Expected LoadLibraryEx+flags to be available. (LoadLibraryEx=%v; flags=%v)",
-                       have, flags)
-       }
-       t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)",
-               have, flags)
-}
-
 var (
        modwinmm    = syscall.NewLazyDLL("winmm.dll")
        modkernel32 = syscall.NewLazyDLL("kernel32.dll")
index 34b481d6e63543c1cf08cf1ea0d2ec664b66781a..78c8b0169a4e810d9527f92f7a76600fd9f2901f 100644 (file)
@@ -44,7 +44,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
 
 func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
 func loadlibrary(filename *uint16) (handle uintptr, err Errno)
-func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
+func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
 
 // A DLL implements access to a single DLL.
@@ -53,26 +53,6 @@ type DLL struct {
        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
@@ -89,11 +69,7 @@ func LoadDLL(name string) (*DLL, error) {
        var h uintptr
        var e Errno
        if sysdll.IsSystemDLL[name] {
-               absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
-               if err != nil {
-                       return nil, err
-               }
-               h, e = loadsystemlibrary(namep, absoluteFilepathp)
+               h, e = loadsystemlibrary(namep)
        } else {
                h, e = loadlibrary(namep)
        }
index 67102b69297acc58a85778be8f0cc1c86350f17a..00dc920974456c783335658ae7c0fc4ead04001e 100644 (file)
@@ -290,7 +290,6 @@ type Tokenprimarygroup struct {
 //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
index 61d89f146048cef62ca57b688fe3cd730711637a..9190ec8b20f2f46c7f1456c404fbd8a813bbc81d 100644 (file)
@@ -866,15 +866,6 @@ func GetStdHandle(stdhandle int) (handle Handle, err error) {
        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 {
-               err = errnoErr(e1)
-       }
-       return
-}
-
 func GetSystemTimeAsFileTime(time *Filetime) {
        Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
        return