From 2f52bdda904a1c332da0969331deb2d00c1f47ba Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Wed, 5 Aug 2026 10:23:15 +0530 Subject: [PATCH v2] Reject out-of-range LSNs in backup manifests parse_xlogrecptr() used sscanf() with "%X" to read each half of an LSN into a uint32. A half wider than 32 bits was therefore accepted with its high-order bits silently discarded, and trailing garbage after the LSN was ignored, because sscanf() still reported two successful conversions. Genuinely unparseable values were rejected, so the difference went unnoticed. The resulting value is used to validate the WAL ranges of a backup, both by pg_verifybackup and pg_combinebackup and, via UPLOAD_MANIFEST, by the server when taking an incremental backup. Those checks were therefore performed against a location the manifest did not actually specify. Use the common pg_parse_lsn() helper, which requires each half to consist of one to eight hexadecimal digits and the whole string to be consumed, matching the rules of the pg_lsn input function, and add tests. Commit 355814931141 tightened the other scalar values of a manifest in the same way, but did not touch this one. --- src/bin/pg_verifybackup/t/005_bad_manifest.pl | 12 +++++++++++ src/common/parse_manifest.c | 21 +++---------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/bin/pg_verifybackup/t/005_bad_manifest.pl b/src/bin/pg_verifybackup/t/005_bad_manifest.pl index bc9fe4a79d7..6a0989ea5c3 100644 --- a/src/bin/pg_verifybackup/t/005_bad_manifest.pl +++ b/src/bin/pg_verifybackup/t/005_bad_manifest.pl @@ -168,6 +168,18 @@ test_parse_error('could not parse start LSN', <timeline || *ep) json_manifest_parse_failure(parse->context, "timeline is not an integer"); - if (!parse_xlogrecptr(&start_lsn, parse->start_lsn)) + if (!pg_parse_lsn(parse->start_lsn, &start_lsn)) json_manifest_parse_failure(parse->context, "could not parse start LSN"); - if (!parse_xlogrecptr(&end_lsn, parse->end_lsn)) + if (!pg_parse_lsn(parse->end_lsn, &end_lsn)) json_manifest_parse_failure(parse->context, "could not parse end LSN"); @@ -932,18 +932,3 @@ hexdecode_string(uint8 *result, char *input, int nbytes) return true; } - -/* - * Parse an XLogRecPtr expressed using the usual string format. - */ -static bool -parse_xlogrecptr(XLogRecPtr *result, char *input) -{ - uint32 hi; - uint32 lo; - - if (sscanf(input, "%X/%08X", &hi, &lo) != 2) - return false; - *result = ((uint64) hi) << 32 | lo; - return true; -} -- 2.34.1