diff options
author | Alexander Korotkov <akorotkov@postgresql.org> | 2025-02-05 00:15:17 +0200 |
---|---|---|
committer | Alexander Korotkov <akorotkov@postgresql.org> | 2025-02-05 00:45:43 +0200 |
commit | 1b8a9533f07a31eae6f93aa99cd996931f1b1911 (patch) | |
tree | 1c0d0ce8ec6137bcd1f230cdcfb2c49faa837afd | |
parent | 8703cdec2055d055583ca17ef2d2b5052b064a15 (diff) | |
download | postgresql-1b8a9533f07a31eae6f93aa99cd996931f1b1911.tar.gz postgresql-1b8a9533f07a31eae6f93aa99cd996931f1b1911.zip |
pg_controldata: Fix possible errors on corrupted pg_control
Protect against malformed timestamps. Also protect against negative WalSegSz
as it triggers division by zero:
((0x100000000UL) / (WalSegSz)) can turn into zero in
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
segno, WalSegSz);
because if WalSegSz is -1 then by arithmetic rules in C we get
0x100000000UL / 0xFFFFFFFFFFFFFFFFUL == 0.
Author: Ilyasov Ian <ianilyasov@outlook.com>
Author: Anton Voloshin <a.voloshin@postgrespro.ru>
Backpatch-through: 13
-rw-r--r-- | src/bin/pg_controldata/pg_controldata.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 93a05d80ca7..cf11ab3f2ee 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -97,6 +97,7 @@ main(int argc, char *argv[]) bool crc_ok; char *DataDir = NULL; time_t time_tmp; + struct tm *tm_tmp; char pgctime_str[128]; char ckpttime_str[128]; char mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1]; @@ -196,20 +197,30 @@ main(int argc, char *argv[]) * about %c */ time_tmp = (time_t) ControlFile->time; - strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, - localtime(&time_tmp)); + tm_tmp = localtime(&time_tmp); + + if (tm_tmp != NULL) + strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, tm_tmp); + else + snprintf(pgctime_str, sizeof(pgctime_str), _("???")); + time_tmp = (time_t) ControlFile->checkPointCopy.time; - strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, - localtime(&time_tmp)); + tm_tmp = localtime(&time_tmp); + + if (tm_tmp != NULL) + strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, tm_tmp); + else + snprintf(ckpttime_str, sizeof(ckpttime_str), _("???")); /* * Calculate name of the WAL file containing the latest checkpoint's REDO * start point. * - * A corrupted control file could report a WAL segment size of 0, and to - * guard against division by zero, we need to treat that specially. + * A corrupted control file could report a WAL segment size of 0 or + * negative value, and to guard against division by zero, we need to treat + * that specially. */ - if (WalSegSz != 0) + if (WalSegSz > 0) { XLogSegNo segno; |