components/golang/patches/0076-runtime-syscall-only-search-for-Windows-DLLs-in-the-.patch
changeset 5781 ecbdf40c0a37
equal deleted inserted replaced
5780:42f59614ccbf 5781:ecbdf40c0a37
       
     1 From a241a38d20d96f65116aeabd7b9a28138a0b6860 Mon Sep 17 00:00:00 2001
       
     2 From: Brad Fitzpatrick <[email protected]>
       
     3 Date: Fri, 25 Mar 2016 06:40:58 +0000
       
     4 Subject: [PATCH 76/79] runtime, syscall: only search for Windows DLLs in the
       
     5  System32 directory
       
     6 
       
     7 Make sure that for any DLL that Go uses itself, we only look for the
       
     8 DLL in the Windows System32 directory, guarding against DLL preloading
       
     9 attacks.
       
    10 
       
    11 (Unless the Windows version is ancient and LoadLibraryEx is
       
    12 unavailable, in which case the user probably has bigger security
       
    13 problems anyway.)
       
    14 
       
    15 This does not change the behavior of syscall.LoadLibrary or NewLazyDLL
       
    16 if the DLL name is something unused by Go itself.
       
    17 
       
    18 This change also intentionally does not add any new API surface. Instead,
       
    19 x/sys is updated with a LoadLibraryEx function and LazyDLL.Flags in:
       
    20     https://golang.org/cl/21388
       
    21 
       
    22 Updates #14959
       
    23 
       
    24 Change-Id: I8d29200559cc19edf8dcf41dbdd39a389cd6aeb9
       
    25 Reviewed-on: https://go-review.googlesource.com/21140
       
    26 Reviewed-by: Russ Cox <[email protected]>
       
    27 Run-TryBot: Brad Fitzpatrick <[email protected]>
       
    28 TryBot-Result: Gobot Gobot <[email protected]>
       
    29 Reviewed-on: https://go-review.googlesource.com/21639
       
    30 Run-TryBot: Andrew Gerrand <[email protected]>
       
    31 Reviewed-by: Brad Fitzpatrick <[email protected]>
       
    32 ---
       
    33  src/cmd/dist/build.go                              |  1 +
       
    34  src/go/build/deps_test.go                          |  6 +-
       
    35  src/internal/syscall/windows/registry/syscall.go   |  2 +-
       
    36  .../syscall/windows/registry/zsyscall_windows.go   |  5 +-
       
    37  src/internal/syscall/windows/syscall_windows.go    |  2 +-
       
    38  src/internal/syscall/windows/sysdll/sysdll.go      | 28 +++++++
       
    39  src/internal/syscall/windows/zsyscall_windows.go   |  5 +-
       
    40  src/runtime/export_windows_test.go                 |  4 +
       
    41  src/runtime/os1_windows.go                         | 30 ++++++-
       
    42  src/runtime/syscall_windows.go                     | 35 ++++++++
       
    43  src/runtime/syscall_windows_test.go                | 93 ++++++++++++++++++++++
       
    44  src/syscall/dll_windows.go                         | 14 +++-
       
    45  src/syscall/mksyscall_windows.go                   | 48 +++++++++--
       
    46  src/syscall/syscall_windows.go                     |  2 +-
       
    47  src/syscall/zsyscall_windows.go                    | 27 ++++---
       
    48  15 files changed, 271 insertions(+), 31 deletions(-)
       
    49  create mode 100644 src/internal/syscall/windows/sysdll/sysdll.go
       
    50 
       
    51 diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
       
    52 index 1658e16..60162ff 100644
       
    53 --- a/src/cmd/dist/build.go
       
    54 +++ b/src/cmd/dist/build.go
       
    55 @@ -861,6 +861,7 @@ var buildorder = []string{
       
    56  	"sort",
       
    57  	"container/heap",
       
    58  	"encoding/base64",
       
    59 +	"internal/syscall/windows/sysdll",
       
    60  	"syscall",
       
    61  	"internal/syscall/windows/registry",
       
    62  	"time",
       
    63 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
       
    64 index 7cea949..464bc6a 100644
       
    65 --- a/src/go/build/deps_test.go
       
    66 +++ b/src/go/build/deps_test.go
       
    67 @@ -128,10 +128,10 @@ var pkgDeps = map[string][]string{
       
    68  	// End of linear dependency definitions.
       
    69  
       
    70  	// Operating system access.
       
    71 -	"syscall":                           {"L0", "unicode/utf16"},
       
    72 +	"syscall":                           {"L0", "internal/race", "internal/syscall/windows/sysdll", "unicode/utf16"},
       
    73  	"internal/syscall/unix":             {"L0", "syscall"},
       
    74 -	"internal/syscall/windows":          {"L0", "syscall"},
       
    75 -	"internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"},
       
    76 +	"internal/syscall/windows":          {"L0", "syscall", "internal/syscall/windows/sysdll"},
       
    77 +	"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
       
    78  	"time":          {"L0", "syscall", "internal/syscall/windows/registry"},
       
    79  	"os":            {"L1", "os", "syscall", "time", "internal/syscall/windows"},
       
    80  	"path/filepath": {"L2", "os", "syscall"},
       
    81 diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go
       
    82 index 38e573f..67394d8 100644
       
    83 --- a/src/internal/syscall/windows/registry/syscall.go
       
    84 +++ b/src/internal/syscall/windows/registry/syscall.go
       
    85 @@ -8,7 +8,7 @@ package registry
       
    86  
       
    87  import "syscall"
       
    88  
       
    89 -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
       
    90 +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall.go
       
    91  
       
    92  const (
       
    93  	_REG_OPTION_NON_VOLATILE = 0
       
    94 diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
       
    95 index 2b3de63..45a0ff7 100644
       
    96 --- a/src/internal/syscall/windows/registry/zsyscall_windows.go
       
    97 +++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
       
    98 @@ -4,12 +4,13 @@ package registry
       
    99  
       
   100  import "unsafe"
       
   101  import "syscall"
       
   102 +import "internal/syscall/windows/sysdll"
       
   103  
       
   104  var _ unsafe.Pointer
       
   105  
       
   106  var (
       
   107 -	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
       
   108 -	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
       
   109 +	modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
       
   110 +	modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
       
   111  
       
   112  	procRegCreateKeyExW           = modadvapi32.NewProc("RegCreateKeyExW")
       
   113  	procRegDeleteKeyW             = modadvapi32.NewProc("RegDeleteKeyW")
       
   114 diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
       
   115 index dc8a916..c1cd4b2 100644
       
   116 --- a/src/internal/syscall/windows/syscall_windows.go
       
   117 +++ b/src/internal/syscall/windows/syscall_windows.go
       
   118 @@ -6,7 +6,7 @@ package windows
       
   119  
       
   120  import "syscall"
       
   121  
       
   122 -//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
       
   123 +//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall_windows.go
       
   124  
       
   125  const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
       
   126  
       
   127 diff --git a/src/internal/syscall/windows/sysdll/sysdll.go b/src/internal/syscall/windows/sysdll/sysdll.go
       
   128 new file mode 100644
       
   129 index 0000000..4e0018f
       
   130 --- /dev/null
       
   131 +++ b/src/internal/syscall/windows/sysdll/sysdll.go
       
   132 @@ -0,0 +1,28 @@
       
   133 +// Copyright 2016 The Go Authors. All rights reserved.
       
   134 +// Use of this source code is governed by a BSD-style
       
   135 +// license that can be found in the LICENSE file.
       
   136 +
       
   137 +// Package sysdll is an internal leaf package that records and reports
       
   138 +// which Windows DLL names are used by Go itself. These DLLs are then
       
   139 +// only loaded from the System32 directory. See Issue 14959.
       
   140 +package sysdll
       
   141 +
       
   142 +// IsSystemDLL reports whether the named dll key (a base name, like
       
   143 +// "foo.dll") is a system DLL which should only be loaded from the
       
   144 +// Windows SYSTEM32 directory.
       
   145 +//
       
   146 +// Filenames are case sensitive, but that doesn't matter because
       
   147 +// the case registered with Add is also the same case used with
       
   148 +// LoadDLL later.
       
   149 +//
       
   150 +// It has no associated mutex and should only be mutated serially
       
   151 +// (currently: during init), and not concurrent with DLL loading.
       
   152 +var IsSystemDLL = map[string]bool{}
       
   153 +
       
   154 +// Add notes that dll is a system32 DLL which should only be loaded
       
   155 +// from the Windows SYSTEM32 directory. It returns its argument back,
       
   156 +// for ease of use in generated code.
       
   157 +func Add(dll string) string {
       
   158 +	IsSystemDLL[dll] = true
       
   159 +	return dll
       
   160 +}
       
   161 diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
       
   162 index c6f607a..f39ca0c 100644
       
   163 --- a/src/internal/syscall/windows/zsyscall_windows.go
       
   164 +++ b/src/internal/syscall/windows/zsyscall_windows.go
       
   165 @@ -4,12 +4,13 @@ package windows
       
   166  
       
   167  import "unsafe"
       
   168  import "syscall"
       
   169 +import "internal/syscall/windows/sysdll"
       
   170  
       
   171  var _ unsafe.Pointer
       
   172  
       
   173  var (
       
   174 -	modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
       
   175 -	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
       
   176 +	modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
       
   177 +	modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
       
   178  
       
   179  	procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
       
   180  	procGetComputerNameExW   = modkernel32.NewProc("GetComputerNameExW")
       
   181 diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go
       
   182 index 61fcef9..3d51fd2 100644
       
   183 --- a/src/runtime/export_windows_test.go
       
   184 +++ b/src/runtime/export_windows_test.go
       
   185 @@ -7,3 +7,7 @@
       
   186  package runtime
       
   187  
       
   188  var TestingWER = &testingWER
       
   189 +
       
   190 +func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) {
       
   191 +	return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
       
   192 +}
       
   193 diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
       
   194 index d012034..ab378b0 100644
       
   195 --- a/src/runtime/os1_windows.go
       
   196 +++ b/src/runtime/os1_windows.go
       
   197 @@ -88,8 +88,11 @@ var (
       
   198  
       
   199  	// Following syscalls are only available on some Windows PCs.
       
   200  	// We will load syscalls, if available, before using them.
       
   201 +	_AddDllDirectory,
       
   202  	_AddVectoredContinueHandler,
       
   203 -	_GetQueuedCompletionStatusEx stdFunction
       
   204 +	_GetQueuedCompletionStatusEx,
       
   205 +	_LoadLibraryExW,
       
   206 +	_ stdFunction
       
   207  )
       
   208  
       
   209  // Call a Windows function with stdcall conventions,
       
   210 @@ -110,8 +113,10 @@ func loadOptionalSyscalls() {
       
   211  		return stdFunction(unsafe.Pointer(f))
       
   212  	}
       
   213  	if l != 0 {
       
   214 +		_AddDllDirectory = findfunc("AddDllDirectory")
       
   215  		_AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler")
       
   216  		_GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx")
       
   217 +		_LoadLibraryExW = findfunc("LoadLibraryExW")
       
   218  	}
       
   219  }
       
   220  
       
   221 @@ -121,6 +126,11 @@ func getLoadLibrary() uintptr {
       
   222  }
       
   223  
       
   224  //go:nosplit
       
   225 +func getLoadLibraryEx() uintptr {
       
   226 +	return uintptr(unsafe.Pointer(_LoadLibraryExW))
       
   227 +}
       
   228 +
       
   229 +//go:nosplit
       
   230  func getGetProcAddress() uintptr {
       
   231  	return uintptr(unsafe.Pointer(_GetProcAddress))
       
   232  }
       
   233 @@ -139,6 +149,22 @@ const (
       
   234  // in sys_windows_386.s and sys_windows_amd64.s
       
   235  func externalthreadhandler()
       
   236  
       
   237 +// When loading DLLs, we prefer to use LoadLibraryEx with
       
   238 +// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
       
   239 +// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
       
   240 +// flags are not available on some versions of Windows without a
       
   241 +// security patch.
       
   242 +//
       
   243 +// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
       
   244 +// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
       
   245 +// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
       
   246 +// systems that have KB2533623 installed. To determine whether the
       
   247 +// flags are available, use GetProcAddress to get the address of the
       
   248 +// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
       
   249 +// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
       
   250 +// flags can be used with LoadLibraryEx."
       
   251 +var useLoadLibraryEx bool
       
   252 +
       
   253  func osinit() {
       
   254  	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
       
   255  
       
   256 @@ -146,6 +172,8 @@ func osinit() {
       
   257  
       
   258  	loadOptionalSyscalls()
       
   259  
       
   260 +	useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
       
   261 +
       
   262  	disableWER()
       
   263  
       
   264  	externalthreadhandlerp = funcPC(externalthreadhandler)
       
   265 diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
       
   266 index 8e069cd..4d8ee51 100644
       
   267 --- a/src/runtime/syscall_windows.go
       
   268 +++ b/src/runtime/syscall_windows.go
       
   269 @@ -88,6 +88,41 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
       
   270  	return callbackasmAddr(n)
       
   271  }
       
   272  
       
   273 +const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
       
   274 +
       
   275 +//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
       
   276 +//go:nosplit
       
   277 +func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
       
   278 +	c := &getg().m.syscall
       
   279 +
       
   280 +	if useLoadLibraryEx {
       
   281 +		c.fn = getLoadLibraryEx()
       
   282 +		c.n = 3
       
   283 +		args := struct {
       
   284 +			lpFileName *uint16
       
   285 +			hFile      uintptr // always 0
       
   286 +			flags      uint32
       
   287 +		}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
       
   288 +		c.args = uintptr(noescape(unsafe.Pointer(&args)))
       
   289 +	} else {
       
   290 +		// User is on Windows XP or something ancient.
       
   291 +		// The caller wanted to only load the filename DLL
       
   292 +		// from the System32 directory but that facility
       
   293 +		// doesn't exist, so just load it the normal way. This
       
   294 +		// is a potential security risk, but so is Windows XP.
       
   295 +		c.fn = getLoadLibrary()
       
   296 +		c.n = 1
       
   297 +		c.args = uintptr(noescape(unsafe.Pointer(&filename)))
       
   298 +	}
       
   299 +
       
   300 +	cgocall(asmstdcallAddr, unsafe.Pointer(c))
       
   301 +	handle = c.r1
       
   302 +	if handle == 0 {
       
   303 +		err = c.err
       
   304 +	}
       
   305 +	return
       
   306 +}
       
   307 +
       
   308  //go:linkname syscall_loadlibrary syscall.loadlibrary
       
   309  //go:nosplit
       
   310  func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
       
   311 diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
       
   312 index 677eb5f..ee449f9 100644
       
   313 --- a/src/runtime/syscall_windows_test.go
       
   314 +++ b/src/runtime/syscall_windows_test.go
       
   315 @@ -6,6 +6,8 @@ package runtime_test
       
   316  
       
   317  import (
       
   318  	"fmt"
       
   319 +	"internal/syscall/windows/sysdll"
       
   320 +	"internal/testenv"
       
   321  	"io/ioutil"
       
   322  	"os"
       
   323  	"os/exec"
       
   324 @@ -640,3 +642,94 @@ uintptr_t cfunc(callback f, uintptr_t n) {
       
   325  		t.Errorf("got %d want %d", got, want)
       
   326  	}
       
   327  }
       
   328 +
       
   329 +// See Issue 14959
       
   330 +func TestDLLPreloadMitigation(t *testing.T) {
       
   331 +	if _, err := exec.LookPath("gcc"); err != nil {
       
   332 +		t.Skip("skipping test: gcc is missing")
       
   333 +	}
       
   334 +
       
   335 +	dir0, err := os.Getwd()
       
   336 +	if err != nil {
       
   337 +		t.Fatal(err)
       
   338 +	}
       
   339 +	defer os.Chdir(dir0)
       
   340 +
       
   341 +	const src = `
       
   342 +#include <stdint.h>
       
   343 +#include <windows.h>
       
   344 +
       
   345 +uintptr_t cfunc() {
       
   346 +   SetLastError(123);
       
   347 +}
       
   348 +`
       
   349 +	tmpdir, err := ioutil.TempDir("", "TestDLLPreloadMitigation")
       
   350 +	if err != nil {
       
   351 +		t.Fatal("TempDir failed: ", err)
       
   352 +	}
       
   353 +	defer os.RemoveAll(tmpdir)
       
   354 +
       
   355 +	srcname := "nojack.c"
       
   356 +	err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
       
   357 +	if err != nil {
       
   358 +		t.Fatal(err)
       
   359 +	}
       
   360 +	name := "nojack.dll"
       
   361 +	cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", name, srcname)
       
   362 +	cmd.Dir = tmpdir
       
   363 +	out, err := cmd.CombinedOutput()
       
   364 +	if err != nil {
       
   365 +		t.Fatalf("failed to build dll: %v - %v", err, string(out))
       
   366 +	}
       
   367 +	dllpath := filepath.Join(tmpdir, name)
       
   368 +
       
   369 +	dll := syscall.MustLoadDLL(dllpath)
       
   370 +	dll.MustFindProc("cfunc")
       
   371 +	dll.Release()
       
   372 +
       
   373 +	// Get into the directory with the DLL we'll load by base name
       
   374 +	// ("nojack.dll") Think of this as the user double-clicking an
       
   375 +	// installer from their Downloads directory where a browser
       
   376 +	// silently downloaded some malicious DLLs.
       
   377 +	os.Chdir(tmpdir)
       
   378 +
       
   379 +	// First before we can load a DLL from the current directory,
       
   380 +	// loading it only as "nojack.dll", without an absolute path.
       
   381 +	delete(sysdll.IsSystemDLL, name) // in case test was run repeatedly
       
   382 +	dll, err = syscall.LoadDLL(name)
       
   383 +	if err != nil {
       
   384 +		t.Fatalf("failed to load %s by base name before sysdll registration: %v", name, err)
       
   385 +	}
       
   386 +	dll.Release()
       
   387 +
       
   388 +	// And now verify that if we register it as a system32-only
       
   389 +	// DLL, the implicit loading from the current directory no
       
   390 +	// longer works.
       
   391 +	sysdll.IsSystemDLL[name] = true
       
   392 +	dll, err = syscall.LoadDLL(name)
       
   393 +	if err == nil {
       
   394 +		dll.Release()
       
   395 +		if wantLoadLibraryEx() {
       
   396 +			t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
       
   397 +		}
       
   398 +		t.Skip("insecure load of DLL, but expected")
       
   399 +	}
       
   400 +}
       
   401 +
       
   402 +// wantLoadLibraryEx reports whether we expect LoadLibraryEx to work for tests.
       
   403 +func wantLoadLibraryEx() bool {
       
   404 +	return testenv.Builder() == "windows-amd64-gce" || testenv.Builder() == "windows-386-gce"
       
   405 +}
       
   406 +
       
   407 +func TestLoadLibraryEx(t *testing.T) {
       
   408 +	use, have, flags := runtime.LoadLibraryExStatus()
       
   409 +	if use {
       
   410 +		return // success.
       
   411 +	}
       
   412 +	if wantLoadLibraryEx() {
       
   413 +		t.Fatalf("Expected LoadLibraryEx+flags to be available. (LoadLibraryEx=%v; flags=%v)",
       
   414 +			have, flags)
       
   415 +	}
       
   416 +	t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)",
       
   417 +		have, flags)
       
   418 +}
       
   419 diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
       
   420 index c157e6d..ec8d85b 100644
       
   421 --- a/src/syscall/dll_windows.go
       
   422 +++ b/src/syscall/dll_windows.go
       
   423 @@ -5,6 +5,7 @@
       
   424  package syscall
       
   425  
       
   426  import (
       
   427 +	"internal/syscall/windows/sysdll"
       
   428  	"sync"
       
   429  	"sync/atomic"
       
   430  	"unsafe"
       
   431 @@ -26,6 +27,7 @@ func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 u
       
   432  func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
       
   433  func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
       
   434  func loadlibrary(filename *uint16) (handle uintptr, err Errno)
       
   435 +func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
       
   436  func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
       
   437  
       
   438  // A DLL implements access to a single DLL.
       
   439 @@ -34,13 +36,19 @@ type DLL struct {
       
   440  	Handle Handle
       
   441  }
       
   442  
       
   443 -// LoadDLL loads DLL file into memory.
       
   444 -func LoadDLL(name string) (dll *DLL, err error) {
       
   445 +// LoadDLL loads the named DLL file into memory.
       
   446 +func LoadDLL(name string) (*DLL, error) {
       
   447  	namep, err := UTF16PtrFromString(name)
       
   448  	if err != nil {
       
   449  		return nil, err
       
   450  	}
       
   451 -	h, e := loadlibrary(namep)
       
   452 +	var h uintptr
       
   453 +	var e Errno
       
   454 +	if sysdll.IsSystemDLL[name] {
       
   455 +		h, e = loadsystemlibrary(namep)
       
   456 +	} else {
       
   457 +		h, e = loadlibrary(namep)
       
   458 +	}
       
   459  	if e != 0 {
       
   460  		return nil, &DLLError{
       
   461  			Err:     e,
       
   462 diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
       
   463 index 622272a..546cb0d 100644
       
   464 --- a/src/syscall/mksyscall_windows.go
       
   465 +++ b/src/syscall/mksyscall_windows.go
       
   466 @@ -57,6 +57,7 @@ import (
       
   467  	"io/ioutil"
       
   468  	"log"
       
   469  	"os"
       
   470 +	"sort"
       
   471  	"strconv"
       
   472  	"strings"
       
   473  	"text/template"
       
   474 @@ -65,6 +66,8 @@ import (
       
   475  var (
       
   476  	filename       = flag.String("output", "", "output file name (standard output if omitted)")
       
   477  	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
       
   478 +	systemDLL      = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory")
       
   479 +	sysRepo        = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo")
       
   480  )
       
   481  
       
   482  func trim(s string) string {
       
   483 @@ -593,8 +596,14 @@ func (f *Fn) HelperName() string {
       
   484  
       
   485  // Source files and functions.
       
   486  type Source struct {
       
   487 -	Funcs []*Fn
       
   488 -	Files []string
       
   489 +	Funcs   []*Fn
       
   490 +	Files   []string
       
   491 +	Imports []string
       
   492 +}
       
   493 +
       
   494 +func (src *Source) Import(pkg string) {
       
   495 +	src.Imports = append(src.Imports, pkg)
       
   496 +	sort.Strings(src.Imports)
       
   497  }
       
   498  
       
   499  // ParseFiles parses files listed in fs and extracts all syscall
       
   500 @@ -604,6 +613,12 @@ func ParseFiles(fs []string) (*Source, error) {
       
   501  	src := &Source{
       
   502  		Funcs: make([]*Fn, 0),
       
   503  		Files: make([]string, 0),
       
   504 +		Imports: []string{
       
   505 +			"unsafe",
       
   506 +		},
       
   507 +	}
       
   508 +	if *systemDLL {
       
   509 +		src.Import("internal/syscall/windows/sysdll")
       
   510  	}
       
   511  	for _, file := range fs {
       
   512  		if err := src.ParseFile(file); err != nil {
       
   513 @@ -676,9 +691,30 @@ func (src *Source) ParseFile(path string) error {
       
   514  
       
   515  // Generate output source file from a source set src.
       
   516  func (src *Source) Generate(w io.Writer) error {
       
   517 +	if *sysRepo && packageName != "windows" {
       
   518 +		src.Import("golang.org/x/sys/windows")
       
   519 +	}
       
   520 +	if packageName != "syscall" {
       
   521 +		src.Import("syscall")
       
   522 +	}
       
   523  	funcMap := template.FuncMap{
       
   524  		"packagename": packagename,
       
   525  		"syscalldot":  syscalldot,
       
   526 +		"newlazydll": func(dll string) string {
       
   527 +			arg := "\"" + dll + ".dll\""
       
   528 +			if *systemDLL {
       
   529 +				arg = "sysdll.Add(" + arg + ")"
       
   530 +			}
       
   531 +			if *sysRepo {
       
   532 +				if packageName == "windows" {
       
   533 +					return "&LazyDLL{Name: " + arg + ", Flags: LoadLibrarySearchSystem32}"
       
   534 +				} else {
       
   535 +					return "&windows.LazyDLL{Name: " + arg + ", Flags: windows.LoadLibrarySearchSystem32}"
       
   536 +				}
       
   537 +			} else {
       
   538 +				return syscalldot() + "NewLazyDLL(" + arg + ")"
       
   539 +			}
       
   540 +		},
       
   541  	}
       
   542  	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
       
   543  	err := t.Execute(w, src)
       
   544 @@ -733,8 +769,10 @@ const srcTemplate = `
       
   545  
       
   546  package {{packagename}}
       
   547  
       
   548 -import "unsafe"{{if syscalldot}}
       
   549 -import "syscall"{{end}}
       
   550 +import (
       
   551 +{{range .Imports}}"{{.}}"
       
   552 +{{end}}
       
   553 +)
       
   554  
       
   555  var _ unsafe.Pointer
       
   556  
       
   557 @@ -746,7 +784,7 @@ var (
       
   558  
       
   559  {{/* help functions */}}
       
   560  
       
   561 -{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
       
   562 +{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{newlazydll .}}
       
   563  {{end}}{{end}}
       
   564  
       
   565  {{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
       
   566 diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
       
   567 index 1006a9b..049dc82 100644
       
   568 --- a/src/syscall/syscall_windows.go
       
   569 +++ b/src/syscall/syscall_windows.go
       
   570 @@ -13,7 +13,7 @@ import (
       
   571  	"unsafe"
       
   572  )
       
   573  
       
   574 -//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
       
   575 +//go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
       
   576  
       
   577  type Handle uintptr
       
   578  
       
   579 diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
       
   580 index 7879ba1..bb3e892 100644
       
   581 --- a/src/syscall/zsyscall_windows.go
       
   582 +++ b/src/syscall/zsyscall_windows.go
       
   583 @@ -2,22 +2,25 @@
       
   584  
       
   585  package syscall
       
   586  
       
   587 -import "unsafe"
       
   588 +import (
       
   589 +	"internal/syscall/windows/sysdll"
       
   590 +	"unsafe"
       
   591 +)
       
   592  
       
   593  var _ unsafe.Pointer
       
   594  
       
   595  var (
       
   596 -	modkernel32 = NewLazyDLL("kernel32.dll")
       
   597 -	modadvapi32 = NewLazyDLL("advapi32.dll")
       
   598 -	modshell32  = NewLazyDLL("shell32.dll")
       
   599 -	modmswsock  = NewLazyDLL("mswsock.dll")
       
   600 -	modcrypt32  = NewLazyDLL("crypt32.dll")
       
   601 -	modws2_32   = NewLazyDLL("ws2_32.dll")
       
   602 -	moddnsapi   = NewLazyDLL("dnsapi.dll")
       
   603 -	modiphlpapi = NewLazyDLL("iphlpapi.dll")
       
   604 -	modsecur32  = NewLazyDLL("secur32.dll")
       
   605 -	modnetapi32 = NewLazyDLL("netapi32.dll")
       
   606 -	moduserenv  = NewLazyDLL("userenv.dll")
       
   607 +	modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
       
   608 +	modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll"))
       
   609 +	modshell32  = NewLazyDLL(sysdll.Add("shell32.dll"))
       
   610 +	modmswsock  = NewLazyDLL(sysdll.Add("mswsock.dll"))
       
   611 +	modcrypt32  = NewLazyDLL(sysdll.Add("crypt32.dll"))
       
   612 +	modws2_32   = NewLazyDLL(sysdll.Add("ws2_32.dll"))
       
   613 +	moddnsapi   = NewLazyDLL(sysdll.Add("dnsapi.dll"))
       
   614 +	modiphlpapi = NewLazyDLL(sysdll.Add("iphlpapi.dll"))
       
   615 +	modsecur32  = NewLazyDLL(sysdll.Add("secur32.dll"))
       
   616 +	modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll"))
       
   617 +	moduserenv  = NewLazyDLL(sysdll.Add("userenv.dll"))
       
   618  
       
   619  	procGetLastError                       = modkernel32.NewProc("GetLastError")
       
   620  	procLoadLibraryW                       = modkernel32.NewProc("LoadLibraryW")
       
   621 -- 
       
   622 2.7.4
       
   623