diff options
author | Andres Freund <andres@anarazel.de> | 2025-02-10 10:03:40 -0500 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2025-02-10 10:03:40 -0500 |
commit | 00f1a1f665f078f5abadbf8baddc5c187fba80f8 (patch) | |
tree | 58c6aa8860903f1b9e64e9baaf7198b94a1e88a3 | |
parent | bf085f6d45e2300439d85bae384a7f90844d3deb (diff) | |
download | postgresql-00f1a1f665f078f5abadbf8baddc5c187fba80f8.tar.gz postgresql-00f1a1f665f078f5abadbf8baddc5c187fba80f8.zip |
Back-patch pg_encoding_verifymbstr()/pg_encoding_verifymbchar() to v13.
A security fix will need those functions, so back-patch the v14+ functions to
v13.
When commit b80e10638e36b9d2f0b39170c613837af2ca2aac introduced the v14+
implementation of pg_encoding_verifymbstr(), it added a callback to each
pg_wchar_table entry. For simplicity and ABI stability, this instead
implements the function in terms of the existing per-character callback.
Author: Noah Misch <noah@leadboat.com>
Author: Andres Freund <andres@anarazel.de>
Security: CVE-2025-1094
-rw-r--r-- | src/common/wchar.c | 66 | ||||
-rw-r--r-- | src/include/mb/pg_wchar.h | 2 |
2 files changed, 68 insertions, 0 deletions
diff --git a/src/common/wchar.c b/src/common/wchar.c index 08734802236..2d044ee4ffb 100644 --- a/src/common/wchar.c +++ b/src/common/wchar.c @@ -1597,6 +1597,72 @@ pg_encoding_verifymb(int encoding, const char *mbstr, int len) pg_wchar_table[PG_SQL_ASCII].mbverify((const unsigned char *) mbstr, len)); } +/* v14+ function name, for easier backpatching */ +int +pg_encoding_verifymbchar(int encoding, const char *mbstr, int len) +{ + int ok_bytes = pg_encoding_verifymb(encoding, mbstr, len); + + if (ok_bytes == 0) + return -1; + return ok_bytes; +} + +/* replace v14+ function, adapted from pg_verify_mbstr_len */ +int +pg_encoding_verifymbstr(int encoding, const char *mbstr, int len) +{ + mbverifier mbverify; + int ok_bytes; + + Assert(PG_VALID_ENCODING(encoding)); + + /* + * In single-byte encodings, we need only reject nulls (\0). + */ + if (pg_encoding_max_length(encoding) <= 1) + { + const char *nullpos = memchr(mbstr, 0, len); + + if (nullpos == NULL) + return len; + return nullpos - mbstr; + } + + /* fetch function pointer just once */ + mbverify = pg_wchar_table[encoding].mbverify; + + ok_bytes = 0; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*mbstr)) + { + if (*mbstr != '\0') + { + ok_bytes++; + mbstr++; + len--; + continue; + } + return ok_bytes; + } + + l = (*mbverify) ((const unsigned char *) mbstr, len); + + if (l < 0) + return ok_bytes; + + mbstr += l; + len -= l; + ok_bytes += l; + } + return ok_bytes; +} + /* * fetch maximum length of a given encoding */ diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h index b43454b64ce..b0dbde45b33 100644 --- a/src/include/mb/pg_wchar.h +++ b/src/include/mb/pg_wchar.h @@ -556,6 +556,8 @@ extern int pg_encoding_mblen(int encoding, const char *mbstr); extern int pg_encoding_mblen_bounded(int encoding, const char *mbstr); extern int pg_encoding_dsplen(int encoding, const char *mbstr); extern int pg_encoding_verifymb(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len); extern int pg_encoding_max_length(int encoding); extern int pg_valid_client_encoding(const char *name); extern int pg_valid_server_encoding(const char *name); |