From 5567ea2fb4ba82a5ebe4efaacef58715d95c9216 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 16 Aug 2026 12:08:22 -0400
Subject: [PATCH v1 1/2] Tighten up tsqueryrecv().

tsqueryrecv() accepted zero-length lexemes, which tsqueryin() doesn't.
It also accepted phrase distance values larger than MAXENTRYPOS,
which tsqueryin() doesn't.  While neither of these omissions are
very harmful in themselves, they do allow accepting tsquery values
that will fail in a subsequent textual dump/reload.

Commit 23d9ad771 performed similar tightening of tsvectorrecv(),
but I left off these changes at the time because they didn't seem
to have security implications.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
---
 src/backend/utils/adt/tsquery.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c
index 3247d5db082..df26fc2a139 100644
--- a/src/backend/utils/adt/tsquery.c
+++ b/src/backend/utils/adt/tsquery.c
@@ -1272,6 +1272,9 @@ tsqueryrecv(PG_FUNCTION_ARGS)
 			if (weight > 0xF)
 				elog(ERROR, "invalid tsquery: invalid weight bitmap");
 
+			if (val_len == 0)
+				elog(ERROR, "invalid tsquery: empty operand");
+
 			if (val_len > MAXSTRLEN)
 				elog(ERROR, "invalid tsquery: operand too long");
 
@@ -1311,7 +1314,14 @@ tsqueryrecv(PG_FUNCTION_ARGS)
 
 			item->qoperator.oper = oper;
 			if (oper == OP_PHRASE)
-				item->qoperator.distance = (int16) pq_getmsgint(buf, sizeof(int16));
+			{
+				unsigned int dist = pq_getmsgint(buf, sizeof(int16));
+
+				if (dist > MAXENTRYPOS)
+					elog(ERROR, "invalid tsquery: invalid phrase distance %d",
+						 dist);
+				item->qoperator.distance = (int16) dist;
+			}
 		}
 		else
 			elog(ERROR, "unrecognized tsquery node type: %d", item->type);
-- 
2.52.0

