postgres.git / summary / log / commit / refs

commit    c24311c1fed18ebdf0e64f31a8cd86cd3232657b
Author:   Alexander Korotkov <akorotkov@postgresql.org>
Date:     Tue Feb 04 22:15:17 2025 +0000
First released in: 18.0, 13.19, 14.16, 15.11, 16.7, 17.3

    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


src/bin/pg_controldata/pg_controldata.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index e73639df744..9ead17e35d1 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]; @@ -197,20 +198,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; [parent: d6ea82f5da18]