commit dab074c44e8fd8effae4ef8561627bde4a7bfe14
Author: ANightly <anightlya@hotmail.com>
Date:   Sat Mar 1 00:20:50 2025 +0200

    Windows 7 for Go 1.24.0

diff --git a/src/crypto/internal/sysrand/rand_windows.go b/src/crypto/internal/sysrand/rand_windows.go
index 91f1490c15..e022d19b77 100644
--- a/src/crypto/internal/sysrand/rand_windows.go
+++ b/src/crypto/internal/sysrand/rand_windows.go
@@ -4,8 +4,26 @@
 
 package sysrand
 
-import "internal/syscall/windows"
+import (
+	"internal/syscall/windows"
+)
+
+func batched(f func([]byte) error, readMax int) func([]byte) error {
+	return func(out []byte) error {
+		for len(out) > 0 {
+			read := len(out)
+			if read > readMax {
+				read = readMax
+			}
+			if err := f(out[:read]); err != nil {
+				return err
+			}
+			out = out[read:]
+		}
+		return nil
+	}
+}
 
 func read(b []byte) error {
-	return windows.ProcessPrng(b)
+	return batched(windows.RtlGenRandom, 1<<31-1)(b)
 }
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index 1ca16caa95..7d5cea8134 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -22,7 +22,7 @@ import (
 //   - On legacy Linux (< 3.17), Reader opens /dev/urandom on first use.
 //   - On macOS, iOS, and OpenBSD Reader, uses arc4random_buf(3).
 //   - On NetBSD, Reader uses the kern.arandom sysctl.
-//   - On Windows, Reader uses the ProcessPrng API.
+//   - On Windows, Reader uses the RtlGenRandom API.
 //   - On js/wasm, Reader uses the Web Crypto API.
 //   - On wasip1/wasm, Reader uses random_get.
 //
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index c848f92d1f..715d07249c 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -416,7 +416,7 @@ func ErrorLoadingGetTempPath2() error {
 //sys	DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
 //sys	CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW
 
-//sys	ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng
+//sys	RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036
 
 type FILE_ID_BOTH_DIR_INFO struct {
 	NextEntryOffset uint32
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index 6a6ea7bdc0..5d335f38c4 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -37,15 +37,14 @@ func errnoErr(e syscall.Errno) error {
 }
 
 var (
-	modadvapi32         = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
-	modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll"))
-	modiphlpapi         = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
-	modkernel32         = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
-	modnetapi32         = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
-	modntdll            = syscall.NewLazyDLL(sysdll.Add("ntdll.dll"))
-	modpsapi            = syscall.NewLazyDLL(sysdll.Add("psapi.dll"))
-	moduserenv          = syscall.NewLazyDLL(sysdll.Add("userenv.dll"))
-	modws2_32           = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll"))
+	modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
+	modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
+	modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
+	modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
+	modntdll    = syscall.NewLazyDLL(sysdll.Add("ntdll.dll"))
+	modpsapi    = syscall.NewLazyDLL(sysdll.Add("psapi.dll"))
+	moduserenv  = syscall.NewLazyDLL(sysdll.Add("userenv.dll"))
+	modws2_32   = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll"))
 
 	procAdjustTokenPrivileges             = modadvapi32.NewProc("AdjustTokenPrivileges")
 	procDuplicateTokenEx                  = modadvapi32.NewProc("DuplicateTokenEx")
@@ -63,7 +62,7 @@ var (
 	procQueryServiceStatus                = modadvapi32.NewProc("QueryServiceStatus")
 	procRevertToSelf                      = modadvapi32.NewProc("RevertToSelf")
 	procSetTokenInformation               = modadvapi32.NewProc("SetTokenInformation")
-	procProcessPrng                       = modbcryptprimitives.NewProc("ProcessPrng")
+	procSystemFunction036            	  = modadvapi32.NewProc("SystemFunction036")
 	procGetAdaptersAddresses              = modiphlpapi.NewProc("GetAdaptersAddresses")
 	procCreateEventW                      = modkernel32.NewProc("CreateEventW")
 	procGetACP                            = modkernel32.NewProc("GetACP")
@@ -236,12 +235,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32
 	return
 }
 
-func ProcessPrng(buf []byte) (err error) {
+func RtlGenRandom(buf []byte) (err error) {
 	var _p0 *byte
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0)
+	r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0)
 	if r1 == 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
index f7c5b5af90..6b82be526e 100644
--- a/src/net/hook_windows.go
+++ b/src/net/hook_windows.go
@@ -13,6 +13,7 @@ var (
 	hostsFilePath = windows.GetSystemDirectory() + "/Drivers/etc/hosts"
 
 	// Placeholders for socket system calls.
+	socketFunc    func(int, int, int) (syscall.Handle, error)                                                 = syscall.Socket
 	wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket
 	connectFunc   func(syscall.Handle, syscall.Sockaddr) error                                                = syscall.Connect
 	listenFunc    func(syscall.Handle, int) error                                                             = syscall.Listen
diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go
index 967ce6795a..0197feb3f1 100644
--- a/src/net/internal/socktest/main_test.go
+++ b/src/net/internal/socktest/main_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !js && !plan9 && !wasip1 && !windows
+//go:build !js && !plan9 && !wasip1
 
 package socktest_test
 
diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go
new file mode 100644
index 0000000000..bd9006da2b
--- /dev/null
+++ b/src/net/internal/socktest/main_windows_test.go
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+package socktest_test
+
+import "syscall"
+
+var (
+	socketFunc func(int, int, int) (syscall.Handle, error)
+	closeFunc  func(syscall.Handle) error
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Closesocket
+}
+
+func uninstallTestHooks() {
+	socketFunc = syscall.Socket
+	closeFunc = syscall.Closesocket
+}
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
index 2f02446075..d5f0efda8b 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -9,6 +9,32 @@ import (
 	"syscall"
 )
 
+// Socket wraps syscall.Socket.
+func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) {
+	sw.once.Do(sw.init)
+	so := &Status{Cookie: cookie(family, sotype, proto)}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterSocket]
+	sw.fmu.RUnlock()
+	af, err := f.apply(so)
+	if err != nil {
+		return syscall.InvalidHandle, err
+	}
+	s, so.Err = syscall.Socket(family, sotype, proto)
+	if err = af.apply(so); err != nil {
+		if so.Err == nil {
+			syscall.Closesocket(s)
+		}
+		return syscall.InvalidHandle, err
+	}
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		return syscall.InvalidHandle, so.Err
+	}
+	return s, nil
+}
+
 // WSASocket wraps [syscall.WSASocket].
 func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) {
 	sw.once.Do(sw.init)
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
index bc024c0bbd..ef5359ad03 100644
--- a/src/net/main_windows_test.go
+++ b/src/net/main_windows_test.go
@@ -8,6 +8,7 @@ import "internal/poll"
 
 var (
 	// Placeholders for saving original socket system calls.
+	origSocket      = socketFunc
 	origWSASocket   = wsaSocketFunc
 	origClosesocket = poll.CloseFunc
 	origConnect     = connectFunc
@@ -17,6 +18,7 @@ var (
 )
 
 func installTestHooks() {
+	socketFunc = sw.Socket
 	wsaSocketFunc = sw.WSASocket
 	poll.CloseFunc = sw.Closesocket
 	connectFunc = sw.Connect
diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go
index a519909bb0..c05f173236 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -20,6 +20,20 @@ func maxListenerBacklog() int {
 func sysSocket(family, sotype, proto int) (syscall.Handle, error) {
 	s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto),
 		nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT)
+	if err == nil {
+		return s, nil
+	}
+	
+	// WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some
+	// old versions of Windows, see
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
+	// for details. Just use syscall.Socket, if windows.WSASocket failed.
+	// See ../syscall/exec_unix.go for description of ForkLock.
+	
+	s, err = socketFunc(family, sotype, proto)
+	if err == nil {
+		syscall.CloseOnExec(s)
+	}
 	if err != nil {
 		return syscall.InvalidHandle, os.NewSyscallError("socket", err)
 	}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 7183e79f7d..b5c2f67043 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -128,8 +128,15 @@ var (
 	_WriteFile,
 	_ stdFunction
 
-	// Use ProcessPrng to generate cryptographically random data.
-	_ProcessPrng stdFunction
+	// Use RtlGenRandom to generate cryptographically random data.
+	// This approach has been recommended by Microsoft (see issue
+	// 15589 for details).
+	// The RtlGenRandom is not listed in advapi32.dll, instead
+	// RtlGenRandom function can be found by searching for SystemFunction036.
+	// Also some versions of Mingw cannot link to SystemFunction036
+	// when building executable as Cgo. So load SystemFunction036
+	// manually during runtime startup.
+	_RtlGenRandom stdFunction
 
 	// Load ntdll.dll manually during startup, otherwise Mingw
 	// links wrong printf function to cgo executable (see issue
@@ -147,10 +154,10 @@ var (
 )
 
 var (
-	bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0}
-	ntdlldll            = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
-	powrprofdll         = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
-	winmmdll            = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
+	advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0}
+	ntdlldll    = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
+	powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
+	winmmdll    = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
 )
 
 // Function to be called by windows CreateThread
@@ -264,11 +271,11 @@ func windows_QueryPerformanceFrequency() int64 {
 }
 
 func loadOptionalSyscalls() {
-	bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:])
-	if bcryptPrimitives == 0 {
-		throw("bcryptprimitives.dll not found")
-	}
-	_ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000"))
+ 	a32 := windowsLoadSystemLib(advapi32dll[:])
+ 	if a32 == 0 {
+ 		throw("advapi32.dll not found")
+ 	}
+	_RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
 
 	n32 := windowsLoadSystemLib(ntdlldll[:])
 	if n32 == 0 {
@@ -501,7 +508,7 @@ func osinit() {
 //go:nosplit
 func readRandom(r []byte) int {
 	n := 0
-	if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
+	if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
 		n = len(r)
 	}
 	return n
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index 1220de4cdf..2c78dc4d76 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -316,7 +316,18 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
 			return 0, 0, err
 		}
 	}
-
+	
+	var info OsVersionInfoW
+	rtlGetVersion(&info)
+	isWin7 := info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1)
+	// NT kernel handles are divisible by 4, with the bottom 3 bits left as
+	// a tag. The fully set tag correlates with the types of handles we're
+	// concerned about here.  Except, the kernel will interpret some
+	// special handle values, like -1, -2, and so forth, so kernelbase.dll
+	// checks to see that those bottom three bits are checked, but that top
+	// bit is not checked.
+	isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 }
+	
 	p, _ := GetCurrentProcess()
 	parentProcess := p
 	if sys.ParentProcess != 0 {
@@ -325,7 +336,15 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
 	fd := make([]Handle, len(attr.Files))
 	for i := range attr.Files {
 		if attr.Files[i] > 0 {
-			err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
+			destinationProcessHandle := parentProcess
+
+			// On Windows 7, console handles aren't real handles, and can only be duplicated
+			// into the current process, not a parent one, which amounts to the same thing.
+			if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) {
+				destinationProcessHandle = p
+			}
+
+			err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
 			if err != nil {
 				return 0, 0, err
 			}
@@ -355,6 +374,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
 	si.StdErr = fd[2]
 
 	fd = append(fd, sys.AdditionalInheritedHandles...)
+	
+	// On Windows 7, console handles aren't real handles, so don't pass them
+	// through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+	for i := range fd {
+		if isLegacyWin7ConsoleHandle(fd[i]) {
+			fd[i] = 0
+		}
+	}
 
 	// The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST
 	// to treat the entire list as empty, so remove NULL handles.
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 05c29c7b20..a6d51f7703 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -233,6 +233,7 @@ func NewCallbackCDecl(fn any) uintptr {
 //sys	FreeLibrary(handle Handle) (err error)
 //sys	GetProcAddress(module Handle, procname string) (proc uintptr, err error)
 //sys	GetVersion() (ver uint32, err error)
+//sys	rtlGetVersion(info *OsVersionInfoW) = ntdll.RtlGetVersion
 //sys	formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
 //sys	ExitProcess(exitcode uint32)
 //sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go
index fa34053178..8952890d3d 100644
--- a/src/syscall/types_windows.go
+++ b/src/syscall/types_windows.go
@@ -334,6 +334,16 @@ type SecurityAttributes struct {
 	InheritHandle      uint32
 }
 
+// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow
+type OsVersionInfoW struct {
+	osVersionInfoSize uint32
+	majorVersion      uint32
+	minorVersion      uint32
+	buildNumber       uint32
+	platformId        uint32
+	csdVersion        [128]uint16
+}
+
 type Overlapped struct {
 	Internal     uintptr
 	InternalHigh uintptr
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index c0585a6df2..0a96c1fd59 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -43,6 +43,7 @@ var (
 	modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
 	modmswsock  = NewLazyDLL(sysdll.Add("mswsock.dll"))
 	modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll"))
+	modntdll    = NewLazyDLL(sysdll.Add("ntdll.dll"))
 	modsecur32  = NewLazyDLL(sysdll.Add("secur32.dll"))
 	modshell32  = NewLazyDLL(sysdll.Add("shell32.dll"))
 	moduserenv  = NewLazyDLL(sysdll.Add("userenv.dll"))
@@ -168,6 +169,7 @@ var (
 	procNetApiBufferFree                   = modnetapi32.NewProc("NetApiBufferFree")
 	procNetGetJoinInformation              = modnetapi32.NewProc("NetGetJoinInformation")
 	procNetUserGetInfo                     = modnetapi32.NewProc("NetUserGetInfo")
+	procRtlGetVersion		               = modntdll.NewProc("RtlGetVersion")
 	procGetUserNameExW                     = modsecur32.NewProc("GetUserNameExW")
 	procTranslateNameW                     = modsecur32.NewProc("TranslateNameW")
 	procCommandLineToArgvW                 = modshell32.NewProc("CommandLineToArgvW")
@@ -1219,6 +1221,11 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by
 	return
 }
 
+func rtlGetVersion(info *OsVersionInfoW) {
+	Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
+	return
+}
+
 func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
 	r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
 	if r1&0xff == 0 {
