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 15:50:05 +00:00
parent 15dcb6c006
commit 516e3c2063
4 changed files with 45 additions and 0 deletions
+14
View File
@@ -295,6 +295,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2 //sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid //sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
//sys coTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree //sys coTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
// syscall interface implementation for other packages // 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)) defer coTaskMemFree(unsafe.Pointer(p))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil 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
}
+7
View File
@@ -216,3 +216,10 @@ func TestKnownFolderPath(t *testing.T) {
t.Fatalf("Path = %q; want %q", got, want) 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)
}
}
+14
View File
@@ -1649,3 +1649,17 @@ const (
KF_FLAG_SIMPLE_IDLIST = 0x00000100 KF_FLAG_SIMPLE_IDLIST = 0x00000100
KF_FLAG_ALIAS_ONLY = 0x80000000 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
}
+10
View File
@@ -43,6 +43,7 @@ var (
modcrypt32 = NewLazySystemDLL("crypt32.dll") modcrypt32 = NewLazySystemDLL("crypt32.dll")
moduser32 = NewLazySystemDLL("user32.dll") moduser32 = NewLazySystemDLL("user32.dll")
modole32 = NewLazySystemDLL("ole32.dll") modole32 = NewLazySystemDLL("ole32.dll")
modntdll = NewLazySystemDLL("ntdll.dll")
modws2_32 = NewLazySystemDLL("ws2_32.dll") modws2_32 = NewLazySystemDLL("ws2_32.dll")
moddnsapi = NewLazySystemDLL("dnsapi.dll") moddnsapi = NewLazySystemDLL("dnsapi.dll")
modiphlpapi = NewLazySystemDLL("iphlpapi.dll") modiphlpapi = NewLazySystemDLL("iphlpapi.dll")
@@ -232,6 +233,7 @@ var (
procStringFromGUID2 = modole32.NewProc("StringFromGUID2") procStringFromGUID2 = modole32.NewProc("StringFromGUID2")
procCoCreateGuid = modole32.NewProc("CoCreateGuid") procCoCreateGuid = modole32.NewProc("CoCreateGuid")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
procWSAStartup = modws2_32.NewProc("WSAStartup") procWSAStartup = modws2_32.NewProc("WSAStartup")
procWSACleanup = modws2_32.NewProc("WSACleanup") procWSACleanup = modws2_32.NewProc("WSACleanup")
procWSAIoctl = modws2_32.NewProc("WSAIoctl") procWSAIoctl = modws2_32.NewProc("WSAIoctl")
@@ -2520,6 +2522,14 @@ func coTaskMemFree(address unsafe.Pointer) {
return 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) { func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
if r0 != 0 { if r0 != 0 {