From 1cff6bb7892da64afc7078cfc0e855b5ae598ac0 Mon Sep 17 00:00:00 2001
From: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Date: Sun, 17 May 2026 11:19:22 +0530
Subject: [PATCH] pg_stash_advice: reject overlong stash names when loading
 dump file

The persistence dump file parser did not validate the length of stash
names read from disk before passing them to dshash_find_or_insert(),
which calls dshash_strhash() with a key_size of NAMEDATALEN.  That
function asserts strlen(v) < size, so a dump file containing any stash
name of 64 bytes or more caused an assertion failure in
assertion-enabled builds.  The resulting SIGABRT was treated by the
postmaster as a crash, leading to a full crash-recovery cycle.  Because
the same dump file is read on every restart, this produced an indefinite
crash-restart loop until the file was manually removed.  In production
builds the name would be silently truncated to NAMEDATALEN-1 bytes by
the dshash key-copy, allowing distinct names to collide.

SQL-level callers cannot trigger this because pgsa_check_stash_name()
enforces the length limit, but the persistence parser bypassed all of
those checks, so the bug was reachable via a corrupted, hand-edited or
truncated dump file, or potentially by reading a file produced by a
future server version with a longer NAMEDATALEN.

Fix this by validating the parsed stash-name length in the same place
where the parser already raises ERRCODE_DATA_CORRUPTED on other forms
of syntax error.  Add a TAP test that writes a poisoned dump file and
verifies that the cluster starts cleanly with a parse-error logged
instead of crashing.
---
 contrib/pg_stash_advice/stashpersist.c   | 17 +++++++++++++++++
 contrib/pg_stash_advice/t/001_persist.pl | 19 +++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/contrib/pg_stash_advice/stashpersist.c b/contrib/pg_stash_advice/stashpersist.c
index 00a0a74f04d..949be1836dc 100644
--- a/contrib/pg_stash_advice/stashpersist.c
+++ b/contrib/pg_stash_advice/stashpersist.c
@@ -367,6 +367,23 @@ pgsa_read_from_disk(void)
 						 errmsg("syntax error in file \"%s\" line %u: expected stash name",
 								PGSA_DUMP_FILE, lineno)));
 
+			/*
+			 * Reject overlong stash names.  Names that do not fit in
+			 * NAMEDATALEN bytes would otherwise crash an assertion-enabled
+			 * build via dshash_strhash() when we try to insert them into
+			 * pgsa_stash_dshash, and would be silently truncated (with
+			 * possible collisions) in production builds.  SQL-level callers
+			 * are checked by pgsa_check_stash_name(), but the dump file
+			 * parser must perform its own check because the file content may
+			 * have been produced by an older or modified server, or
+			 * tampered with on disk.
+			 */
+			if (strlen(name) >= NAMEDATALEN)
+				ereport(ERROR,
+						(errcode(ERRCODE_DATA_CORRUPTED),
+						 errmsg("syntax error in file \"%s\" line %u: stash name is longer than %d bytes",
+								PGSA_DUMP_FILE, lineno, NAMEDATALEN - 1)));
+
 			/* No further fields are expected. */
 			if (*cursor != '\0')
 				ereport(ERROR,
diff --git a/contrib/pg_stash_advice/t/001_persist.pl b/contrib/pg_stash_advice/t/001_persist.pl
index 83e98889f93..7387789edb8 100644
--- a/contrib/pg_stash_advice/t/001_persist.pl
+++ b/contrib/pg_stash_advice/t/001_persist.pl
@@ -89,4 +89,23 @@ ok( !-f $node->data_dir . '/pg_stash_advice.tsv',
 
 $node->stop;
 
+# A dump file that contains a stash name longer than NAMEDATALEN-1 bytes used
+# to crash the worker via an assertion failure in dshash_strhash(), which in
+# turn led the postmaster to crash-restart the cluster in a loop.  Verify
+# that an overlong stash name is now rejected with a clean parse error and
+# that the cluster can start normally.
+my $long_name = 'a' x 64;
+my $dump_path = $node->data_dir . '/pg_stash_advice.tsv';
+open(my $fh, '>', $dump_path) or die "cannot open $dump_path: $!";
+print $fh "stash\t$long_name\n";
+close($fh);
+
+$node->start;
+$node->wait_for_log(qr/stash name is longer than 63 bytes/);
+
+is( $node->safe_psql("postgres", "SELECT 1"),
+	"1", 'cluster is up after rejecting overlong stash name in dump file');
+
+$node->stop;
+
 done_testing();
-- 
2.34.1

