Improve pglz_decompress's defenses against corrupt compressed data.
authorTom Lane <[email protected]>
Thu, 19 Oct 2023 00:43:17 +0000 (20:43 -0400)
committerTom Lane <[email protected]>
Thu, 19 Oct 2023 00:43:17 +0000 (20:43 -0400)
When processing a match tag, check to see if the claimed "off"
is more than the distance back to the output buffer start.
If it is, then the data is corrupt, and what's more we would
fetch from outside the buffer boundaries and potentially incur
a SIGSEGV.  (Although the odds of that seem relatively low, given
that "off" can't be more than 4K.)

Back-patch to v13; before that, this function wasn't really
trying to protect against bad data.

Report and fix by Flavien Guedez.

Discussion: https://postgr.es/m/01fc0593-e31e-463d-902c-dd43174acee2@oopacity.net

src/common/pg_lzcompress.c

index f9c29820e30bd584d7ec4636a6043b0864a30318..e21287fd0ea2fd3478e60a5b40c775a9f28fd727 100644 (file)
@@ -735,11 +735,15 @@ pglz_decompress(const char *source, int32 slen, char *dest,
 
                /*
                 * Check for corrupt data: if we fell off the end of the
-                * source, or if we obtained off = 0, we have problems.  (We
-                * must check this, else we risk an infinite loop below in the
-                * face of corrupt data.)
+                * source, or if we obtained off = 0, or if off is more than
+                * the distance back to the buffer start, we have problems.
+                * (We must check for off = 0, else we risk an infinite loop
+                * below in the face of corrupt data.  Likewise, the upper
+                * limit on off prevents accessing outside the buffer
+                * boundaries.)
                 */
-               if (unlikely(sp > srcend || off == 0))
+               if (unlikely(sp > srcend || off == 0 ||
+                            off > (dp - (unsigned char *) dest)))
                    return -1;
 
                /*