|
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 |