From f1a074b146c900bd439b6ef1953866f41b61a669 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 23 Mar 2018 10:10:49 -0400 Subject: [PATCH] pg_resetwal: Prevent division-by-zero errors Handle the case where the pg_control file specifies a WAL segment size of 0 bytes. This would previously have led to a division by zero error. Change this to assume the whole file is corrupt and go to guess everything. Discussion: https://www.postgresql.org/message-id/a6163ad7-cc99-fdd1-dfad-25df73032ab8%402ndquadrant.com --- src/bin/pg_resetwal/pg_resetwal.c | 4 +-- src/bin/pg_resetwal/t/002_corrupted.pl | 47 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/bin/pg_resetwal/t/002_corrupted.pl diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index a132cf2e9f..c99e7a8db1 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -601,7 +601,7 @@ ReadControlFile(void) fprintf(stderr, _("%s: pg_control specifies invalid WAL segment size (%d bytes); proceed with caution \n"), progname, WalSegSz); - guessed = true; + return false; } return true; @@ -678,7 +678,7 @@ GuessControlValues(void) ControlFile.floatFormat = FLOATFORMAT_VALUE; ControlFile.blcksz = BLCKSZ; ControlFile.relseg_size = RELSEG_SIZE; - ControlFile.xlog_blcksz = XLOG_BLCKSZ; + WalSegSz = ControlFile.xlog_blcksz = XLOG_BLCKSZ; ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE; ControlFile.nameDataLen = NAMEDATALEN; ControlFile.indexMaxKeys = INDEX_MAX_KEYS; diff --git a/src/bin/pg_resetwal/t/002_corrupted.pl b/src/bin/pg_resetwal/t/002_corrupted.pl new file mode 100644 index 0000000000..9df5574c8b --- /dev/null +++ b/src/bin/pg_resetwal/t/002_corrupted.pl @@ -0,0 +1,47 @@ +# Tests for handling a corrupted pg_control + +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 6; + +my $node = get_new_node('main'); +$node->init; + +my $pg_control = $node->data_dir . '/global/pg_control'; +my $size = (stat($pg_control))[7]; + +# Read out the head of the file to get PG_CONTROL_VERSION in +# particular. +my $data; +open my $fh, '<', $pg_control or BAIL_OUT($!); +binmode $fh; +read $fh, $data, 16; +close $fh; + +# Fill pg_control with zeros +open $fh, '>', $pg_control or BAIL_OUT($!); +binmode $fh; +print $fh pack("x[$size]"); +close $fh; + +command_checks_all([ 'pg_resetwal', '-n', $node->data_dir ], + 0, + [ qr/pg_control version number/ ], + [ qr/pg_resetwal: pg_control exists but is broken or wrong version; ignoring it/ ], + 'processes corrupted pg_control all zeroes'); + +# Put in the previously saved header data. This uses a different code +# path internally, allowing us to process a zero WAL segment size. +open $fh, '>', $pg_control or BAIL_OUT($!); +binmode $fh; +print $fh $data, pack("x[" . ($size - 16) . "]"); +close $fh; + +command_checks_all([ 'pg_resetwal', '-n', $node->data_dir ], + 0, + [ qr/pg_control version number/ ], + [ qr/\Qpg_resetwal: pg_control specifies invalid WAL segment size (0 bytes); proceed with caution\E/ ], + 'processes zero WAL segment size'); -- 2.40.0