CVE-2023-46228 (published 2023-10-19T05:15Z)

zchunk before 1.3.2 has multiple integer overflows via malformed zchunk files to lib/comp/comp.c, lib/comp/zstd/zstd.c, lib/dl/multipart.c, or lib/header.c.

CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/zchunk/zchunk
commit_details: repo_url: https://github.com/zchunk/zchunk
author: Jonathan Dieter
author_date: 2023-10-05 19:52:18+01:00
msg: Handle overflow errors in malformed zchunk files

Thanks to Agostino Sarubbo of Gentoo for the heads up!

Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
repository: repo_url: https://github.com/zchunk/zchunk
repo_name: zchunk/zchunk
description: A file format designed for highly efficient deltas while maintaining good compression
repo_language: C
owner: zchunk
file_changes: filename: comp.c
change_type: ModificationType.MODIFY
diff: @@ -115,6 +115,12 @@ static bool comp_add_to_data(zckCtx *zck, zckComp *comp, const char *src,
     ALLOCD_BOOL(zck, comp);
     ALLOCD_BOOL(zck, src);
 
+    if((comp->data_size > comp->data_size + src_size) ||
+       (src_size > comp->data_size + src_size)) {
+        zck_log(ZCK_LOG_ERROR, "Integer overflow when reading data");
+        return false;
+    }
+
     comp->data = zrealloc(comp->data, comp->data_size + src_size);
     if (!comp->data) {
         zck_log(ZCK_LOG_ERROR, "OOM in %s", __func__);

programming_language: C++
filename: zstd.c
change_type: ModificationType.MODIFY
diff: @@ -117,6 +117,12 @@ static ssize_t compress(zckCtx *zck, zckComp *comp, const char *src,
     ALLOCD_INT(zck, dst_size);
     ALLOCD_INT(zck, comp);
 
+    if((comp->dc_data_size > comp->dc_data_size + src_size) ||
+       (src_size > comp->dc_data_size + src_size)) {
+        zck_log(ZCK_LOG_ERROR, "Integer overflow when reading decompressed data");
+        return false;
+    }
+
     comp->dc_data = zrealloc(comp->dc_data, comp->dc_data_size + src_size);
     if (!comp->dc_data) {
         zck_log(ZCK_LOG_ERROR, "OOM in %s", __func__);

programming_language: C
filename: multipart.c
change_type: ModificationType.MODIFY
diff: @@ -119,6 +119,12 @@ size_t multipart_extract(zckDL *dl, char *b, size_t l) {
 
     /* Add new data to stored buffer */
     if(mp->buffer) {
+        if((mp->buffer_len > mp->buffer_len + l) ||
+           (l > mp->buffer_len + l)) {
+            zck_log(ZCK_LOG_ERROR, "Integer overflow when extracting multipart data");
+            return 0;
+        }
+
         buf = zrealloc(mp->buffer, mp->buffer_len + l);
         if (!buf) {
             zck_log(ZCK_LOG_ERROR, "OOM in %s", __func__);

programming_language: C
filename: header.c
change_type: ModificationType.MODIFY
diff: @@ -74,11 +74,16 @@ static bool read_optional_element(zckCtx *zck, size_t id, size_t data_size,
 }
 
 static bool read_header_from_file(zckCtx *zck) {
-    /* Verify that lead_size and header_length have been set */
+    /* Verify that lead_size and header_length have been set and are legit */
     if(zck->lead_size == 0 || zck->header_length == 0) {
         set_error(zck, "Lead and header sizes are both 0.  Have you run zck_read_lead() yet?");
         return false;
     }
+    if((zck->lead_size > zck->lead_size + zck->header_length) ||
+       (zck->header_length > zck->lead_size + zck->header_length)) {
+        zck_log(ZCK_LOG_ERROR, "Integer overflow when reading header");
+        return false;
+    }
 
     /* Allocate header and store any extra bytes at beginning of header */
     zck->header = zrealloc(zck->header, zck->lead_size + zck->header_length);
@@ -533,6 +538,12 @@ static bool read_lead(zckCtx *zck) {
     /* Set header digest location */
     zck->hdr_digest_loc = length;
 
+    /* Verify that we're not going to overflow */
+    if(length > length + zck->hash_type.digest_size) {
+        zck_log(ZCK_LOG_ERROR, "Integer overflow when reading lead");
+        return false;
+    }
+
     /* Read header digest */
     zck_log(ZCK_LOG_DEBUG, "Reading header digest");
     header = zrealloc(header, length + zck->hash_type.digest_size);

programming_language: C++