From 81ca08f1b3ebd3d7b893e0bb39cd00e97827e1f7 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 3 May 2019 09:34:00 +0200 Subject: [PATCH] setupapi: safer aliasing of slice types --- tun/wintun/guid/guid_windows.go | 11 +++---- tun/wintun/guid/zguid_windows.go | 12 ++++++-- tun/wintun/setupapi/setupapi_windows.go | 30 +++++++++++++++----- tun/wintun/setupapi/setupapi_windows_test.go | 4 ++- tun/wintun/wintun_windows.go | 6 +--- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/tun/wintun/guid/guid_windows.go b/tun/wintun/guid/guid_windows.go index 0078d2c..c5f4be6 100644 --- a/tun/wintun/guid/guid_windows.go +++ b/tun/wintun/guid/guid_windows.go @@ -12,7 +12,7 @@ import ( "golang.org/x/sys/windows" ) -//sys clsidFromString(lpsz *uint16, pclsid *windows.GUID) (hr int32) = ole32.CLSIDFromString +//sys clsidFromString(lpsz *uint16, pclsid *windows.GUID) (err error) [failretval!=0] = ole32.CLSIDFromString // // FromString parses "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" string to GUID. @@ -22,14 +22,11 @@ func FromString(str string) (*windows.GUID, error) { if err != nil { return nil, err } - guid := &windows.GUID{} - - hr := clsidFromString(strUTF16, guid) - if hr < 0 { - return nil, syscall.Errno(hr) + err = clsidFromString(strUTF16, guid) + if err != nil { + return nil, err } - return guid, nil } diff --git a/tun/wintun/guid/zguid_windows.go b/tun/wintun/guid/zguid_windows.go index 5467849..b0b4cce 100644 --- a/tun/wintun/guid/zguid_windows.go +++ b/tun/wintun/guid/zguid_windows.go @@ -42,8 +42,14 @@ var ( procCLSIDFromString = modole32.NewProc("CLSIDFromString") ) -func clsidFromString(lpsz *uint16, pclsid *windows.GUID) (hr int32) { - r0, _, _ := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0) - hr = int32(r0) +func clsidFromString(lpsz *uint16, pclsid *windows.GUID) (err error) { + r1, _, e1 := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0) + if r1 != 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } return } diff --git a/tun/wintun/setupapi/setupapi_windows.go b/tun/wintun/setupapi/setupapi_windows.go index dec9da2..621d12b 100644 --- a/tun/wintun/setupapi/setupapi_windows.go +++ b/tun/wintun/setupapi/setupapi_windows.go @@ -8,6 +8,7 @@ package setupapi import ( "encoding/binary" "fmt" + "runtime" "syscall" "unsafe" @@ -261,9 +262,13 @@ func SetupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *Dev func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { switch dataType { case windows.REG_SZ: - return windows.UTF16ToString(BufToUTF16(buf)), nil + ret := windows.UTF16ToString(bufToUTF16(buf)) + runtime.KeepAlive(buf) + return ret, nil case windows.REG_EXPAND_SZ: - return registry.ExpandString(windows.UTF16ToString(BufToUTF16(buf))) + ret, err := registry.ExpandString(windows.UTF16ToString(bufToUTF16(buf))) + runtime.KeepAlive(buf) + return ret, err case windows.REG_BINARY: return buf, nil case windows.REG_DWORD_LITTLE_ENDIAN: @@ -271,7 +276,7 @@ func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { case windows.REG_DWORD_BIG_ENDIAN: return binary.BigEndian.Uint32(buf), nil case windows.REG_MULTI_SZ: - bufW := BufToUTF16(buf) + bufW := bufToUTF16(buf) a := []string{} for i := 0; i < len(bufW); { j := i + wcslen(bufW[i:]) @@ -280,6 +285,7 @@ func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { } i = j + 1 } + runtime.KeepAlive(buf) return a, nil case windows.REG_QWORD_LITTLE_ENDIAN: return binary.LittleEndian.Uint64(buf), nil @@ -288,8 +294,8 @@ func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { } } -// BufToUTF16 function reinterprets []byte buffer as []uint16 -func BufToUTF16(buf []byte) []uint16 { +// bufToUTF16 function reinterprets []byte buffer as []uint16 +func bufToUTF16(buf []byte) []uint16 { sl := struct { addr *uint16 len int @@ -298,8 +304,8 @@ func BufToUTF16(buf []byte) []uint16 { return *(*[]uint16)(unsafe.Pointer(&sl)) } -// UTF16ToBuf function reinterprets []uint16 as []byte -func UTF16ToBuf(buf []uint16) []byte { +// utf16ToBuf function reinterprets []uint16 as []byte +func utf16ToBuf(buf []uint16) []byte { sl := struct { addr *byte len int @@ -334,6 +340,16 @@ func (deviceInfoSet DevInfo) SetDeviceRegistryProperty(deviceInfoData *DevInfoDa return SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyBuffers) } +func (deviceInfoSet DevInfo) SetDeviceRegistryPropertyString(deviceInfoData *DevInfoData, property SPDRP, str string) error { + str16, err := windows.UTF16FromString(str) + if err != nil { + return err + } + err = SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, utf16ToBuf(append(str16, 0))) + runtime.KeepAlive(str16) + return err +} + //sys setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiGetDeviceInstallParamsW // SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element. diff --git a/tun/wintun/setupapi/setupapi_windows_test.go b/tun/wintun/setupapi/setupapi_windows_test.go index 73cad7c..d5443ff 100644 --- a/tun/wintun/setupapi/setupapi_windows_test.go +++ b/tun/wintun/setupapi/setupapi_windows_test.go @@ -6,6 +6,7 @@ package setupapi import ( + "runtime" "strings" "syscall" "testing" @@ -471,7 +472,7 @@ func TestSetupDiGetSelectedDevice(t *testing.T) { func TestUTF16ToBuf(t *testing.T) { buf := []uint16{0x0123, 0x4567, 0x89ab, 0xcdef} - buf2 := UTF16ToBuf(buf) + buf2 := utf16ToBuf(buf) if len(buf)*2 != len(buf2) || cap(buf)*2 != cap(buf2) || buf2[0] != 0x23 || buf2[1] != 0x01 || @@ -480,4 +481,5 @@ func TestUTF16ToBuf(t *testing.T) { buf2[6] != 0xef || buf2[7] != 0xcd { t.Errorf("SetupDiSetSelectedDevice(nil) should fail with ERROR_INVALID_USER_BUFFER") } + runtime.KeepAlive(buf) } diff --git a/tun/wintun/wintun_windows.go b/tun/wintun/wintun_windows.go index e1b46a8..69f6eb6 100644 --- a/tun/wintun/wintun_windows.go +++ b/tun/wintun/wintun_windows.go @@ -218,11 +218,7 @@ func CreateInterface(description string, hwndParent uintptr) (*Wintun, bool, err } // Set Plug&Play device hardware ID property. - hwid, err := syscall.UTF16FromString(hardwareID) - if err != nil { - return nil, false, err // syscall.UTF16FromString(hardwareID) should never fail: hardwareID is const string without NUL chars. - } - err = devInfoList.SetDeviceRegistryProperty(deviceData, setupapi.SPDRP_HARDWAREID, setupapi.UTF16ToBuf(append(hwid, 0))) + err = devInfoList.SetDeviceRegistryPropertyString(deviceData, setupapi.SPDRP_HARDWAREID, hardwareID) if err != nil { return nil, false, errors.New("SetupDiSetDeviceRegistryProperty(SPDRP_HARDWAREID) failed: " + err.Error()) }