From 350ff161c8a61b6483a1e4689e09cd47dd0dd5f9 Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Sat, 17 Jun 2023 16:22:38 +0200
Subject: [PATCH] WebP decoder: validate WebP blob width, height, band count
against TIFF parameters
to avoid use of uninitialized variable, or decoding corrupted content
without explicit error
Fixes #581, fixes #582
---
libtiff/tif_webp.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/libtiff/tif_webp.c b/libtiff/tif_webp.c
index 07db7cce..ce15391e 100644
--- a/libtiff/tif_webp.c
+++ b/libtiff/tif_webp.c
@@ -149,6 +149,57 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
segment_height = td->td_rowsperstrip;
}
+ int webp_width, webp_height;
+ if (!WebPGetInfo(tif->tif_rawcp,
+ tif->tif_rawcc > UINT32_MAX ? UINT32_MAX
+ : (uint32_t)tif->tif_rawcc,
+ &webp_width, &webp_height))
+ {
+ TIFFErrorExtR(tif, module, "WebPGetInfo() failed");
+ return 0;
+ }
+ if ((uint32_t)webp_width != segment_width ||
+ (uint32_t)webp_height != segment_height)
+ {
+ TIFFErrorExtR(
+ tif, module, "WebP blob dimension is %dx%d. Expected %ux%u",
+ webp_width, webp_height, segment_width, segment_height);
+ return 0;
+ }
+
+#if WEBP_DECODER_ABI_VERSION >= 0x0002
+ WebPDecoderConfig config;
+ if (!WebPInitDecoderConfig(&config))
+ {
+ TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
+ return 0;
+ }
+
+ const bool bWebPGetFeaturesOK =
+ WebPGetFeatures(tif->tif_rawcp,
+ tif->tif_rawcc > UINT32_MAX
+ ? UINT32_MAX
+ : (uint32_t)tif->tif_rawcc,
+ &config.input) == VP8_STATUS_OK;
+
+ WebPFreeDecBuffer(&config.output);
+
+ if (!bWebPGetFeaturesOK)
+ {
+ TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
+ return 0;
+ }
+
+ const int webp_bands = config.input.has_alpha ? 4 : 3;
+ if (webp_bands != sp->nSamples)
+ {
+ TIFFErrorExtR(tif, module,
+ "WebP blob band count is %d. Expected %d", webp_bands,
+ sp->nSamples);
+ return 0;
+ }
+#endif
+
buffer_size = segment_width * segment_height * sp->nSamples;
if (occ == (tmsize_t)buffer_size)
{