pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Michael Paquier <michael@paquier.xyz>
To: Postgres hackers <pgsql-hackers@lists.postgresql.org>
Cc: Andrew Dunstan <andrew@dunslane.net>
Subject: Plug-in coverage hole for pglz_decompress()
Date: Mon, 11 May 2026 15:35:50 +0900
Message-ID: <agF4xkIdRcrCIprs@paquier.xyz> (raw)

Hi all,
(Andrew in CC, in case.)

While doing a post-commit review of 67d318e70402, I have noticed the
following coverage hole in pglz_decompress(), where a failure of this
check is not covered, see also [1]:
    if (unlikely(off == 0 ||
                 off > (dp - (unsigned char *) dest)))
        return -1;

This can be triggered easily with the two following sequences in the
regression tests:
SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);

It's unfortunately too late for this round of minor releases, but I'd
like to fix this hole once the next minor versions are tagged, down to
v14.  If there are any objections or comments, feel free.  Mea culpa.

Thanks,

[1]: https://coverage.postgresql.org/src/common/pg_lzcompress.c.gcov.html
--
Michael
From 4a63b443e241e98df27489ac04291822f4a56bc5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 11 May 2026 15:21:30 +0900
Subject: [PATCH] Add more tests for corrupted data in pglz_decompress()

Two cases fixed by 2b5ba2a0a141 were not covered, emulating corrupted
data:
- Set control bit with a valid 2-byte match tag where offset is 0.
- Set control bit with a valid 2-byte match tag where offset exceeds
output written.

Oversight in 67d318e70402.

Backpatch-through: 14
---
 src/test/regress/expected/compression_pglz.out | 12 ++++++++++++
 src/test/regress/sql/compression_pglz.sql      | 10 ++++++++++
 2 files changed, 22 insertions(+)

diff --git a/src/test/regress/expected/compression_pglz.out b/src/test/regress/expected/compression_pglz.out
index 0ef49d425068..066a3317c65d 100644
--- a/src/test/regress/expected/compression_pglz.out
+++ b/src/test/regress/expected/compression_pglz.out
@@ -60,6 +60,18 @@ SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false);
 ERROR:  pglz_decompress failed
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true);
 ERROR:  pglz_decompress failed
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset exceeds output written.
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, false);
+ERROR:  pglz_decompress failed
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
+ERROR:  pglz_decompress failed
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset is 0.
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, false);
+ERROR:  pglz_decompress failed
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);
+ERROR:  pglz_decompress failed
 -- Clean up
 DROP FUNCTION test_pglz_compress;
 DROP FUNCTION test_pglz_decompress;
diff --git a/src/test/regress/sql/compression_pglz.sql b/src/test/regress/sql/compression_pglz.sql
index a44af02afb7b..dbd37f7d4eb2 100644
--- a/src/test/regress/sql/compression_pglz.sql
+++ b/src/test/regress/sql/compression_pglz.sql
@@ -48,6 +48,16 @@ SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true);
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false);
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true);
 
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset exceeds output written.
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
+
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset is 0.
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);
+
 -- Clean up
 DROP FUNCTION test_pglz_compress;
 DROP FUNCTION test_pglz_decompress;
-- 
2.54.0

Attachments:

  [text/plain] 0001-Add-more-tests-for-corrupted-data-in-pglz_decompress.patch (2.8K, ../agF4xkIdRcrCIprs@paquier.xyz/2-0001-Add-more-tests-for-corrupted-data-in-pglz_decompress.patch)
  download | inline diff:
From 4a63b443e241e98df27489ac04291822f4a56bc5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 11 May 2026 15:21:30 +0900
Subject: [PATCH] Add more tests for corrupted data in pglz_decompress()

Two cases fixed by 2b5ba2a0a141 were not covered, emulating corrupted
data:
- Set control bit with a valid 2-byte match tag where offset is 0.
- Set control bit with a valid 2-byte match tag where offset exceeds
output written.

Oversight in 67d318e70402.

Backpatch-through: 14
---
 src/test/regress/expected/compression_pglz.out | 12 ++++++++++++
 src/test/regress/sql/compression_pglz.sql      | 10 ++++++++++
 2 files changed, 22 insertions(+)

diff --git a/src/test/regress/expected/compression_pglz.out b/src/test/regress/expected/compression_pglz.out
index 0ef49d425068..066a3317c65d 100644
--- a/src/test/regress/expected/compression_pglz.out
+++ b/src/test/regress/expected/compression_pglz.out
@@ -60,6 +60,18 @@ SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false);
 ERROR:  pglz_decompress failed
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true);
 ERROR:  pglz_decompress failed
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset exceeds output written.
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, false);
+ERROR:  pglz_decompress failed
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
+ERROR:  pglz_decompress failed
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset is 0.
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, false);
+ERROR:  pglz_decompress failed
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);
+ERROR:  pglz_decompress failed
 -- Clean up
 DROP FUNCTION test_pglz_compress;
 DROP FUNCTION test_pglz_decompress;
diff --git a/src/test/regress/sql/compression_pglz.sql b/src/test/regress/sql/compression_pglz.sql
index a44af02afb7b..dbd37f7d4eb2 100644
--- a/src/test/regress/sql/compression_pglz.sql
+++ b/src/test/regress/sql/compression_pglz.sql
@@ -48,6 +48,16 @@ SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true);
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false);
 SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true);
 
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset exceeds output written.
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x011001'::bytea, 1024, true);
+
+-- Corrupted compressed data.  Set control bit with a valid 2-byte match
+-- tag where offset is 0.
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, false);
+SELECT test_pglz_decompress('\x010300'::bytea, 1024, true);
+
 -- Clean up
 DROP FUNCTION test_pglz_compress;
 DROP FUNCTION test_pglz_decompress;
-- 
2.54.0

  [application/pgp-signature] signature.asc (832B, ../agF4xkIdRcrCIprs@paquier.xyz/3-signature.asc)
  download

view thread (3+ messages)  latest in thread

Message-ID: <agF4xkIdRcrCIprs@paquier.xyz>
Permalink:  ../agF4xkIdRcrCIprs@paquier.xyz/
Also on:    postgresql.org/message-id/agF4xkIdRcrCIprs@paquier.xyz

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: michael@paquier.xyz, pgsql-hackers@lists.postgresql.org, andrew@dunslane.net
  Subject: Re: Plug-in coverage hole for pglz_decompress()
  In-Reply-To: <agF4xkIdRcrCIprs@paquier.xyz>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox