aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2025-02-10 10:03:40 -0500
committerAndres Freund <andres@anarazel.de>2025-02-10 10:03:40 -0500
commit00f1a1f665f078f5abadbf8baddc5c187fba80f8 (patch)
tree58c6aa8860903f1b9e64e9baaf7198b94a1e88a3
parentbf085f6d45e2300439d85bae384a7f90844d3deb (diff)
downloadpostgresql-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.c66
-rw-r--r--src/include/mb/pg_wchar.h2
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);