windows: allow determining real version number

Other functions, like GetVersion(), will lie about the OS version
depending on various win32 and manifest compatibility shims in place.
Calling RtlGetVersion is the proper way to retrieve the true OS version.

Change-Id: I2bd6d097dd763df51617cd825dc0ad300abf6212
Reviewed-on: https://go-review.googlesource.com/c/sys/+/182718
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matt Layher <mdlayher@gmail.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld
2019-06-18 12:54:32 +02:00
parent 15dcb6c006
commit 516e3c2063
4 changed files with 45 additions and 0 deletions

View File

@@ -295,6 +295,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
//sys coTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
// syscall interface implementation for other packages
@@ -1304,3 +1305,16 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e
defer coTaskMemFree(unsafe.Pointer(p))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
}
// RtlGetVersion returns the true version of the underlying operating system, ignoring
// any manifesting or compatibility layers on top of the win32 layer.
func RtlGetVersion() *OsVersionInfoEx {
info := &OsVersionInfoEx{}
info.osVersionInfoSize = uint32(unsafe.Sizeof(*info))
// According to documentation, this function always succeeds.
// The function doesn't even check the validity of the
// osVersionInfoSize member. Disassembling ntdll.dll indicates
// that the documentation is indeed correct about that.
_ = rtlGetVersion(info)
return info
}

View File

@@ -216,3 +216,10 @@ func TestKnownFolderPath(t *testing.T) {
t.Fatalf("Path = %q; want %q", got, want)
}
}
func TestRtlGetVersion(t *testing.T) {
version := windows.RtlGetVersion()
if version.MajorVersion < 6 {
t.Fatalf("MajorVersion = %d; want >= 6", version.MajorVersion)
}
}

View File

@@ -1649,3 +1649,17 @@ const (
KF_FLAG_SIMPLE_IDLIST = 0x00000100
KF_FLAG_ALIAS_ONLY = 0x80000000
)
type OsVersionInfoEx struct {
osVersionInfoSize uint32
MajorVersion uint32
MinorVersion uint32
BuildNumber uint32
PlatformId uint32
CsdVersion [128]uint16
ServicePackMajor uint16
ServicePackMinor uint16
SuiteMask uint16
ProductType byte
_ byte
}

View File

@@ -43,6 +43,7 @@ var (
modcrypt32 = NewLazySystemDLL("crypt32.dll")
moduser32 = NewLazySystemDLL("user32.dll")
modole32 = NewLazySystemDLL("ole32.dll")
modntdll = NewLazySystemDLL("ntdll.dll")
modws2_32 = NewLazySystemDLL("ws2_32.dll")
moddnsapi = NewLazySystemDLL("dnsapi.dll")
modiphlpapi = NewLazySystemDLL("iphlpapi.dll")
@@ -232,6 +233,7 @@ var (
procStringFromGUID2 = modole32.NewProc("StringFromGUID2")
procCoCreateGuid = modole32.NewProc("CoCreateGuid")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
procWSAStartup = modws2_32.NewProc("WSAStartup")
procWSACleanup = modws2_32.NewProc("WSACleanup")
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
@@ -2520,6 +2522,14 @@ func coTaskMemFree(address unsafe.Pointer) {
return
}
func rtlGetVersion(info *OsVersionInfoEx) (ret error) {
r0, _, _ := syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
if r0 != 0 {