all: avoid unsafe StringToUTF16Ptr on Windows

The syscall.StringToUTF16Ptr function panics when
provided with an input containing a NUL character.
Replace with syscall.UTF16PtrFromString.

Fixes potential panics in net.Dial, net.LookupPort,
and syscall.Readlink.

Fixes CVE-2026-39836
Fixes #79006

Change-Id: I2fd7bb750d27474047f199faca4061466a6a6964
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/4260
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/775320
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Damien Neil 2026-04-24 16:40:40 -07:00 committed by Cherry Mui
parent f9f6dc7c82
commit 788b1c54c1
5 changed files with 37 additions and 7 deletions

View file

@ -132,7 +132,11 @@ loopItems:
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
var h syscall.Handle
var d uint32
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return 0, false, err
}
err = regCreateKeyEx(syscall.Handle(k), pathp,
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
if err != nil {
return 0, false, err
@ -142,7 +146,11 @@ func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool
// DeleteKey deletes the subkey path of key k and its values.
func DeleteKey(k Key, path string) error {
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return err
}
return regDeleteKey(syscall.Handle(k), pathp)
}
// A KeyInfo describes the statistics of a key. It is returned by Stat.

View file

@ -333,7 +333,11 @@ func (k Key) SetBinaryValue(name string, value []byte) error {
// DeleteValue removes a named value from the key k.
func (k Key) DeleteValue(name string) error {
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
namep, err := syscall.UTF16PtrFromString(name)
if err != nil {
return err
}
return regDeleteValue(syscall.Handle(k), namep)
}
// ReadValueNames returns the value names of key k.

View file

@ -769,6 +769,7 @@ func TestLookupPort(t *testing.T) {
{"udp", "-1", 0, false},
{"udp", "65536", 0, false},
{"tcp", "123456789", 0, false},
{"tcp", "bad\x00port", 0, false},
// Issue 13610: LookupPort("tcp", "")
{"tcp", "", 0, true},

View file

@ -215,8 +215,13 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int
hints.Family = syscall.AF_INET6
}
servicep, err := syscall.UTF16PtrFromString(service)
if err != nil {
return 0, newDNSError(err, network+"/"+service, "")
}
var result *syscall.AddrinfoW
e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
e := syscall.GetAddrInfoW(nil, servicep, &hints, &result)
if e != nil {
if port, err := lookupPortMap(network, service); err == nil {
return port, nil
@ -269,7 +274,12 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error)
}
defer syscall.DnsRecordListFree(rec, 1)
resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), rec)
namep, err := syscall.UTF16PtrFromString(name)
if err != nil {
return "", newDNSError(err, name, "")
}
resolved := resolveCNAME(namep, rec)
cname := windows.UTF16PtrToString(resolved)
return absDomainName(cname), nil
}
@ -415,7 +425,10 @@ const dnsSectionMask = 0x0003
// returns only results applicable to name and resolves CNAME entries.
func validRecs(r *syscall.DNSRecord, dnstype uint16, name string) []*syscall.DNSRecord {
cname := syscall.StringToUTF16Ptr(name)
cname, err := syscall.UTF16PtrFromString(name)
if err != nil {
return nil
}
if dnstype != syscall.DNS_TYPE_CNAME {
cname = resolveCNAME(cname, r)
}

View file

@ -1375,7 +1375,11 @@ func LoadCreateSymbolicLink() error {
// Readlink returns the destination of the named symbolic link.
func Readlink(path string, buf []byte) (n int, err error) {
fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING,
pathp, err := UTF16PtrFromString(path)
if err != nil {
return -1, err
}
fd, err := CreateFile(pathp, GENERIC_READ, 0, nil, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0)
if err != nil {
return -1, err