windows: avoid uint16 overflow in NewNTUnicodeString Fixes CVE-2026-39824 Fixes #78916 Change-Id: I344518a17d59fd81c4bb39da0b3e13be6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/sys/+/770080 Reviewed-by: Neal Patel <nealpatel@google.com> Reviewed-by: Quim Muntal <quimmuntal@gmail.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 9cab50a..453a7b9 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go
@@ -1697,10 +1697,13 @@ if err != nil { return nil, err } - n := uint16(len(s16) * 2) + n := len(s16) * 2 + if n > (1<<16)-1 { + return nil, syscall.EINVAL + } return &NTUnicodeString{ - Length: n - 2, // subtract 2 bytes for the NULL terminator - MaximumLength: n, + Length: uint16(n) - 2, // subtract 2 bytes for the NULL terminator + MaximumLength: uint16(n), Buffer: &s16[0], }, nil }
diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 7611538..f552b94 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go
@@ -10,6 +10,7 @@ "debug/pe" "errors" "fmt" + "math" "os" "os/exec" "path/filepath" @@ -1475,21 +1476,37 @@ } func TestRoundtripNTUnicodeString(t *testing.T) { - for _, s := range []string{ - "", - "hello", - "Ƀ", - strings.Repeat("*", 32000), // NTUnicodeString works up to 2^16 byte lengths == 32768 uint16s. - // TODO: various encoding errors? - } { - ntus, err := windows.NewNTUnicodeString(s) + // NTUnicodeString maximum string length must fit in a uint16, less for terminal NUL. + maxString := strings.Repeat("*", (math.MaxUint16/2)-1) + for _, test := range []struct { + s string + wantErr bool + }{{ + s: "", + }, { + s: "hello", + }, { + s: "Ƀ", + }, { + s: maxString, + }, { + s: maxString + "*", + wantErr: true, + }, { + s: "a\x00a", + wantErr: true, + }} { + ntus, err := windows.NewNTUnicodeString(test.s) + if (err != nil) != test.wantErr { + t.Errorf("NewNTUnicodeString(%q): %v, wantErr:%v", test.s, err, test.wantErr) + continue + } if err != nil { - t.Errorf("encoding %q failed: %v", s, err) continue } s2 := ntus.String() - if s != s2 { - t.Errorf("round trip of %q = %q, wanted original", s, s2) + if test.s != s2 { + t.Errorf("round trip of %q = %q, wanted original", test.s, s2) } } }