Skip to content

Commit a17d959

Browse files
qmuntalneild
authored andcommitted
runtime: always use LoadLibraryEx to load system libraries
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 <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Run-TryBot: Quim Muntal <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 34d0268 commit a17d959

7 files changed

+40
-134
lines changed

src/runtime/export_windows_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,3 @@ func NumberOfProcessors() int32 {
2121
stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
2222
return int32(info.dwnumberofprocessors)
2323
}
24-
25-
func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) {
26-
return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
27-
}

src/runtime/os_windows.go

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ const (
3737
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
3838
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
3939
//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll"
40+
//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll"
4041
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
41-
//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
4242
//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
4343
//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
4444
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
@@ -88,8 +88,8 @@ var (
8888
_GetSystemTimeAsFileTime,
8989
_GetThreadContext,
9090
_SetThreadContext,
91+
_LoadLibraryExW,
9192
_LoadLibraryW,
92-
_LoadLibraryA,
9393
_PostQueuedCompletionStatus,
9494
_QueryPerformanceCounter,
9595
_QueryPerformanceFrequency,
@@ -116,10 +116,7 @@ var (
116116

117117
// Following syscalls are only available on some Windows PCs.
118118
// We will load syscalls, if available, before using them.
119-
_AddDllDirectory,
120119
_AddVectoredContinueHandler,
121-
_LoadLibraryExA,
122-
_LoadLibraryExW,
123120
_ stdFunction
124121

125122
// Use RtlGenRandom to generate cryptographically random data.
@@ -146,6 +143,15 @@ var (
146143
_ stdFunction
147144
)
148145

146+
var (
147+
advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0}
148+
kernel32dll = [...]uint16{'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0}
149+
ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
150+
powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
151+
winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
152+
ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0}
153+
)
154+
149155
// Function to be called by windows CreateThread
150156
// to start new os thread.
151157
func tstart_stdcall(newm *m)
@@ -225,46 +231,35 @@ const _MAX_PATH = 260 // https://docs.microsoft.com/en-us/windows/win32/fileio/m
225231
var sysDirectory [_MAX_PATH + 1]byte
226232
var sysDirectoryLen uintptr
227233

228-
func windowsLoadSystemLib(name []byte) uintptr {
229-
if sysDirectoryLen == 0 {
230-
l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
231-
if l == 0 || l > uintptr(len(sysDirectory)-1) {
232-
throw("Unable to determine system directory")
233-
}
234-
sysDirectory[l] = '\\'
235-
sysDirectoryLen = l + 1
236-
}
237-
if useLoadLibraryEx {
238-
return stdcall3(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
239-
} else {
240-
absName := append(sysDirectory[:sysDirectoryLen], name...)
241-
return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0])))
234+
func initSysDirectory() {
235+
l := stdcall2(_GetSystemDirectoryA, uintptr(unsafe.Pointer(&sysDirectory[0])), uintptr(len(sysDirectory)-1))
236+
if l == 0 || l > uintptr(len(sysDirectory)-1) {
237+
throw("Unable to determine system directory")
242238
}
239+
sysDirectory[l] = '\\'
240+
sysDirectoryLen = l + 1
241+
}
242+
243+
func windowsLoadSystemLib(name []uint16) uintptr {
244+
return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
243245
}
244246

245247
const haveCputicksAsm = GOARCH == "386" || GOARCH == "amd64"
246248

247249
func loadOptionalSyscalls() {
248-
var kernel32dll = []byte("kernel32.dll\000")
249-
k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
250+
k32 := windowsLoadSystemLib(kernel32dll[:])
250251
if k32 == 0 {
251252
throw("kernel32.dll not found")
252253
}
253-
_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
254254
_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
255-
_LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
256-
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
257-
useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
258255

259-
var advapi32dll = []byte("advapi32.dll\000")
260-
a32 := windowsLoadSystemLib(advapi32dll)
256+
a32 := windowsLoadSystemLib(advapi32dll[:])
261257
if a32 == 0 {
262258
throw("advapi32.dll not found")
263259
}
264260
_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
265261

266-
var ntdll = []byte("ntdll.dll\000")
267-
n32 := windowsLoadSystemLib(ntdll)
262+
n32 := windowsLoadSystemLib(ntdlldll[:])
268263
if n32 == 0 {
269264
throw("ntdll.dll not found")
270265
}
@@ -279,8 +274,7 @@ func loadOptionalSyscalls() {
279274
}
280275
}
281276

282-
var winmmdll = []byte("winmm.dll\000")
283-
m32 := windowsLoadSystemLib(winmmdll)
277+
m32 := windowsLoadSystemLib(winmmdll[:])
284278
if m32 == 0 {
285279
throw("winmm.dll not found")
286280
}
@@ -290,8 +284,7 @@ func loadOptionalSyscalls() {
290284
throw("timeBegin/EndPeriod not found")
291285
}
292286

293-
var ws232dll = []byte("ws2_32.dll\000")
294-
ws232 := windowsLoadSystemLib(ws232dll)
287+
ws232 := windowsLoadSystemLib(ws2_32dll[:])
295288
if ws232 == 0 {
296289
throw("ws2_32.dll not found")
297290
}
@@ -315,7 +308,7 @@ func monitorSuspendResume() {
315308
context uintptr
316309
}
317310

318-
powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
311+
powrprof := windowsLoadSystemLib(powrprofdll[:])
319312
if powrprof == 0 {
320313
return // Running on Windows 7, where we don't need it anyway.
321314
}
@@ -389,22 +382,6 @@ const (
389382
// in sys_windows_386.s and sys_windows_amd64.s:
390383
func getlasterror() uint32
391384

392-
// When loading DLLs, we prefer to use LoadLibraryEx with
393-
// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
394-
// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
395-
// flags are not available on some versions of Windows without a
396-
// security patch.
397-
//
398-
// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
399-
// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
400-
// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
401-
// systems that have KB2533623 installed. To determine whether the
402-
// flags are available, use GetProcAddress to get the address of the
403-
// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
404-
// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
405-
// flags can be used with LoadLibraryEx."
406-
var useLoadLibraryEx bool
407-
408385
var timeBeginPeriodRetValue uint32
409386

410387
// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
@@ -555,6 +532,7 @@ func osinit() {
555532
initHighResTimer()
556533
timeBeginPeriodRetValue = osRelax(false)
557534

535+
initSysDirectory()
558536
initLongPathSupport()
559537

560538
ncpu = getproccount()

src/runtime/syscall_windows.go

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -413,36 +413,23 @@ func callbackWrap(a *callbackArgs) {
413413

414414
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
415415

416-
// When available, this function will use LoadLibraryEx with the filename
417-
// parameter and the important SEARCH_SYSTEM32 argument. But on systems that
418-
// do not have that option, absoluteFilepath should contain a fallback
419-
// to the full path inside of system32 for use with vanilla LoadLibrary.
420-
//
421416
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
422417
//go:nosplit
423418
//go:cgo_unsafe_args
424-
func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
419+
func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
425420
lockOSThread()
426421
c := &getg().m.syscall
427-
428-
if useLoadLibraryEx {
429-
c.fn = getLoadLibraryEx()
430-
c.n = 3
431-
args := struct {
432-
lpFileName *uint16
433-
hFile uintptr // always 0
434-
flags uint32
435-
}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
436-
c.args = uintptr(noescape(unsafe.Pointer(&args)))
437-
} else {
438-
c.fn = getLoadLibrary()
439-
c.n = 1
440-
c.args = uintptr(noescape(unsafe.Pointer(&absoluteFilepath)))
441-
}
422+
c.fn = getLoadLibraryEx()
423+
c.n = 3
424+
args := struct {
425+
lpFileName *uint16
426+
hFile uintptr // always 0
427+
flags uint32
428+
}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
429+
c.args = uintptr(noescape(unsafe.Pointer(&args)))
442430

443431
cgocall(asmstdcallAddr, unsafe.Pointer(c))
444432
KeepAlive(filename)
445-
KeepAlive(absoluteFilepath)
446433
handle = c.r1
447434
if handle == 0 {
448435
err = c.err

src/runtime/syscall_windows_test.go

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,10 +1164,7 @@ uintptr_t cfunc(void) {
11641164
dll, err = syscall.LoadDLL(name)
11651165
if err == nil {
11661166
dll.Release()
1167-
if wantLoadLibraryEx() {
1168-
t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
1169-
}
1170-
t.Skip("insecure load of DLL, but expected")
1167+
t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
11711168
}
11721169
}
11731170

@@ -1213,24 +1210,6 @@ func TestBigStackCallbackSyscall(t *testing.T) {
12131210
}
12141211
}
12151212

1216-
// wantLoadLibraryEx reports whether we expect LoadLibraryEx to work for tests.
1217-
func wantLoadLibraryEx() bool {
1218-
return testenv.Builder() != "" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "386")
1219-
}
1220-
1221-
func TestLoadLibraryEx(t *testing.T) {
1222-
use, have, flags := runtime.LoadLibraryExStatus()
1223-
if use {
1224-
return // success.
1225-
}
1226-
if wantLoadLibraryEx() {
1227-
t.Fatalf("Expected LoadLibraryEx+flags to be available. (LoadLibraryEx=%v; flags=%v)",
1228-
have, flags)
1229-
}
1230-
t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)",
1231-
have, flags)
1232-
}
1233-
12341213
var (
12351214
modwinmm = syscall.NewLazyDLL("winmm.dll")
12361215
modkernel32 = syscall.NewLazyDLL("kernel32.dll")

src/syscall/dll_windows.go

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
4444

4545
func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
4646
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
47-
func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
47+
func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
4848
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
4949

5050
// A DLL implements access to a single DLL.
@@ -53,26 +53,6 @@ type DLL struct {
5353
Handle Handle
5454
}
5555

56-
// We use this for computing the absolute path for system DLLs on systems
57-
// where SEARCH_SYSTEM32 is not available.
58-
var systemDirectoryPrefix string
59-
60-
func init() {
61-
n := uint32(MAX_PATH)
62-
for {
63-
b := make([]uint16, n)
64-
l, e := getSystemDirectory(&b[0], n)
65-
if e != nil {
66-
panic("Unable to determine system directory: " + e.Error())
67-
}
68-
if l <= n {
69-
systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
70-
break
71-
}
72-
n = l
73-
}
74-
}
75-
7656
// LoadDLL loads the named DLL file into memory.
7757
//
7858
// 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) {
8969
var h uintptr
9070
var e Errno
9171
if sysdll.IsSystemDLL[name] {
92-
absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
93-
if err != nil {
94-
return nil, err
95-
}
96-
h, e = loadsystemlibrary(namep, absoluteFilepathp)
72+
h, e = loadsystemlibrary(namep)
9773
} else {
9874
h, e = loadlibrary(namep)
9975
}

src/syscall/security_windows.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,6 @@ type Tokenprimarygroup struct {
290290
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
291291
//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
292292
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
293-
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
294293

295294
// An access token contains the security information for a logon session.
296295
// The system creates an access token when a user logs on, and every

src/syscall/zsyscall_windows.go

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)