Files
go-legacy-win7/patches/0003-Add-back-LoadLibraryA-fallback.patch

308 lines
12 KiB
Diff
Raw Normal View History

2025-02-14 12:42:07 +07:00
From b832732b5d8509512c5021b5f4b1cf3e2ec6ea2c Mon Sep 17 00:00:00 2001
2024-11-09 17:58:11 +11:00
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
2025-02-14 12:42:07 +07:00
Date: Fri, 14 Feb 2025 11:35:56 +0700
2024-11-09 17:58:11 +11:00
Subject: [PATCH] Add back LoadLibraryA fallback
---
src/runtime/export_windows_test.go | 4 ++
src/runtime/os_windows.go | 60 ++++++++++++++++++++++++++++-
src/runtime/syscall_windows.go | 17 +++++++-
src/runtime/syscall_windows_test.go | 23 ++++++++++-
2024-12-24 19:34:49 +07:00
src/syscall/dll_windows.go | 28 +++++++++++++-
2024-11-09 17:58:11 +11:00
src/syscall/security_windows.go | 1 +
src/syscall/zsyscall_windows.go | 10 +++++
2024-12-24 19:34:49 +07:00
7 files changed, 136 insertions(+), 7 deletions(-)
2024-11-09 17:58:11 +11:00
diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go
2025-02-14 12:42:07 +07:00
index 13d30d4..5ff5229 100644
2024-11-09 17:58:11 +11:00
--- a/src/runtime/export_windows_test.go
+++ b/src/runtime/export_windows_test.go
2025-02-14 12:42:07 +07:00
@@ -39,3 +39,7 @@ func NewContextStub() *ContextStub {
2024-11-09 17:58:11 +11:00
ctx.set_fp(getcallerfp())
return &ContextStub{ctx}
}
+
+func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) {
+ return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
+}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
2025-02-14 12:42:07 +07:00
index fd65e34..c85fab7 100644
2024-11-09 17:58:11 +11:00
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
2025-02-14 12:42:07 +07:00
@@ -42,6 +42,7 @@ const (
2024-11-09 17:58:11 +11:00
//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._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll"
2025-02-14 12:42:07 +07:00
@@ -75,6 +76,7 @@ var (
2024-11-09 17:58:11 +11:00
// Following syscalls are available on every Windows PC.
// All these variables are set by the Windows executable
// loader before the Go program starts.
+ _AddDllDirectory,
_AddVectoredContinueHandler,
_AddVectoredExceptionHandler,
_CloseHandle,
2025-02-14 12:42:07 +07:00
@@ -100,6 +102,7 @@ var (
2024-11-09 17:58:11 +11:00
_SetThreadContext,
_LoadLibraryExW,
_LoadLibraryW,
+ _LoadLibraryA,
_PostQueuedCompletionStatus,
_QueryPerformanceCounter,
_QueryPerformanceFrequency,
2025-02-14 12:42:07 +07:00
@@ -158,7 +161,6 @@ var (
2024-11-09 17:58:11 +11:00
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
2025-02-14 12:42:07 +07:00
@@ -254,7 +256,36 @@ func windows_GetSystemDirectory() string {
2024-11-09 17:58:11 +11:00
}
func windowsLoadSystemLib(name []uint16) uintptr {
- return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
+ if useLoadLibraryEx {
+ return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
+ } else {
+ var nameBytes [_MAX_PATH]byte
+ n := len(name)
+ if n > len(nameBytes) {
+ n = len(nameBytes)
+ }
+ for i := 0; i < n && name[i] != 0; i++ {
+ nameBytes[i] = byte(name[i])
+ }
+
+ // Construct the full path
+ var fullPath [_MAX_PATH]byte
+ copy(fullPath[:], sysDirectory[:sysDirectoryLen])
+ pathLen := sysDirectoryLen
+ for i := 0; i < len(nameBytes) && nameBytes[i] != 0 && pathLen < _MAX_PATH; i++ {
+ fullPath[pathLen] = nameBytes[i]
+ pathLen++
+ }
+
+ // Ensure null-termination
+ if pathLen < _MAX_PATH {
+ fullPath[pathLen] = 0
+ } else {
+ fullPath[_MAX_PATH-1] = 0
+ }
+
+ return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&fullPath[0])))
+ }
}
//go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter
2025-02-14 12:42:07 +07:00
@@ -272,6 +303,15 @@ func windows_QueryPerformanceFrequency() int64 {
2024-11-09 17:58:11 +11:00
}
func loadOptionalSyscalls() {
+ var kernel32dll = []byte("kernel32.dll\000")
+ k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
+ if k32 == 0 {
+ throw("kernel32.dll not found")
+ }
+ _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
+ _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
+ useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
+
a32 := windowsLoadSystemLib(advapi32dll[:])
if a32 == 0 {
throw("advapi32.dll not found")
2025-02-14 12:42:07 +07:00
@@ -366,6 +406,22 @@ const (
2024-11-09 17:58:11 +11:00
// 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
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
2024-12-24 19:24:09 +07:00
index 85b1b8c..eb808fe 100644
2024-11-09 17:58:11 +11:00
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -413,10 +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
-func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
- handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
+func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
+ if useLoadLibraryEx {
+ handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
+ } else {
+ handle, _, err = syscall_SyscallN(
+ uintptr(unsafe.Pointer(_LoadLibraryW)),
+ uintptr(unsafe.Pointer(absoluteFilepath)),
+ )
+ }
KeepAlive(filename)
+ KeepAlive(absoluteFilepath)
if handle != 0 {
err = 0
}
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
2025-02-14 12:42:07 +07:00
index 01a9ca3..53f7110 100644
2024-11-09 17:58:11 +11:00
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
2025-02-14 12:42:07 +07:00
@@ -1160,7 +1160,10 @@ uintptr_t cfunc(void) {
2024-11-09 17:58:11 +11:00
dll, err = syscall.LoadDLL(name)
if err == nil {
dll.Release()
- t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
+ 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")
}
}
2025-02-14 12:42:07 +07:00
@@ -1213,6 +1216,24 @@ func TestSyscallStackUsage(t *testing.T) {
2024-11-09 18:59:13 +11:00
syscall.Syscall18(procSetEvent.Addr(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2024-11-09 17:58:11 +11:00
}
+// 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")
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
2024-12-24 19:34:49 +07:00
index a7873e6..bd82b51 100644
2024-11-09 17:58:11 +11:00
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
2024-12-24 19:34:49 +07:00
@@ -45,7 +45,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
//go:noescape
2024-11-09 17:58:11 +11:00
func SyscallN(trap uintptr, args ...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.
2024-12-24 19:34:49 +07:00
@@ -54,6 +54,26 @@ type DLL struct {
2024-11-09 17:58:11 +11:00
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
2024-12-24 19:34:49 +07:00
@@ -70,7 +90,11 @@ func LoadDLL(name string) (*DLL, error) {
2024-11-09 17:58:11 +11:00
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
2024-12-24 19:24:09 +07:00
index 4e988c4..45b1908 100644
2024-11-09 17:58:11 +11:00
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -290,6 +290,7 @@ 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
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
2025-02-14 12:42:07 +07:00
index c0585a6..85c66de 100644
2024-11-09 17:58:11 +11:00
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -128,6 +128,7 @@ var (
procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW")
procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
procGetTempPathW = modkernel32.NewProc("GetTempPathW")
procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
2025-02-14 12:42:07 +07:00
@@ -871,6 +872,15 @@ func GetStdHandle(stdhandle int) (handle Handle, err error) {
2024-11-09 17:58:11 +11:00
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
--
2024-12-24 19:24:09 +07:00
2.39.5
2024-11-09 17:58:11 +11:00