From 51655475defa9131403512b81a9b39872799f14c Mon Sep 17 00:00:00 2001 From: Aleksander Alekseev Date: Wed, 13 Jul 2022 16:00:22 +0300 Subject: [PATCH v1] Fix out of bounds memory reads in text_substring() --- src/backend/utils/adt/varlena.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 919138eaf3..e4f25f4aae 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -927,6 +927,8 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) int32 slice_start; int32 slice_size; int32 slice_strlen; + int32 copy_bytes; + int32 max_copy_bytes; text *slice; int32 E1; int32 i; @@ -1004,8 +1006,9 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) } /* Now we can get the actual length of the slice in MB characters */ + max_copy_bytes = VARSIZE_ANY_EXHDR(slice); slice_strlen = pg_mbstrlen_with_len(VARDATA_ANY(slice), - VARSIZE_ANY_EXHDR(slice)); + max_copy_bytes); /* * Check that the start position wasn't > slice_strlen. If so, SQL99 @@ -1032,7 +1035,11 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) */ p = VARDATA_ANY(slice); for (i = 0; i < S1 - 1; i++) - p += pg_mblen(p); + { + int t = pg_mblen(p); + p += t; + max_copy_bytes -= t; + } /* hang onto a pointer to our start position */ s = p; @@ -1044,9 +1051,13 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) for (i = S1; i < E1; i++) p += pg_mblen(p); - ret = (text *) palloc(VARHDRSZ + (p - s)); - SET_VARSIZE(ret, VARHDRSZ + (p - s)); - memcpy(VARDATA(ret), s, (p - s)); + copy_bytes = p - s; + if(copy_bytes > max_copy_bytes) + copy_bytes = max_copy_bytes; + + ret = (text *) palloc(VARHDRSZ + copy_bytes); + SET_VARSIZE(ret, VARHDRSZ + copy_bytes); + memcpy(VARDATA(ret), s, copy_bytes); if (slice != (text *) DatumGetPointer(str)) pfree(slice); -- 2.36.1