0001-Fix-out-of-bounds-access-on-embedded-null-tokens-in-.patch
application/x-patch
Filename: 0001-Fix-out-of-bounds-access-on-embedded-null-tokens-in-.patch
Type: application/x-patch
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Fix out-of-bounds access on embedded null tokens in dict_int and dict_xsyn
| File | + | − |
|---|---|---|
| contrib/dict_int/dict_int.c | 6 | 0 |
| contrib/dict_xsyn/dict_xsyn.c | 7 | 8 |
From 382c736b599292470b050e112b66945c46a5a7e7 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Thu, 18 Jun 2026 19:54:54 +0530
Subject: [PATCH] Fix out-of-bounds access on embedded null tokens in dict_int
and dict_xsyn
pnstrdup() stops at the first null byte, so a token beginning with a null
is copied as a 1-byte string. Both dictionaries then reused the original
token length against that shorter copy.
dintdict_lexize() (dict_int) used it for the "len > maxlen" check and then
wrote txt[maxlen] = '\0' past the end of the 1-byte allocation; recompute
len from the copy. dxsyn_lexize() (dict_xsyn) passed the original length
to str_tolower(), which then read past the copy; pass the token directly
instead, dropping the needless copy.
Reaching either path needs a token with a null byte, which the normal
text-search input path does not produce (it requires SQL_ASCII and a
caller passing raw bytes to the lexize method).
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>
Bug: #19525
---
contrib/dict_int/dict_int.c | 6 ++++++
contrib/dict_xsyn/dict_xsyn.c | 15 +++++++--------
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/contrib/dict_int/dict_int.c b/contrib/dict_int/dict_int.c
index aafce894977..b4413cfde99 100644
--- a/contrib/dict_int/dict_int.c
+++ b/contrib/dict_int/dict_int.c
@@ -95,6 +95,12 @@ dintdict_lexize(PG_FUNCTION_ARGS)
else
txt = pnstrdup(in, len);
+ /*
+ * pnstrdup() stops at the first null byte, so recompute len from the copy;
+ * otherwise the truncation below could write past the allocation.
+ */
+ len = strlen(txt);
+
if (len > d->maxlen)
{
if (d->rejectlong)
diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c
index 9e3784e0f47..b375e8f7387 100644
--- a/contrib/dict_xsyn/dict_xsyn.c
+++ b/contrib/dict_xsyn/dict_xsyn.c
@@ -211,14 +211,13 @@ dxsyn_lexize(PG_FUNCTION_ARGS)
if (!length || d->len == 0)
PG_RETURN_POINTER(NULL);
- /* Create search pattern */
- {
- char *temp = pnstrdup(in, length);
-
- word.key = str_tolower(temp, length, DEFAULT_COLLATION_OID);
- pfree(temp);
- word.value = NULL;
- }
+ /*
+ * Pass the token directly to str_tolower(); copying it first with
+ * pnstrdup() and reusing the original length would read past the copy if
+ * the token contains a null byte.
+ */
+ word.key = str_tolower(in, length, DEFAULT_COLLATION_OID);
+ word.value = NULL;
/* Look for matching syn */
found = (Syn *) bsearch(&word, d->syn, d->len, sizeof(Syn), compare_syn);
--
2.34.1