aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/os_windows.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-03-06 19:26:29 +0100
committerAlex Brainman <alex.brainman@gmail.com>2019-03-10 05:40:13 +0000
commit9b6e9f0c8c66355c0f0575d808b32f52c8c6d21c (patch)
tree4b143b84ee9ad075e6342094ee262e7dcc748a42 /src/runtime/os_windows.go
parent243c8eb8c290ebbf2e2811da2dd7538200dde6b3 (diff)
downloadgo-9b6e9f0c8c66355c0f0575d808b32f52c8c6d21c.tar.gz
go-9b6e9f0c8c66355c0f0575d808b32f52c8c6d21c.zip
runtime: safely load DLLs
While many other call sites have been moved to using the proper higher-level system loading, these areas were left out. This prevents DLL directory injection attacks. This includes both the runtime load calls (using LoadLibrary prior) and the implicitly linked ones via cgo_import_dynamic, which we move to our LoadLibraryEx. The goal is to only loosely load kernel32.dll and strictly load all others. Meanwhile we make sure that we never fallback to insecure loading on older or unpatched systems. This is CVE-2019-9634. Fixes #14959 Fixes #28978 Fixes #30642 Change-Id: I401a13ed8db248ab1bb5039bf2d31915cac72b93 Reviewed-on: https://go-review.googlesource.com/c/go/+/165798 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Diffstat (limited to 'src/runtime/os_windows.go')
-rw-r--r--src/runtime/os_windows.go64
1 files changed, 54 insertions, 10 deletions
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 2e1ec58a0d..d3e84fe3dc 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -29,6 +29,7 @@ const (
//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"
@@ -47,12 +48,9 @@ const (
//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
@@ -75,6 +73,7 @@ var (
_GetProcessAffinityMask,
_GetQueuedCompletionStatus,
_GetStdHandle,
+ _GetSystemDirectoryA,
_GetSystemInfo,
_GetSystemTimeAsFileTime,
_GetThreadContext,
@@ -96,12 +95,9 @@ var (
_VirtualAlloc,
_VirtualFree,
_VirtualQuery,
- _WSAGetOverlappedResult,
_WaitForSingleObject,
_WriteConsoleW,
_WriteFile,
- _timeBeginPeriod,
- _timeEndPeriod,
_ stdFunction
// Following syscalls are only available on some Windows PCs.
@@ -109,6 +105,7 @@ var (
_AddDllDirectory,
_AddVectoredContinueHandler,
_GetQueuedCompletionStatusEx,
+ _LoadLibraryExA,
_LoadLibraryExW,
_ stdFunction
@@ -126,6 +123,12 @@ var (
// 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
@@ -173,6 +176,26 @@ func windowsFindfunc(lib uintptr, name []byte) stdFunction {
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])))
@@ -182,17 +205,19 @@ func loadOptionalSyscalls() {
_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")
}
@@ -205,6 +230,27 @@ func loadOptionalSyscalls() {
}
}
+ 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
initWine(k32)
@@ -311,8 +357,6 @@ func osinit() {
loadOptionalSyscalls()
- useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
-
disableWER()
initExceptionHandler()