From 61c6ee7eb652ebf3b5c09ae603b3322d4b90370a Mon Sep 17 00:00:00 2001 From: Hayato Kuroda Date: Mon, 26 Oct 2026 16:19:25 +0900 Subject: [PATCH v7 1/3] Use pg_parse_lsn() for reading backup label read_backup_label() previously parsed the START WAL LOCATION and CHECKPOINT LOCATION fields using fscanf("%X/%08X") into uint32 values. An overlong high component could overflow, while an overlong low component was truncated to its first eight digits. Other malformed forms accepted by scanf(), such as signs and "0x" prefixes, could also be interpreted differently from pg_lsn input. Use pg_parse_lsn() instead, requiring one to eight hexadecimal digits per component and no trailing characters, as for pg_lsn input. This follows similar conversions in commits 4a842a1d657, ba6d9ee259c, and 5ffb8c74093. --- src/backend/access/transam/xlogrecovery.c | 27 +++++++++++++++-------- src/backend/utils/adt/pg_lsn.c | 2 -- src/include/common/pg_parse_lsn.h | 2 ++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 20be788da78..7a1de0567a8 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -44,6 +44,7 @@ #include "catalog/pg_control.h" #include "commands/tablespace.h" #include "common/file_utils.h" +#include "common/pg_parse_lsn.h" #include "miscadmin.h" #include "nodes/miscnodes.h" #include "pgstat.h" @@ -1190,8 +1191,7 @@ read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, char backupfrom[20]; char backuplabel[MAXPGPATH]; char backuptime[128]; - uint32 hi, - lo; + char lsn[MAXPG_LSNLEN + 1]; /* suppress possible uninitialized-variable warnings */ *checkPointLoc = InvalidXLogRecPtr; @@ -1218,19 +1218,23 @@ read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, * is pretty crude, but we are not expecting any variability in the file * format). */ - if (fscanf(lfp, "START WAL LOCATION: %X/%08X (file %08X%16s)%c", - &hi, &lo, &tli_from_walseg, startxlogfilename, &ch) != 5 || ch != '\n') + if (fscanf(lfp, + "START WAL LOCATION: %" CppAsString2(MAXPG_LSNLEN) "[0123456789ABCDEFabcdef/] (file %08X%16s)%c", + lsn, &tli_from_walseg, startxlogfilename, &ch) != 4 || + ch != '\n' || + !pg_parse_lsn(lsn, &RedoStartLSN)) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE))); - RedoStartLSN = ((uint64) hi) << 32 | lo; RedoStartTLI = tli_from_walseg; - if (fscanf(lfp, "CHECKPOINT LOCATION: %X/%08X%c", - &hi, &lo, &ch) != 3 || ch != '\n') + if (fscanf(lfp, + "CHECKPOINT LOCATION: %" CppAsString2(MAXPG_LSNLEN) "[0123456789ABCDEFabcdef/]%c", lsn, + &ch) != 2 || + ch != '\n' || + !pg_parse_lsn(lsn, checkPointLoc)) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE))); - *checkPointLoc = ((uint64) hi) << 32 | lo; *backupLabelTLI = tli_from_walseg; /* @@ -1297,7 +1301,12 @@ read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, tli_from_file, BACKUP_LABEL_FILE))); } - if (fscanf(lfp, "INCREMENTAL FROM LSN: %X/%08X\n", &hi, &lo) > 0) + /* + * INCREMENTAL FROM LSN indicates that this is an incremental backup. The + * LSN itself need not be parsed, so reading its first character is + * sufficient. + */ + if (fscanf(lfp, "INCREMENTAL FROM LSN: %c", &ch) == 1) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("this is an incremental backup, not a data directory"), diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c index 7886e9b83e8..3ec2c2b650e 100644 --- a/src/backend/utils/adt/pg_lsn.c +++ b/src/backend/utils/adt/pg_lsn.c @@ -19,8 +19,6 @@ #include "utils/numeric.h" #include "utils/pg_lsn.h" -#define MAXPG_LSNLEN 17 - /*---------------------------------------------------------- * Formatting and conversion routines. *---------------------------------------------------------*/ diff --git a/src/include/common/pg_parse_lsn.h b/src/include/common/pg_parse_lsn.h index 0a80785a4e9..94d776f89b6 100644 --- a/src/include/common/pg_parse_lsn.h +++ b/src/include/common/pg_parse_lsn.h @@ -15,6 +15,8 @@ #include "access/xlogdefs.h" +#define MAXPG_LSNLEN 17 + extern bool pg_parse_lsn(const char *str, XLogRecPtr *result); #endif /* PG_PARSE_LSN_H */ -- 2.52.0