CVE-2020-21049: Out-of-bounds Read (CWE-125)
value: An invalid read in the stb_image.h component of libsixel prior to v1.8.5 allows attackers to cause a denial of service (DOS) via a crafted PSD file.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 6.5
Published: 2021-09-14T16:15Z
Repository: https://github.com/saitoha/libsixel
Language: C
Files changed: include/sixel.h.in, src/allocator.c
Commit date: 2019-12-23 13:20:08 +0000
Commit message: Introduce SIXEL_ALLOCATE_BYTES_MAX macro and limit allocation size to 128MB(#74)

Diff: diff --git a/include/sixel.h.in b/include/sixel.h.in
index 5fc553f1..792bb1b0 100644
--- a/include/sixel.h.in
+++ b/include/sixel.h.in
@@ -37,10 +37,11 @@ typedef unsigned char sixel_index_t;
 
 #define SIXEL_OUTPUT_PACKET_SIZE     16384
 #define SIXEL_PALETTE_MIN            2
 #define SIXEL_PALETTE_MAX            256
 #define SIXEL_USE_DEPRECATED_SYMBOLS 1
+#define SIXEL_ALLOCATE_BYTES_MAX     10248UL * 1024UL * 128UL   /* up to 128M */
 
 /* return value */
 typedef int SIXELSTATUS;
 #define SIXEL_OK                0x0000                          /* succeeded */
 #define SIXEL_FALSE             0x1000                          /* failed */
diff --git a/src/allocator.c b/src/allocator.c
index bb0c009f..5cee49c0 100644
--- a/src/allocator.c
+++ b/src/allocator.c
@@ -150,10 +150,15 @@ sixel_allocator_malloc(
     if (n == 0) {
         sixel_helper_set_additional_message(
             "sixel_allocator_malloc: called with n == 0");
         return NULL;
     }
+
+    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
+        return NULL;
+    }
+
     return allocator->fn_malloc(n);
 }
 
 
 /* call custom calloc() */
@@ -161,14 +166,28 @@ SIXELAPI void *
 sixel_allocator_calloc(
     sixel_allocator_t   /* in */ *allocator,  /* allocator object */
     size_t              /* in */ nelm,        /* number of elements */
     size_t              /* in */ elsize)      /* size of element */
 {
+    size_t n;
+
     /* precondition */
     assert(allocator);
     assert(allocator->fn_calloc);
 
+    n = nelm * elsize;
+
+    if (n == 0) {
+        sixel_helper_set_additional_message(
+            "sixel_allocator_malloc: called with n == 0");
+        return NULL;
+    }
+
+    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
+        return NULL;
+    }
+
     return allocator->fn_calloc(nelm, elsize);
 }
 
 
 /* call custom realloc() */
@@ -180,10 +199,20 @@ sixel_allocator_realloc(
 {
     /* precondition */
     assert(allocator);
     assert(allocator->fn_realloc);
 
+    if (n == 0) {
+        sixel_helper_set_additional_message(
+            "sixel_allocator_malloc: called with n == 0");
+        return NULL;
+    }
+
+    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
+        return NULL;
+    }
+
     return allocator->fn_realloc(p, n);
 }
 
 
 /* call custom free() */

Fixed code: #define SIXEL_ALLOCATE_BYTES_MAX     10248UL * 1024UL * 128UL   /* up to 128M */

    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
        return NULL;
    }

    size_t n;

    n = nelm * elsize;

    if (n == 0) {
        sixel_helper_set_additional_message(
            "sixel_allocator_malloc: called with n == 0");
        return NULL;
    }

    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
        return NULL;
    }

    if (n == 0) {
        sixel_helper_set_additional_message(
            "sixel_allocator_malloc: called with n == 0");
        return NULL;
    }

    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
        return NULL;
    }