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>
This commit is contained in:
Jason A. Donenfeld 2019-03-06 19:26:29 +01:00 committed by Alex Brainman
parent 243c8eb8c2
commit 9b6e9f0c8c
5 changed files with 101 additions and 20 deletions

View file

@ -104,9 +104,13 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
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
@ -121,15 +125,9 @@ func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
}{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))