From 6cb2474327e3941c31f170de34d8a97c9871ea4f Mon Sep 17 00:00:00 2001 From: ajs124 Date: Thu, 14 Sep 2023 13:51:18 +0200 Subject: [PATCH] libwebp: 1.3.1 -> 1.3.2 fixes CVE-2023-4863, which allows us to drop the patch --- .../libraries/libwebp/CVE-2023-4863.patch | 361 ------------------ .../development/libraries/libwebp/default.nix | 12 +- 2 files changed, 2 insertions(+), 371 deletions(-) delete mode 100644 pkgs/development/libraries/libwebp/CVE-2023-4863.patch diff --git a/pkgs/development/libraries/libwebp/CVE-2023-4863.patch b/pkgs/development/libraries/libwebp/CVE-2023-4863.patch deleted file mode 100644 index c01b8a486675..000000000000 --- a/pkgs/development/libraries/libwebp/CVE-2023-4863.patch +++ /dev/null @@ -1,361 +0,0 @@ -From 4de93ac70c3292fc944e4587101a52a29f8b0c9c Mon Sep 17 00:00:00 2001 -From: Vincent Rabaud -Date: Thu, 7 Sep 2023 21:16:03 +0200 -Subject: [PATCH] Fix OOB write in BuildHuffmanTable. - -First, BuildHuffmanTable is called to check if the data is valid. -If it is and the table is not big enough, more memory is allocated. - -This will make sure that valid (but unoptimized because of unbalanced -codes) streams are still decodable. - -Bug: chromium:1479274 -Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741 -(cherry picked from commit 902bc9190331343b2017211debcec8d2ab87e17a) ---- - src/dec/vp8l_dec.c | 46 ++++++++++--------- - src/dec/vp8li_dec.h | 2 +- - src/utils/huffman_utils.c | 97 +++++++++++++++++++++++++++++++-------- - src/utils/huffman_utils.h | 27 +++++++++-- - 4 files changed, 129 insertions(+), 43 deletions(-) - -diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c -index c0ea0181..7995313f 100644 ---- a/src/dec/vp8l_dec.c -+++ b/src/dec/vp8l_dec.c -@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths( - int symbol; - int max_symbol; - int prev_code_len = DEFAULT_CODE_LENGTH; -- HuffmanCode table[1 << LENGTHS_TABLE_BITS]; -+ HuffmanTables tables; - -- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS, -- code_length_code_lengths, -- NUM_CODE_LENGTH_CODES)) { -+ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) || -+ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, -+ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) { - goto End; - } - -@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths( - int code_len; - if (max_symbol-- == 0) break; - VP8LFillBitWindow(br); -- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; -+ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; - VP8LSetBitPos(br, br->bit_pos_ + p->bits); - code_len = p->value; - if (code_len < kCodeLengthLiterals) { -@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths( - ok = 1; - - End: -+ VP8LHuffmanTablesDeallocate(&tables); - if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR; - return ok; - } -@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths( - // 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman - // tree. - static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, -- int* const code_lengths, HuffmanCode* const table) { -+ int* const code_lengths, -+ HuffmanTables* const table) { - int ok = 0; - int size = 0; - VP8LBitReader* const br = &dec->br_; -@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, - VP8LMetadata* const hdr = &dec->hdr_; - uint32_t* huffman_image = NULL; - HTreeGroup* htree_groups = NULL; -- HuffmanCode* huffman_tables = NULL; -- HuffmanCode* huffman_table = NULL; -+ HuffmanTables* huffman_tables = &hdr->huffman_tables_; - int num_htree_groups = 1; - int num_htree_groups_max = 1; - int max_alphabet_size = 0; -@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, - int* mapping = NULL; - int ok = 0; - -+ // Check the table has been 0 initialized (through InitMetadata). -+ assert(huffman_tables->root.start == NULL); -+ assert(huffman_tables->curr_segment == NULL); -+ - if (allow_recursion && VP8LReadBits(br, 1)) { - // use meta Huffman codes. - const int huffman_precision = VP8LReadBits(br, 3) + 2; -@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, - - 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); - -- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) { -+ if (htree_groups == NULL || code_lengths == NULL || -+ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size, -+ huffman_tables)) { - dec->status_ = VP8_STATUS_OUT_OF_MEMORY; - goto Error; - } - -- huffman_table = huffman_tables; - for (i = 0; i < num_htree_groups_max; ++i) { - // If the index "i" is unused in the Huffman image, just make sure the - // coefficients are valid but do not store them. -@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, - int max_bits = 0; - for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { - int alphabet_size = kAlphabetSize[j]; -- htrees[j] = huffman_table; - if (j == 0 && color_cache_bits > 0) { - alphabet_size += (1 << color_cache_bits); - } -- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table); -+ size = -+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables); -+ htrees[j] = huffman_tables->curr_segment->curr_table; - if (size == 0) { - goto Error; - } - if (is_trivial_literal && kLiteralMap[j] == 1) { -- is_trivial_literal = (huffman_table->bits == 0); -+ is_trivial_literal = (htrees[j]->bits == 0); - } -- total_size += huffman_table->bits; -- huffman_table += size; -+ total_size += htrees[j]->bits; -+ huffman_tables->curr_segment->curr_table += size; - if (j <= ALPHA) { - int local_max_bits = code_lengths[0]; - int k; -@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, - hdr->huffman_image_ = huffman_image; - hdr->num_htree_groups_ = num_htree_groups; - hdr->htree_groups_ = htree_groups; -- hdr->huffman_tables_ = huffman_tables; - - Error: - WebPSafeFree(code_lengths); - WebPSafeFree(mapping); - if (!ok) { - WebPSafeFree(huffman_image); -- WebPSafeFree(huffman_tables); -+ VP8LHuffmanTablesDeallocate(huffman_tables); - VP8LHtreeGroupsFree(htree_groups); - } - return ok; -@@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) { - assert(hdr != NULL); - - WebPSafeFree(hdr->huffman_image_); -- WebPSafeFree(hdr->huffman_tables_); -+ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_); - VP8LHtreeGroupsFree(hdr->htree_groups_); - VP8LColorCacheClear(&hdr->color_cache_); - VP8LColorCacheClear(&hdr->saved_color_cache_); -@@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) { - - if (dec == NULL) return 0; - -- assert(dec->hdr_.huffman_tables_ != NULL); -+ assert(dec->hdr_.huffman_tables_.root.start != NULL); - assert(dec->hdr_.htree_groups_ != NULL); - assert(dec->hdr_.num_htree_groups_ > 0); - -diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h -index 72b2e861..32540a4b 100644 ---- a/src/dec/vp8li_dec.h -+++ b/src/dec/vp8li_dec.h -@@ -51,7 +51,7 @@ typedef struct { - uint32_t* huffman_image_; - int num_htree_groups_; - HTreeGroup* htree_groups_; -- HuffmanCode* huffman_tables_; -+ HuffmanTables huffman_tables_; - } VP8LMetadata; - - typedef struct VP8LDecoder VP8LDecoder; -diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c -index 90c2fbf7..cf73abd4 100644 ---- a/src/utils/huffman_utils.c -+++ b/src/utils/huffman_utils.c -@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, - if (num_open < 0) { - return 0; - } -- if (root_table == NULL) continue; - for (; count[len] > 0; --count[len]) { - HuffmanCode code; - if ((key & mask) != low) { -- table += table_size; -+ if (root_table != NULL) table += table_size; - table_bits = NextTableBitSize(count, len, root_bits); - table_size = 1 << table_bits; - total_size += table_size; - low = key & mask; -- root_table[low].bits = (uint8_t)(table_bits + root_bits); -- root_table[low].value = (uint16_t)((table - root_table) - low); -+ if (root_table != NULL) { -+ root_table[low].bits = (uint8_t)(table_bits + root_bits); -+ root_table[low].value = (uint16_t)((table - root_table) - low); -+ } -+ } -+ if (root_table != NULL) { -+ code.bits = (uint8_t)(len - root_bits); -+ code.value = (uint16_t)sorted[symbol++]; -+ ReplicateValue(&table[key >> root_bits], step, table_size, code); - } -- code.bits = (uint8_t)(len - root_bits); -- code.value = (uint16_t)sorted[symbol++]; -- ReplicateValue(&table[key >> root_bits], step, table_size, code); - key = GetNextKey(key, len); - } - } -@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits, - ((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES) - // Cut-off value for switching between heap and stack allocation. - #define SORTED_SIZE_CUTOFF 512 --int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, -+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, - const int code_lengths[], int code_lengths_size) { -- int total_size; -+ const int total_size = -+ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL); - assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE); -- if (root_table == NULL) { -- total_size = BuildHuffmanTable(NULL, root_bits, -- code_lengths, code_lengths_size, NULL); -- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) { -+ if (total_size == 0 || root_table == NULL) return total_size; -+ -+ if (root_table->curr_segment->curr_table + total_size >= -+ root_table->curr_segment->start + root_table->curr_segment->size) { -+ // If 'root_table' does not have enough memory, allocate a new segment. -+ // The available part of root_table->curr_segment is left unused because we -+ // need a contiguous buffer. -+ const int segment_size = root_table->curr_segment->size; -+ struct HuffmanTablesSegment* next = -+ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next)); -+ if (next == NULL) return 0; -+ // Fill the new segment. -+ // We need at least 'total_size' but if that value is small, it is better to -+ // allocate a big chunk to prevent more allocations later. 'segment_size' is -+ // therefore chosen (any other arbitrary value could be chosen). -+ next->size = total_size > segment_size ? total_size : segment_size; -+ next->start = -+ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start)); -+ if (next->start == NULL) { -+ WebPSafeFree(next); -+ return 0; -+ } -+ next->curr_table = next->start; -+ next->next = NULL; -+ // Point to the new segment. -+ root_table->curr_segment->next = next; -+ root_table->curr_segment = next; -+ } -+ if (code_lengths_size <= SORTED_SIZE_CUTOFF) { - // use local stack-allocated array. - uint16_t sorted[SORTED_SIZE_CUTOFF]; -- total_size = BuildHuffmanTable(root_table, root_bits, -- code_lengths, code_lengths_size, sorted); -- } else { // rare case. Use heap allocation. -+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, -+ code_lengths, code_lengths_size, sorted); -+ } else { // rare case. Use heap allocation. - uint16_t* const sorted = - (uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted)); - if (sorted == NULL) return 0; -- total_size = BuildHuffmanTable(root_table, root_bits, -- code_lengths, code_lengths_size, sorted); -+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits, -+ code_lengths, code_lengths_size, sorted); - WebPSafeFree(sorted); - } - return total_size; - } -+ -+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) { -+ // Have 'segment' point to the first segment for now, 'root'. -+ HuffmanTablesSegment* const root = &huffman_tables->root; -+ huffman_tables->curr_segment = root; -+ // Allocate root. -+ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start)); -+ if (root->start == NULL) return 0; -+ root->curr_table = root->start; -+ root->next = NULL; -+ root->size = size; -+ return 1; -+} -+ -+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) { -+ HuffmanTablesSegment *current, *next; -+ if (huffman_tables == NULL) return; -+ // Free the root node. -+ current = &huffman_tables->root; -+ next = current->next; -+ WebPSafeFree(current->start); -+ current->start = NULL; -+ current->next = NULL; -+ current = next; -+ // Free the following nodes. -+ while (current != NULL) { -+ next = current->next; -+ WebPSafeFree(current->start); -+ WebPSafeFree(current); -+ current = next; -+ } -+} -diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h -index 13b7ad1a..98415c53 100644 ---- a/src/utils/huffman_utils.h -+++ b/src/utils/huffman_utils.h -@@ -43,6 +43,29 @@ typedef struct { - // or non-literal symbol otherwise - } HuffmanCode32; - -+// Contiguous memory segment of HuffmanCodes. -+typedef struct HuffmanTablesSegment { -+ HuffmanCode* start; -+ // Pointer to where we are writing into the segment. Starts at 'start' and -+ // cannot go beyond 'start' + 'size'. -+ HuffmanCode* curr_table; -+ // Pointer to the next segment in the chain. -+ struct HuffmanTablesSegment* next; -+ int size; -+} HuffmanTablesSegment; -+ -+// Chained memory segments of HuffmanCodes. -+typedef struct HuffmanTables { -+ HuffmanTablesSegment root; -+ // Currently processed segment. At first, this is 'root'. -+ HuffmanTablesSegment* curr_segment; -+} HuffmanTables; -+ -+// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on -+// memory allocation error, 1 otherwise. -+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables); -+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables); -+ - #define HUFFMAN_PACKED_BITS 6 - #define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS) - -@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups); - // the huffman table. - // Returns built table size or 0 in case of error (invalid tree or - // memory error). --// If root_table is NULL, it returns 0 if a lookup cannot be built, something --// > 0 otherwise (but not the table size). --int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits, -+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits, - const int code_lengths[], int code_lengths_size); - - #ifdef __cplusplus --- -2.41.0 - diff --git a/pkgs/development/libraries/libwebp/default.nix b/pkgs/development/libraries/libwebp/default.nix index 287c0b6b18be..2605dabf125a 100644 --- a/pkgs/development/libraries/libwebp/default.nix +++ b/pkgs/development/libraries/libwebp/default.nix @@ -27,23 +27,15 @@ stdenv.mkDerivation rec { pname = "libwebp"; - version = "1.3.1"; + version = "1.3.2"; src = fetchFromGitHub { owner = "webmproject"; repo = pname; rev = "v${version}"; - hash = "sha256-Q94avvKjPdwdGt5ADo30cf2V4T7MCTubDHJxTtbG4xQ="; + hash = "sha256-UYO2Fmm8nzQR8VBC26wEwWd3qZTD+6MHKcmKBoNcpEE="; }; - patches = [ - # Commit 902bc919 from upstream, mangled slightly to apply onto 1.3.1. - # There is currently (2023-09-12) no confirmation that this is the fix for - # CVE-2023-4863, but it is linked to the right crbug, and matches the - # description of that (critical sev, exploited in the wild) CVE. - ./CVE-2023-4863.patch - ]; - configureFlags = [ (lib.enableFeature threadingSupport "threading") (lib.enableFeature openglSupport "gl")