[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#989618: marked as done (unblock: libwebp/0.6.1-2.1)



Your message dated Tue, 08 Jun 2021 21:25:28 +0000
with message-id <E1lqjE0-0000jy-Fd@respighi.debian.org>
and subject line unblock libwebp
has caused the Debian Bug report #989618,
regarding unblock: libwebp/0.6.1-2.1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
989618: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989618
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: jab@debian.org

Please unblock libwebp and age it to five days.

It fixes all open security issues. There is RC #914315
about updating to a new version, but bumping to 1.2.0
is obviously not a solution at this time of the freeze.
Still I think the RC bugs should stay open (bookworm
definitely must not release with 0.6 :-), so please tag it
bullseye-ignore.

unblock libwebp/0.6.1-2.1

Cheers,
        Moritz

Debdiff:

diff -Nru libwebp-0.6.1/debian/changelog libwebp-0.6.1/debian/changelog
--- libwebp-0.6.1/debian/changelog	2018-03-01 21:51:06.000000000 +0100
+++ libwebp-0.6.1/debian/changelog	2021-06-05 19:35:57.000000000 +0200
@@ -1,3 +1,12 @@
+libwebp (0.6.1-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix multiple security issues: CVE-2018-25009, CVE-2018-25010, CVE-2018-25011
+    CVE-2020-36328, CVE-2018-25013, CVE-2018-25014, CVE-2020-36329, CVE-2020-36330
+    CVE-2020-36331, CVE-2020-36332
+
+ -- Moritz Muehlenhoff <jmm@debian.org>  Sat, 05 Jun 2021 19:35:57 +0200
+
 libwebp (0.6.1-2) unstable; urgency=medium
 
   * Fix lintian warning on manpage
diff -Nru libwebp-0.6.1/debian/patches/security-fixes.patch libwebp-0.6.1/debian/patches/security-fixes.patch
--- libwebp-0.6.1/debian/patches/security-fixes.patch	1970-01-01 01:00:00.000000000 +0100
+++ libwebp-0.6.1/debian/patches/security-fixes.patch	2021-06-05 19:34:56.000000000 +0200
@@ -0,0 +1,355 @@
+Patches for the following CVE IDs:
+
+CVE-2018-25009
+CVE-2018-25010
+CVE-2018-25011
+CVE-2020-36328
+CVE-2018-25013
+CVE-2018-25014
+CVE-2020-36329
+CVE-2020-36330
+CVE-2020-36331
+CVE-2020-36332
+
+Comprised of the following upstream commits:
+1344a2e947c749d231141a295327e5b99b444d63
+2c70ad76c94db5427d37ab4b85dc89b94dd75e01
+39cb9aad85ca7bb1d193013460db1f8cc6bff109
+569001f19fc81fcb5ab358f587a54c62e7c4665c
+907208f97ead639bd521cf355a2f203f462eade6
+95fd65070662e01cc9170c4444f5c0859a710097
+be738c6d396fa5a272c1b209be4379a7532debfe
+dad31750e374eff8e02fb467eb562d4bf236ed6e
+dce5d7643177633ebe3513af492ea8c08c299cf3
+eb82ce76ddca13ad6fb13376bb58b9fd3f850e9e
+
+--- libwebp-0.6.1.orig/src/dec/buffer_dec.c
++++ libwebp-0.6.1/src/dec/buffer_dec.c
+@@ -74,7 +74,8 @@ static VP8StatusCode CheckDecBuffer(cons
+   } else {    // RGB checks
+     const WebPRGBABuffer* const buf = &buffer->u.RGBA;
+     const int stride = abs(buf->stride);
+-    const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
++    const uint64_t size =
++        MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
+     ok &= (size <= buf->size);
+     ok &= (stride >= width * kModeBpp[mode]);
+     ok &= (buf->rgba != NULL);
+--- libwebp-0.6.1.orig/src/dec/idec_dec.c
++++ libwebp-0.6.1/src/dec/idec_dec.c
+@@ -283,10 +283,8 @@ static void RestoreContext(const MBConte
+ 
+ static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
+   if (idec->state_ == STATE_VP8_DATA) {
+-    VP8Io* const io = &idec->io_;
+-    if (io->teardown != NULL) {
+-      io->teardown(io);
+-    }
++    // Synchronize the thread, clean-up and check for errors.
++    VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+   }
+   idec->state_ = STATE_ERROR;
+   return error;
+@@ -473,6 +471,12 @@ static VP8StatusCode DecodeRemaining(Web
+             MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
+           return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+         }
++        // Synchronize the threads.
++        if (dec->mt_method_ > 0) {
++          if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) {
++            return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
++          }
++        }
+         RestoreContext(&context, dec, token_br);
+         return VP8_STATUS_SUSPENDED;
+       }
+--- libwebp-0.6.1.orig/src/dec/vp8l_dec.c
++++ libwebp-0.6.1/src/dec/vp8l_dec.c
+@@ -362,12 +362,19 @@ static int ReadHuffmanCodes(VP8LDecoder*
+   VP8LMetadata* const hdr = &dec->hdr_;
+   uint32_t* huffman_image = NULL;
+   HTreeGroup* htree_groups = NULL;
++  // When reading htrees, some might be unused, as the format allows it.
++  // We will still read them but put them in this htree_group_bogus.
++  HTreeGroup htree_group_bogus;
+   HuffmanCode* huffman_tables = NULL;
++  HuffmanCode* huffman_tables_bogus = NULL;
+   HuffmanCode* next = NULL;
+   int num_htree_groups = 1;
++  int num_htree_groups_max = 1;
+   int max_alphabet_size = 0;
+   int* code_lengths = NULL;
+   const int table_size = kTableSize[color_cache_bits];
++  int* mapping = NULL;
++  int ok = 0;
+ 
+   if (allow_recursion && VP8LReadBits(br, 1)) {
+     // use meta Huffman codes.
+@@ -384,10 +391,42 @@ static int ReadHuffmanCodes(VP8LDecoder*
+       // The huffman data is stored in red and green bytes.
+       const int group = (huffman_image[i] >> 8) & 0xffff;
+       huffman_image[i] = group;
+-      if (group >= num_htree_groups) {
+-        num_htree_groups = group + 1;
++      if (group >= num_htree_groups_max) {
++        num_htree_groups_max = group + 1;
+       }
+     }
++    // Check the validity of num_htree_groups_max. If it seems too big, use a
++    // smaller value for later. This will prevent big memory allocations to end
++    // up with a bad bitstream anyway.
++    // The value of 1000 is totally arbitrary. We know that num_htree_groups_max
++    // is smaller than (1 << 16) and should be smaller than the number of pixels
++    // (though the format allows it to be bigger).
++    if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
++      // Create a mapping from the used indices to the minimal set of used
++      // values [0, num_htree_groups)
++      mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
++      if (mapping == NULL) {
++        dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
++        goto Error;
++      }
++      // -1 means a value is unmapped, and therefore unused in the Huffman
++      // image.
++      memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
++      for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
++        // Get the current mapping for the group and remap the Huffman image.
++        int* const mapped_group = &mapping[huffman_image[i]];
++        if (*mapped_group == -1) *mapped_group = num_htree_groups++;
++        huffman_image[i] = *mapped_group;
++      }
++      huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
++          table_size, sizeof(*huffman_tables_bogus));
++      if (huffman_tables_bogus == NULL) {
++        dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
++        goto Error;
++      }
++    } else {
++      num_htree_groups = num_htree_groups_max;
++    }
+   }
+ 
+   if (br->eos_) goto Error;
+@@ -403,11 +442,11 @@ static int ReadHuffmanCodes(VP8LDecoder*
+     }
+   }
+ 
++  code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
++                                      sizeof(*code_lengths));
+   huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
+                                                 sizeof(*huffman_tables));
+   htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+-  code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
+-                                      sizeof(*code_lengths));
+ 
+   if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
+     dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+@@ -415,28 +454,35 @@ static int ReadHuffmanCodes(VP8LDecoder*
+   }
+ 
+   next = huffman_tables;
+-  for (i = 0; i < num_htree_groups; ++i) {
+-    HTreeGroup* const htree_group = &htree_groups[i];
++  for (i = 0; i < num_htree_groups_max; ++i) {
++    // If the index "i" is unused in the Huffman image, read the coefficients
++    // but store them to a bogus htree_group.
++    const int is_bogus = (mapping != NULL && mapping[i] == -1);
++    HTreeGroup* const htree_group =
++        is_bogus ? &htree_group_bogus :
++        &htree_groups[(mapping == NULL) ? i : mapping[i]];
+     HuffmanCode** const htrees = htree_group->htrees;
++    HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
+     int size;
+     int total_size = 0;
+     int is_trivial_literal = 1;
+     int max_bits = 0;
+     for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+       int alphabet_size = kAlphabetSize[j];
+-      htrees[j] = next;
++      htrees[j] = huffman_tables_i;
+       if (j == 0 && color_cache_bits > 0) {
+         alphabet_size += 1 << color_cache_bits;
+       }
+-      size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
++      size =
++          ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
+       if (size == 0) {
+         goto Error;
+       }
+       if (is_trivial_literal && kLiteralMap[j] == 1) {
+-        is_trivial_literal = (next->bits == 0);
++        is_trivial_literal = (huffman_tables_i->bits == 0);
+       }
+-      total_size += next->bits;
+-      next += size;
++      total_size += huffman_tables_i->bits;
++      huffman_tables_i += size;
+       if (j <= ALPHA) {
+         int local_max_bits = code_lengths[0];
+         int k;
+@@ -448,38 +494,41 @@ static int ReadHuffmanCodes(VP8LDecoder*
+         max_bits += local_max_bits;
+       }
+     }
++    if (!is_bogus) next = huffman_tables_i;
+     htree_group->is_trivial_literal = is_trivial_literal;
+     htree_group->is_trivial_code = 0;
+     if (is_trivial_literal) {
+       const int red = htrees[RED][0].value;
+       const int blue = htrees[BLUE][0].value;
+       const int alpha = htrees[ALPHA][0].value;
+-      htree_group->literal_arb =
+-          ((uint32_t)alpha << 24) | (red << 16) | blue;
++      htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
+       if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
+         htree_group->is_trivial_code = 1;
+         htree_group->literal_arb |= htrees[GREEN][0].value << 8;
+       }
+     }
+-    htree_group->use_packed_table = !htree_group->is_trivial_code &&
+-                                    (max_bits < HUFFMAN_PACKED_BITS);
++    htree_group->use_packed_table =
++        !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
+     if (htree_group->use_packed_table) BuildPackedTable(htree_group);
+   }
+-  WebPSafeFree(code_lengths);
++  ok = 1;
+ 
+-  // All OK. Finalize pointers and return.
++  // All OK. Finalize pointers.
+   hdr->huffman_image_ = huffman_image;
+   hdr->num_htree_groups_ = num_htree_groups;
+   hdr->htree_groups_ = htree_groups;
+   hdr->huffman_tables_ = huffman_tables;
+-  return 1;
+ 
+  Error:
+   WebPSafeFree(code_lengths);
+-  WebPSafeFree(huffman_image);
+-  WebPSafeFree(huffman_tables);
+-  VP8LHtreeGroupsFree(htree_groups);
+-  return 0;
++  WebPSafeFree(huffman_tables_bogus);
++  WebPSafeFree(mapping);
++  if (!ok) {
++    WebPSafeFree(huffman_image);
++    WebPSafeFree(huffman_tables);
++    VP8LHtreeGroupsFree(htree_groups);
++  }
++  return ok;
+ }
+ 
+ //------------------------------------------------------------------------------
+--- libwebp-0.6.1.orig/src/mux/muxi.h
++++ libwebp-0.6.1/src/mux/muxi.h
+@@ -14,6 +14,7 @@
+ #ifndef WEBP_MUX_MUXI_H_
+ #define WEBP_MUX_MUXI_H_
+ 
++#include <assert.h>
+ #include <stdlib.h>
+ #include "src/dec/vp8i_dec.h"
+ #include "src/dec/vp8li_dec.h"
+@@ -143,13 +144,13 @@ void ChunkListDelete(WebPChunk** const c
+ 
+ // Returns size of the chunk including chunk header and padding byte (if any).
+ static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
++  assert(chunk_size <= MAX_CHUNK_PAYLOAD);
+   return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
+ }
+ 
+ // Size of a chunk including header and padding.
+ static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
+   const size_t data_size = chunk->data_.size;
+-  assert(data_size < MAX_CHUNK_PAYLOAD);
+   return SizeWithPadding(data_size);
+ }
+ 
+--- libwebp-0.6.1.orig/src/mux/muxread.c
++++ libwebp-0.6.1/src/mux/muxread.c
+@@ -59,6 +59,7 @@ static WebPMuxError ChunkVerifyAndAssign
+   // Sanity checks.
+   if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
+   chunk_size = GetLE32(data + TAG_SIZE);
++  if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA;
+ 
+   {
+     const size_t chunk_disk_size = SizeWithPadding(chunk_size);
+@@ -137,6 +138,7 @@ static int MuxImageParse(const WebPChunk
+         wpi->is_partial_ = 1;  // Waiting for a VP8 chunk.
+         break;
+       case WEBP_CHUNK_IMAGE:
++        if (wpi->img_ != NULL) goto Fail;  // Only 1 image chunk allowed.
+         if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail;
+         if (!MuxImageFinalize(wpi)) goto Fail;
+         wpi->is_partial_ = 0;  // wpi is completely filled.
+@@ -187,7 +189,7 @@ WebPMux* WebPMuxCreateInternal(const Web
+   size = bitstream->size;
+ 
+   if (data == NULL) return NULL;
+-  if (size < RIFF_HEADER_SIZE) return NULL;
++  if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL;
+   if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') ||
+       GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) {
+     return NULL;
+@@ -196,8 +198,6 @@ WebPMux* WebPMuxCreateInternal(const Web
+   mux = WebPMuxNew();
+   if (mux == NULL) return NULL;
+ 
+-  if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err;
+-
+   tag = GetLE32(data + RIFF_HEADER_SIZE);
+   if (tag != kChunks[IDX_VP8].tag &&
+       tag != kChunks[IDX_VP8L].tag &&
+@@ -205,13 +205,17 @@ WebPMux* WebPMuxCreateInternal(const Web
+     goto Err;  // First chunk should be VP8, VP8L or VP8X.
+   }
+ 
+-  riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE));
+-  if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) {
+-    goto Err;
+-  } else {
+-    if (riff_size < size) {  // Redundant data after last chunk.
+-      size = riff_size;  // To make sure we don't read any data beyond mux_size.
+-    }
++  riff_size = GetLE32(data + TAG_SIZE);
++  if (riff_size > MAX_CHUNK_PAYLOAD) goto Err;
++
++  // Note this padding is historical and differs from demux.c which does not
++  // pad the file size.
++  riff_size = SizeWithPadding(riff_size);
++  if (riff_size < CHUNK_HEADER_SIZE) goto Err;
++  if (riff_size > size) goto Err;
++  // There's no point in reading past the end of the RIFF chunk.
++  if (size > riff_size + CHUNK_HEADER_SIZE) {
++    size = riff_size + CHUNK_HEADER_SIZE;
+   }
+ 
+   end = data + size;
+@@ -260,6 +264,7 @@ WebPMux* WebPMuxCreateInternal(const Web
+         chunk_list = MuxGetChunkListFromId(mux, id);  // List to add this chunk.
+         if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+         if (id == WEBP_CHUNK_VP8X) {  // grab global specs
++          if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err;
+           mux->canvas_width_ = GetLE24(data + 12) + 1;
+           mux->canvas_height_ = GetLE24(data + 15) + 1;
+         }
+--- libwebp-0.6.1.orig/src/utils/quant_levels_dec_utils.c
++++ libwebp-0.6.1/src/utils/quant_levels_dec_utils.c
+@@ -261,9 +261,15 @@ static void CleanupParams(SmoothParams*
+ 
+ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
+                          int strength) {
+-  const int radius = 4 * strength / 100;
++  int radius = 4 * strength / 100;
++
+   if (strength < 0 || strength > 100) return 0;
+   if (data == NULL || width <= 0 || height <= 0) return 0;  // bad params
++
++  // limit the filter size to not exceed the image dimensions
++  if (2 * radius + 1 > width) radius = (width - 1) >> 1;
++  if (2 * radius + 1 > height) radius = (height - 1) >> 1;
++
+   if (radius > 0) {
+     SmoothParams p;
+     memset(&p, 0, sizeof(p));
diff -Nru libwebp-0.6.1/debian/patches/series libwebp-0.6.1/debian/patches/series
--- libwebp-0.6.1/debian/patches/series	2018-03-01 21:51:06.000000000 +0100
+++ libwebp-0.6.1/debian/patches/series	2021-06-05 19:31:12.000000000 +0200
@@ -1,3 +1,4 @@
 soname_override
 big-endian
 fix-lintian-warning
+security-fixes.patch

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: