aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2019-06-13 14:41:20 -0400
committerFilippo Valsorda <filippo@golang.org>2019-06-13 14:41:20 -0400
commit346babe6a67fbbd570a2ec234ebf279cfb1a0078 (patch)
treecca4f0157fd1269c42571eb3909df3257adf2c4f
parent7be8a5843a9bdb944774feab38883ea8ad0ad904 (diff)
parent541c49144d73f2a03374517091835fa8a43eebe2 (diff)
downloadgo-346babe6a67fbbd570a2ec234ebf279cfb1a0078.tar.gz
go-346babe6a67fbbd570a2ec234ebf279cfb1a0078.zip
[dev.boringcrypto.go1.11] all: merge go1.11.11 into dev.boringcrypto.go1.11
Change-Id: Ib34dd423b6d83a7e5d0c1f9d7be638aa892fa28c
-rw-r--r--doc/devel/release.html33
-rw-r--r--src/cmd/link/elf_test.go113
-rw-r--r--src/cmd/link/internal/loadelf/ldelf.go8
-rw-r--r--src/crypto/x509/root_cgo_darwin.go8
-rw-r--r--src/net/lookup_test.go25
-rw-r--r--src/runtime/asm_wasm.s2
-rw-r--r--src/runtime/os_windows.go64
-rw-r--r--src/runtime/syscall_windows.go14
-rw-r--r--src/syscall/dll_windows.go28
-rw-r--r--src/syscall/security_windows.go1
-rw-r--r--src/syscall/zsyscall_windows.go14
11 files changed, 271 insertions, 39 deletions
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 3b6a635a68..98e0513349 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -81,6 +81,39 @@ runtime, go command, and the <code>crypto/x509</code>, <code>encoding/json</code
1.11.6 milestone</a> on our issue tracker for details.
</p>
+<p>
+go1.11.7 (released 2019/04/05) includes fixes to the runtime and the
+<code>net</code> packages. See the
+<a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.7">Go
+1.11.7 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.11.8 (released 2019/04/08) was accidentally released without its
+intended fix. It is identical to go1.11.7, except for its version
+number. The intended fix is in go1.11.9.
+</p>
+
+<p>
+go1.11.9 (released 2019/04/11) fixes an issue where using the prebuilt binary
+releases on older versions of GNU/Linux
+<a href="https://golang.org/issues/31293">led to failures</a>
+when linking programs that used cgo.
+Only Linux users who hit this issue need to update.
+</p>
+
+<p>
+go1.11.10 (released 2019/05/06) includes fixes to the runtime and the linker.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.10">Go
+1.11.10 milestone</a> on our issue tracker for details.
+</p>
+
+<p>
+go1.11.11 (released 2019/06/11) includes a fix to the <code>crypto/x509</code> package.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.11.11">Go
+1.11.11 milestone</a> on our issue tracker for details.
+</p>
+
<h2 id="go1.10">go1.10 (released 2018/02/16)</h2>
<p>
diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go
new file mode 100644
index 0000000000..3df9869284
--- /dev/null
+++ b/src/cmd/link/elf_test.go
@@ -0,0 +1,113 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build dragonfly freebsd linux netbsd openbsd
+
+package main
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var asmSource = `
+ .section .text1,"ax"
+s1:
+ .byte 0
+ .section .text2,"ax"
+s2:
+ .byte 0
+`
+
+var goSource = `
+package main
+func main() {}
+`
+
+// The linker used to crash if an ELF input file had multiple text sections
+// with the same name.
+func TestSectionsWithSameName(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ testenv.MustHaveCGO(t)
+ t.Parallel()
+
+ objcopy, err := exec.LookPath("objcopy")
+ if err != nil {
+ t.Skipf("can't find objcopy: %v", err)
+ }
+
+ dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ gopath := filepath.Join(dir, "GOPATH")
+ env := append(os.Environ(), "GOPATH="+gopath)
+
+ if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
+ t.Fatal(err)
+ }
+
+ asmFile := filepath.Join(dir, "x.s")
+ if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
+ t.Fatal(err)
+ }
+
+ goTool := testenv.GoToolPath(t)
+ cmd := exec.Command(goTool, "env", "CC")
+ cmd.Env = env
+ ccb, err := cmd.Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cc := strings.TrimSpace(string(ccb))
+
+ cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
+ cmd.Env = env
+ cflagsb, err := cmd.Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cflags := strings.Fields(string(cflagsb))
+
+ asmObj := filepath.Join(dir, "x.o")
+ t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
+ if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ asm2Obj := filepath.Join(dir, "x2.syso")
+ t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
+ if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ for _, s := range []string{asmFile, asmObj} {
+ if err := os.Remove(s); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ goFile := filepath.Join(dir, "main.go")
+ if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(goTool, "build")
+ cmd.Dir = dir
+ cmd.Env = env
+ t.Logf("%s build", goTool)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+}
diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go
index 8e32e7dee6..57d000a8bc 100644
--- a/src/cmd/link/internal/loadelf/ldelf.go
+++ b/src/cmd/link/internal/loadelf/ldelf.go
@@ -678,6 +678,8 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
// as well use one large chunk.
// create symbols for elfmapped sections
+ sectsymNames := make(map[string]bool)
+ counter := 0
for i := 0; uint(i) < elfobj.nsect; i++ {
sect = &elfobj.sect[i]
if sect.type_ == SHT_ARM_ATTRIBUTES && sect.name == ".ARM.attributes" {
@@ -709,6 +711,12 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
}
name := fmt.Sprintf("%s(%s)", pkg, sect.name)
+ for sectsymNames[name] {
+ counter++
+ name = fmt.Sprintf("%s(%s%d)", pkg, sect.name, counter)
+ }
+ sectsymNames[name] = true
+
s := syms.Lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index e6332072d6..1c20f26acb 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.go
@@ -16,7 +16,7 @@ package x509
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
-static bool isSSLPolicy(SecPolicyRef policyRef) {
+static Boolean isSSLPolicy(SecPolicyRef policyRef) {
if (!policyRef) {
return false;
}
@@ -24,13 +24,13 @@ static bool isSSLPolicy(SecPolicyRef policyRef) {
if (properties == NULL) {
return false;
}
+ Boolean isSSL = false;
CFTypeRef value = NULL;
if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid, (const void **)&value)) {
- CFRelease(properties);
- return CFEqual(value, kSecPolicyAppleSSL);
+ isSSL = CFEqual(value, kSecPolicyAppleSSL);
}
CFRelease(properties);
- return false;
+ return isSSL;
}
// sslTrustSettingsResult obtains the final kSecTrustSettingsResult value
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index f2adbc18c5..a2e3318c8d 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -250,14 +250,11 @@ func TestLookupGmailTXT(t *testing.T) {
}
}
-var lookupGooglePublicDNSAddrTests = []struct {
- addr, name string
-}{
- {"8.8.8.8", ".google.com."},
- {"8.8.4.4", ".google.com."},
-
- {"2001:4860:4860::8888", ".google.com."},
- {"2001:4860:4860::8844", ".google.com."},
+var lookupGooglePublicDNSAddrTests = []string{
+ "8.8.8.8",
+ "8.8.4.4",
+ "2001:4860:4860::8888",
+ "2001:4860:4860::8844",
}
func TestLookupGooglePublicDNSAddr(t *testing.T) {
@@ -269,8 +266,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
defer dnsWaitGroup.Wait()
- for _, tt := range lookupGooglePublicDNSAddrTests {
- names, err := LookupAddr(tt.addr)
+ for _, ip := range lookupGooglePublicDNSAddrTests {
+ names, err := LookupAddr(ip)
if err != nil {
t.Fatal(err)
}
@@ -278,8 +275,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
t.Error("got no record")
}
for _, name := range names {
- if !strings.HasSuffix(name, tt.name) {
- t.Errorf("got %s; want a record containing %s", name, tt.name)
+ if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
+ t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
}
}
}
@@ -652,8 +649,8 @@ func testDots(t *testing.T, mode string) {
t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
} else {
for _, name := range names {
- if !strings.HasSuffix(name, ".google.com.") {
- t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
+ if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
+ t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
break
}
}
diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s
index baf840d0cf..cb08922043 100644
--- a/src/runtime/asm_wasm.s
+++ b/src/runtime/asm_wasm.s
@@ -446,7 +446,7 @@ TEXT runtime·gcWriteBarrier(SB), NOSPLIT, $16
// Record value
MOVD R1, 0(R5)
// Record *slot
- MOVD R0, 8(R5)
+ MOVD (R0), 8(R5)
// Increment wbBuf.next
Get R5
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 5607bf95c1..a3d0bcc596 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"
@@ -46,12 +47,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
@@ -74,6 +72,7 @@ var (
_GetProcessAffinityMask,
_GetQueuedCompletionStatus,
_GetStdHandle,
+ _GetSystemDirectoryA,
_GetSystemInfo,
_GetSystemTimeAsFileTime,
_GetThreadContext,
@@ -94,12 +93,9 @@ var (
_VirtualAlloc,
_VirtualFree,
_VirtualQuery,
- _WSAGetOverlappedResult,
_WaitForSingleObject,
_WriteConsoleW,
_WriteFile,
- _timeBeginPeriod,
- _timeEndPeriod,
_ stdFunction
// Following syscalls are only available on some Windows PCs.
@@ -107,6 +103,7 @@ var (
_AddDllDirectory,
_AddVectoredContinueHandler,
_GetQueuedCompletionStatusEx,
+ _LoadLibraryExA,
_LoadLibraryExW,
_ stdFunction
@@ -124,6 +121,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
@@ -171,6 +174,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])))
@@ -180,22 +203,45 @@ 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")
}
_NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
+ 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)
@@ -302,8 +348,6 @@ func osinit() {
loadOptionalSyscalls()
- useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
-
disableWER()
initExceptionHandler()
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 8264070569..ee931ceb0a 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -90,9 +90,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
@@ -107,15 +111,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))
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index 2ee85a0d77..577ca96b1c 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -27,7 +27,7 @@ func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 u
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
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)
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.
@@ -36,6 +36,26 @@ type DLL struct {
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
@@ -52,7 +72,11 @@ func LoadDLL(name string) (*DLL, error) {
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
index ae8b3a17bf..db80d98a08 100644
--- 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
index de2d4f3adb..2348f6534f 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -190,6 +190,7 @@ var (
procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
+ procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW")
)
func GetLastError() (lasterr error) {
@@ -1916,3 +1917,16 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
}
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 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}