CVE-2024-32886 (Go, published 2024-05-08T14:15Z)
Description: value: Vitess is a database clustering system for horizontal scaling of MySQL. When executing the following simple query, the `vtgate` will go into an endless loop that also keeps consuming memory and eventually will run out of memory. This vulnerability is fixed in 19.0.4, 18.0.5, and 17.0.7.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/vitessio/vitess
Files changed:
go/mysql/collations/charset/convert.go
go/mysql/collations/charset/helpers.go
go/mysql/collations/charset/unicode/utf16.go
go/mysql/collations/charset/unicode/utf32.go
go/vt/vtgate/evalengine/compiler_asm.go
go/vt/vtgate/evalengine/compiler_test.go
go/vt/vtgate/evalengine/expr_collate.go
go/vt/vtgate/evalengine/translate.go
Commit message: Merge pull request from GHSA-649x-hxfx-57j2

* collations: Fix OOM and handle padding for multibyte

This fixes the OOM issue where a simple query can trigger a denial of
service attack. It also ensures we return the right result for these
queries by doing the correct padding.

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

* Address review comments

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

---------

Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>

Vulnerable code:
		if cp == utf8.RuneError && width < 3 {
		if r == RuneError && size < 2 {
		return utf8.RuneError, 0
		return utf8.RuneError, 0
		return utf8.RuneError, 0
		return utf8.RuneError, 0
		arg := evalToBinary(env.vm.stack[env.vm.sp-offset])
	var b *evalBytes
	if expr.TypedCollation.Collation == collations.CollationBinaryID {
		b = evalToBinary(e)
	} else {
		b, err = evalToVarchar(e, expr.TypedCollation.Collation, false)
		if err != nil {
			return nil, err
		}
			lit.inner, err = evalToVarchar(lit.inner, collation, false)

Fixed code:
		if cp == utf8.RuneError {
		if r == RuneError {
		return utf8.RuneError, len(b)
		return utf8.RuneError, len(b)
		return utf8.RuneError, len(p)
		return utf8.RuneError, len(p)
		var arg *evalBytes
		arg, env.vm.err = introducerCast(env.vm.stack[env.vm.sp-offset], col.Collation)
		{
			expression: `convert(0xFF using utf16)`,
			result:     `VARCHAR("ÿ")`,
		},
		{
			expression: `_utf16 0xFF`,
			result:     `VARCHAR("ÿ")`,
		},
		{
			expression: `convert(0xFF using utf32)`,
			result:     `NULL`,
		},
		{
			expression: `cast(_utf32 0xFF as binary)`,
			result:     `VARBINARY("\x00\x00\x00\xff")`,
		},
		{
			expression: `cast(_utf32 0x00FF as binary)`,
			result:     `VARBINARY("\x00\x00\x00\xff")`,
		},
		{
			expression: `cast(_utf32 0x0000FF as binary)`,
			result:     `VARBINARY("\x00\x00\x00\xff")`,
		},
	"vitess.io/vitess/go/mysql/collations/charset"
	"vitess.io/vitess/go/mysql/collations/colldata"
func introducerCast(e eval, col collations.ID) (*evalBytes, error) {
	if col == collations.CollationBinaryID {
		return evalToBinary(e), nil
	}

	var bytes []byte
	if b, ok := e.(*evalBytes); !ok {
		bytes = b.ToRawBytes()
	} else {
		cs := colldata.Lookup(col).Charset()
		bytes = b.bytes
		// We only need to pad here for encodings that have a minimum
		// character byte width larger than 1, which is all UTF-16
		// variations and UTF-32.
		switch cs.(type) {
		case charset.Charset_utf16, charset.Charset_utf16le, charset.Charset_ucs2:
			if len(bytes)%2 != 0 {
				bytes = append([]byte{0}, bytes...)
			}
		case charset.Charset_utf32:
			if mod := len(bytes) % 4; mod != 0 {
				bytes = append(make([]byte, 4-mod), bytes...)
			}
		}
	}
	typedcol := collations.TypedCollation{
		Collation:    col,
		Coercibility: collations.CoerceCoercible,
		Repertoire:   collations.RepertoireASCII,
	}
	return newEvalText(bytes, typedcol), nil
}

	b, err := introducerCast(e, expr.TypedCollation.Collation)
	if err != nil {
		return nil, err
			lit.inner, err = introducerCast(lit.inner, collation)